PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/share/classes/sun/security/krb5/Config.java

https://bitbucket.org/sreilly/openjdk7u-jdk
Java | 1365 lines | 1014 code | 63 blank | 288 comment | 276 complexity | 98d62d9fe94192472eab097badd9e64f MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. /*
  26. *
  27. * (C) Copyright IBM Corp. 1999 All Rights Reserved.
  28. * Copyright 1997 The Open Group Research Institute. All rights reserved.
  29. */
  30. package sun.security.krb5;
  31. import java.io.File;
  32. import java.io.FileInputStream;
  33. import java.util.Hashtable;
  34. import java.util.Vector;
  35. import java.util.ArrayList;
  36. import java.io.BufferedReader;
  37. import java.io.InputStreamReader;
  38. import java.io.IOException;
  39. import java.util.Enumeration;
  40. import java.util.StringTokenizer;
  41. import java.net.InetAddress;
  42. import java.net.UnknownHostException;
  43. import java.util.List;
  44. import sun.net.dns.ResolverConfiguration;
  45. import sun.security.krb5.internal.crypto.EType;
  46. import sun.security.krb5.internal.ktab.*;
  47. import sun.security.krb5.internal.Krb5;
  48. /**
  49. * This class maintains key-value pairs of Kerberos configurable constants
  50. * from configuration file or from user specified system properties.
  51. */
  52. public class Config {
  53. /*
  54. * Only allow a single instance of Config.
  55. */
  56. private static Config singleton = null;
  57. /*
  58. * Hashtable used to store configuration infomation.
  59. */
  60. private Hashtable<String,Object> stanzaTable;
  61. private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
  62. // these are used for hexdecimal calculation.
  63. private static final int BASE16_0 = 1;
  64. private static final int BASE16_1 = 16;
  65. private static final int BASE16_2 = 16 * 16;
  66. private static final int BASE16_3 = 16 * 16 * 16;
  67. /**
  68. * Specified by system properties. Must be both null or non-null.
  69. */
  70. private final String defaultRealm;
  71. private final String defaultKDC;
  72. // used for native interface
  73. private static native String getWindowsDirectory(boolean isSystem);
  74. /**
  75. * Gets an instance of Config class. One and only one instance (the
  76. * singleton) is returned.
  77. *
  78. * @exception KrbException if error occurs when constructing a Config
  79. * instance. Possible causes would be either of java.security.krb5.realm or
  80. * java.security.krb5.kdc not specified, error reading configuration file.
  81. */
  82. public static synchronized Config getInstance() throws KrbException {
  83. if (singleton == null) {
  84. singleton = new Config();
  85. }
  86. return singleton;
  87. }
  88. /**
  89. * Refresh and reload the Configuration. This could involve,
  90. * for example reading the Configuration file again or getting
  91. * the java.security.krb5.* system properties again.
  92. *
  93. * @exception KrbException if error occurs when constructing a Config
  94. * instance. Possible causes would be either of java.security.krb5.realm or
  95. * java.security.krb5.kdc not specified, error reading configuration file.
  96. */
  97. public static synchronized void refresh() throws KrbException {
  98. singleton = new Config();
  99. KdcComm.initStatic();
  100. }
  101. private static boolean isMacosLionOrBetter() {
  102. // split the "10.x.y" version number
  103. String osVersion = System.getProperty("os.version");
  104. String[] fragments = osVersion.split("\\.");
  105. // sanity check the "10." part of the version
  106. if (!fragments[0].equals("10")) return false;
  107. if (fragments.length < 2) return false;
  108. // check if Mac OS X 10.7(.y)
  109. try {
  110. int minorVers = Integer.parseInt(fragments[1]);
  111. if (minorVers >= 7) return true;
  112. } catch (NumberFormatException e) {
  113. // was not an integer
  114. }
  115. return false;
  116. }
  117. /**
  118. * Private constructor - can not be instantiated externally.
  119. */
  120. private Config() throws KrbException {
  121. /*
  122. * If either one system property is specified, we throw exception.
  123. */
  124. String tmp =
  125. java.security.AccessController.doPrivileged(
  126. new sun.security.action.GetPropertyAction
  127. ("java.security.krb5.kdc"));
  128. if (tmp != null) {
  129. // The user can specify a list of kdc hosts separated by ":"
  130. defaultKDC = tmp.replace(':', ' ');
  131. } else {
  132. defaultKDC = null;
  133. }
  134. defaultRealm =
  135. java.security.AccessController.doPrivileged(
  136. new sun.security.action.GetPropertyAction
  137. ("java.security.krb5.realm"));
  138. if ((defaultKDC == null && defaultRealm != null) ||
  139. (defaultRealm == null && defaultKDC != null)) {
  140. throw new KrbException
  141. ("System property java.security.krb5.kdc and " +
  142. "java.security.krb5.realm both must be set or " +
  143. "neither must be set.");
  144. }
  145. // Always read the Kerberos configuration file
  146. try {
  147. Vector<String> configFile;
  148. configFile = loadConfigFile();
  149. if (configFile == null && isMacosLionOrBetter()) {
  150. stanzaTable = SCDynamicStoreConfig.getConfig();
  151. } else {
  152. stanzaTable = parseStanzaTable(configFile);
  153. }
  154. } catch (IOException ioe) {
  155. // No krb5.conf, no problem. We'll use DNS or system property etc.
  156. }
  157. }
  158. /**
  159. * Gets the default int value for the specified name.
  160. * @param name the name.
  161. * @return the default Integer, null is returned if no such name and
  162. * value are found in configuration file, or error occurs when parsing
  163. * string to integer.
  164. */
  165. public int getDefaultIntValue(String name) {
  166. String result = null;
  167. int value = Integer.MIN_VALUE;
  168. result = getDefault(name);
  169. if (result != null) {
  170. try {
  171. value = parseIntValue(result);
  172. } catch (NumberFormatException e) {
  173. if (DEBUG) {
  174. System.out.println("Exception in getting value of " +
  175. name + " " +
  176. e.getMessage());
  177. System.out.println("Setting " + name +
  178. " to minimum value");
  179. }
  180. value = Integer.MIN_VALUE;
  181. }
  182. }
  183. return value;
  184. }
  185. /**
  186. * Gets the default int value for the specified name in the specified
  187. * section. <br>This method is quicker by using section name as the
  188. * search key.
  189. * @param name the name.
  190. * @param sectio the name string of the section.
  191. * @return the default Integer, null is returned if no such name and
  192. * value are found in configuration file, or error occurs when parsing
  193. * string to integer.
  194. */
  195. public int getDefaultIntValue(String name, String section) {
  196. String result = null;
  197. int value = Integer.MIN_VALUE;
  198. result = getDefault(name, section);
  199. if (result != null) {
  200. try {
  201. value = parseIntValue(result);
  202. } catch (NumberFormatException e) {
  203. if (DEBUG) {
  204. System.out.println("Exception in getting value of " +
  205. name +" in section " +
  206. section + " " + e.getMessage());
  207. System.out.println("Setting " + name +
  208. " to minimum value");
  209. }
  210. value = Integer.MIN_VALUE;
  211. }
  212. }
  213. return value;
  214. }
  215. /**
  216. * Gets the default string value for the specified name.
  217. * @param name the name.
  218. * @return the default value, null is returned if it cannot be found.
  219. */
  220. public String getDefault(String name) {
  221. if (stanzaTable == null) {
  222. return null;
  223. } else {
  224. return getDefault(name, stanzaTable);
  225. }
  226. }
  227. /**
  228. * This method does the real job to recursively search through the
  229. * stanzaTable.
  230. * @param k the key string.
  231. * @param t stanzaTable or sub hashtable within it.
  232. * @return the value found in config file, returns null if no value
  233. * matched with the key is found.
  234. */
  235. private String getDefault(String k, Hashtable t) {
  236. String result = null;
  237. String key;
  238. if (stanzaTable != null) {
  239. for (Enumeration e = t.keys(); e.hasMoreElements(); ) {
  240. key = (String)e.nextElement();
  241. Object ob = t.get(key);
  242. if (ob instanceof Hashtable) {
  243. result = getDefault(k, (Hashtable)ob);
  244. if (result != null) {
  245. return result;
  246. }
  247. } else if (key.equalsIgnoreCase(k)) {
  248. if (ob instanceof String) {
  249. return (String)(t.get(key));
  250. } else if (ob instanceof Vector) {
  251. result = "";
  252. int length = ((Vector)ob).size();
  253. for (int i = 0; i < length; i++) {
  254. if (i == length -1) {
  255. result +=
  256. (String)(((Vector)ob).elementAt(i));
  257. } else {
  258. result +=
  259. (String)(((Vector)ob).elementAt(i)) + " ";
  260. }
  261. }
  262. return result;
  263. }
  264. }
  265. }
  266. }
  267. return result;
  268. }
  269. /**
  270. * Gets the default string value for the specified name in the
  271. * specified section.
  272. * <br>This method is quicker by using the section name as the search key.
  273. * @param name the name.
  274. * @param section the name of the section.
  275. * @return the default value, null is returned if it cannot be found.
  276. */
  277. public String getDefault(String name, String section) {
  278. String stanzaName;
  279. String result = null;
  280. Hashtable subTable;
  281. if (stanzaTable != null) {
  282. for (Enumeration e = stanzaTable.keys(); e.hasMoreElements(); ) {
  283. stanzaName = (String)e.nextElement();
  284. subTable = (Hashtable)stanzaTable.get(stanzaName);
  285. if (stanzaName.equalsIgnoreCase(section)) {
  286. if (subTable.containsKey(name)) {
  287. return (String)(subTable.get(name));
  288. }
  289. } else if (subTable.containsKey(section)) {
  290. Object ob = subTable.get(section);
  291. if (ob instanceof Hashtable) {
  292. Hashtable temp = (Hashtable)ob;
  293. if (temp.containsKey(name)) {
  294. Object object = temp.get(name);
  295. if (object instanceof Vector) {
  296. result = "";
  297. int length = ((Vector)object).size();
  298. for (int i = 0; i < length; i++) {
  299. if (i == length - 1) {
  300. result +=
  301. (String)(((Vector)object).elementAt(i));
  302. } else {
  303. result +=
  304. (String)(((Vector)object).elementAt(i))
  305. + " ";
  306. }
  307. }
  308. } else {
  309. result = (String)object;
  310. }
  311. }
  312. }
  313. }
  314. }
  315. }
  316. return result;
  317. }
  318. /**
  319. * Gets the default boolean value for the specified name.
  320. * @param name the name.
  321. * @return the default boolean value, false is returned if it cannot be
  322. * found.
  323. */
  324. public boolean getDefaultBooleanValue(String name) {
  325. String val = null;
  326. if (stanzaTable == null) {
  327. val = null;
  328. } else {
  329. val = getDefault(name, stanzaTable);
  330. }
  331. if (val != null && val.equalsIgnoreCase("true")) {
  332. return true;
  333. } else {
  334. return false;
  335. }
  336. }
  337. /**
  338. * Gets the default boolean value for the specified name in the
  339. * specified section.
  340. * <br>This method is quicker by using the section name as the search key.
  341. * @param name the name.
  342. * @param section the name of the section.
  343. * @return the default boolean value, false is returned if it cannot be
  344. * found.
  345. */
  346. public boolean getDefaultBooleanValue(String name, String section) {
  347. String val = getDefault(name, section);
  348. if (val != null && val.equalsIgnoreCase("true")) {
  349. return true;
  350. } else {
  351. return false;
  352. }
  353. }
  354. /**
  355. * Parses a string to an integer. The convertible strings include the
  356. * string representations of positive integers, negative integers, and
  357. * hex decimal integers. Valid inputs are, e.g., -1234, +1234,
  358. * 0x40000.
  359. *
  360. * @param input the String to be converted to an Integer.
  361. * @return an numeric value represented by the string
  362. * @exception NumberFormationException if the String does not contain a
  363. * parsable integer.
  364. */
  365. private int parseIntValue(String input) throws NumberFormatException {
  366. int value = 0;
  367. if (input.startsWith("+")) {
  368. String temp = input.substring(1);
  369. return Integer.parseInt(temp);
  370. } else if (input.startsWith("0x")) {
  371. String temp = input.substring(2);
  372. char[] chars = temp.toCharArray();
  373. if (chars.length > 8) {
  374. throw new NumberFormatException();
  375. } else {
  376. for (int i = 0; i < chars.length; i++) {
  377. int index = chars.length - i - 1;
  378. switch (chars[i]) {
  379. case '0':
  380. value += 0;
  381. break;
  382. case '1':
  383. value += 1 * getBase(index);
  384. break;
  385. case '2':
  386. value += 2 * getBase(index);
  387. break;
  388. case '3':
  389. value += 3 * getBase(index);
  390. break;
  391. case '4':
  392. value += 4 * getBase(index);
  393. break;
  394. case '5':
  395. value += 5 * getBase(index);
  396. break;
  397. case '6':
  398. value += 6 * getBase(index);
  399. break;
  400. case '7':
  401. value += 7 * getBase(index);
  402. break;
  403. case '8':
  404. value += 8 * getBase(index);
  405. break;
  406. case '9':
  407. value += 9 * getBase(index);
  408. break;
  409. case 'a':
  410. case 'A':
  411. value += 10 * getBase(index);
  412. break;
  413. case 'b':
  414. case 'B':
  415. value += 11 * getBase(index);
  416. break;
  417. case 'c':
  418. case 'C':
  419. value += 12 * getBase(index);
  420. break;
  421. case 'd':
  422. case 'D':
  423. value += 13 * getBase(index);
  424. break;
  425. case 'e':
  426. case 'E':
  427. value += 14 * getBase(index);
  428. break;
  429. case 'f':
  430. case 'F':
  431. value += 15 * getBase(index);
  432. break;
  433. default:
  434. throw new NumberFormatException("Invalid numerical format");
  435. }
  436. }
  437. }
  438. if (value < 0) {
  439. throw new NumberFormatException("Data overflow.");
  440. }
  441. } else {
  442. value = Integer.parseInt(input);
  443. }
  444. return value;
  445. }
  446. private int getBase(int i) {
  447. int result = 16;
  448. switch (i) {
  449. case 0:
  450. result = BASE16_0;
  451. break;
  452. case 1:
  453. result = BASE16_1;
  454. break;
  455. case 2:
  456. result = BASE16_2;
  457. break;
  458. case 3:
  459. result = BASE16_3;
  460. break;
  461. default:
  462. for (int j = 1; j < i; j++) {
  463. result *= 16;
  464. }
  465. }
  466. return result;
  467. }
  468. /**
  469. * Finds the matching value in the hashtable.
  470. */
  471. private String find(String key1, String key2) {
  472. String result;
  473. if ((stanzaTable != null) &&
  474. ((result = (String)
  475. (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) {
  476. return result;
  477. } else {
  478. return "";
  479. }
  480. }
  481. /**
  482. * Reads name/value pairs to the memory from the configuration
  483. * file. The default location of the configuration file is in java home
  484. * directory.
  485. *
  486. * Configuration file contains information about the default realm,
  487. * ticket parameters, location of the KDC and the admin server for
  488. * known realms, etc. The file is divided into sections. Each section
  489. * contains one or more name/value pairs with one pair per line. A
  490. * typical file would be:
  491. * [libdefaults]
  492. * default_realm = EXAMPLE.COM
  493. * default_tgs_enctypes = des-cbc-md5
  494. * default_tkt_enctypes = des-cbc-md5
  495. * [realms]
  496. * EXAMPLE.COM = {
  497. * kdc = kerberos.example.com
  498. * kdc = kerberos-1.example.com
  499. * admin_server = kerberos.example.com
  500. * }
  501. * SAMPLE_COM = {
  502. * kdc = orange.sample.com
  503. * admin_server = orange.sample.com
  504. * }
  505. * [domain_realm]
  506. * blue.sample.com = TEST.SAMPLE.COM
  507. * .backup.com = EXAMPLE.COM
  508. */
  509. private Vector<String> loadConfigFile() throws IOException {
  510. try {
  511. final String fileName = getFileName();
  512. if (!fileName.equals("")) {
  513. BufferedReader br = new BufferedReader(new InputStreamReader(
  514. java.security.AccessController.doPrivileged(
  515. new java.security.PrivilegedExceptionAction<FileInputStream> () {
  516. public FileInputStream run() throws IOException {
  517. return new FileInputStream(fileName);
  518. }
  519. })));
  520. String Line;
  521. Vector<String> v = new Vector<>();
  522. String previous = null;
  523. while ((Line = br.readLine()) != null) {
  524. // ignore comments and blank line in the configuration file.
  525. // Comments start with #.
  526. if (!(Line.startsWith("#") || Line.trim().isEmpty())) {
  527. String current = Line.trim();
  528. // In practice, a subsection might look like:
  529. // EXAMPLE.COM =
  530. // {
  531. // kdc = kerberos.example.com
  532. // ...
  533. // }
  534. // Before parsed into stanza table, it needs to be
  535. // converted into formal style:
  536. // EXAMPLE.COM = {
  537. // kdc = kerberos.example.com
  538. // ...
  539. // }
  540. //
  541. // So, if a line is "{", adhere to the previous line.
  542. if (current.equals("{")) {
  543. if (previous == null) {
  544. throw new IOException(
  545. "Config file should not start with \"{\"");
  546. }
  547. previous += " " + current;
  548. } else {
  549. if (previous != null) {
  550. v.addElement(previous);
  551. }
  552. previous = current;
  553. }
  554. }
  555. }
  556. if (previous != null) {
  557. v.addElement(previous);
  558. }
  559. br.close();
  560. return v;
  561. }
  562. return null;
  563. } catch (java.security.PrivilegedActionException pe) {
  564. throw (IOException)pe.getException();
  565. }
  566. }
  567. /**
  568. * Parses stanza names and values from configuration file to
  569. * stanzaTable (Hashtable). Hashtable key would be stanza names,
  570. * (libdefaults, realms, domain_realms, etc), and the hashtable value
  571. * would be another hashtable which contains the key-value pairs under
  572. * a stanza name.
  573. */
  574. private Hashtable<String,Object> parseStanzaTable(Vector<String> v) throws KrbException {
  575. if (v == null) {
  576. throw new KrbException("I/O error while reading" +
  577. " configuration file.");
  578. }
  579. Hashtable<String,Object> table = new Hashtable<>();
  580. for (int i = 0; i < v.size(); i++) {
  581. String line = v.elementAt(i).trim();
  582. if (line.equalsIgnoreCase("[realms]")) {
  583. for (int count = i + 1; count < v.size() + 1; count++) {
  584. // find the next stanza name
  585. if ((count == v.size()) ||
  586. (v.elementAt(count).startsWith("["))) {
  587. Hashtable<String,Hashtable<String,Vector<String>>> temp =
  588. new Hashtable<>();
  589. temp = parseRealmField(v, i + 1, count);
  590. table.put("realms", temp);
  591. i = count - 1;
  592. break;
  593. }
  594. }
  595. } else if (line.equalsIgnoreCase("[capaths]")) {
  596. for (int count = i + 1; count < v.size() + 1; count++) {
  597. // find the next stanza name
  598. if ((count == v.size()) ||
  599. (v.elementAt(count).startsWith("["))) {
  600. Hashtable<String,Hashtable<String,Vector<String>>> temp =
  601. new Hashtable<>();
  602. temp = parseRealmField(v, i + 1, count);
  603. table.put("capaths", temp);
  604. i = count - 1;
  605. break;
  606. }
  607. }
  608. } else if (line.startsWith("[") && line.endsWith("]")) {
  609. String key = line.substring(1, line.length() - 1);
  610. for (int count = i + 1; count < v.size() + 1; count++) {
  611. // find the next stanza name
  612. if ((count == v.size()) ||
  613. (v.elementAt(count).startsWith("["))) {
  614. Hashtable<String,String> temp =
  615. parseField(v, i + 1, count);
  616. table.put(key, temp);
  617. i = count - 1;
  618. break;
  619. }
  620. }
  621. }
  622. }
  623. return table;
  624. }
  625. /**
  626. * Gets the default configuration file name. This method will never
  627. * return null.
  628. *
  629. * If the system property "java.security.krb5.conf" is defined, we'll
  630. * use its value, no matter if the file exists or not. Otherwise,
  631. * the file will be searched in a list of possible loations in the
  632. * following order:
  633. *
  634. * 1. at Java home lib\security directory with "krb5.conf" name,
  635. * 2. at windows directory with the name of "krb5.ini" for Windows,
  636. * /etc/krb5/krb5.conf for Solaris, /etc/krb5.conf otherwise.
  637. *
  638. * Note: When the Terminal Service is started in Windows (from 2003),
  639. * there are two kinds of Windows directories: A system one (say,
  640. * C:\Windows), and a user-private one (say, C:\Users\Me\Windows).
  641. * We will first look for krb5.ini in the user-private one. If not
  642. * found, try the system one instead.
  643. */
  644. private String getFileName() {
  645. String name =
  646. java.security.AccessController.doPrivileged(
  647. new sun.security.action.
  648. GetPropertyAction("java.security.krb5.conf"));
  649. if (name == null) {
  650. name = java.security.AccessController.doPrivileged(
  651. new sun.security.action.
  652. GetPropertyAction("java.home")) + File.separator +
  653. "lib" + File.separator + "security" +
  654. File.separator + "krb5.conf";
  655. if (!fileExists(name)) {
  656. name = null;
  657. String osname =
  658. java.security.AccessController.doPrivileged(
  659. new sun.security.action.GetPropertyAction("os.name"));
  660. if (osname.startsWith("Windows")) {
  661. try {
  662. Credentials.ensureLoaded();
  663. } catch (Exception e) {
  664. // ignore exceptions
  665. }
  666. if (Credentials.alreadyLoaded) {
  667. String path = getWindowsDirectory(false);
  668. if (path != null) {
  669. if (path.endsWith("\\")) {
  670. path = path + "krb5.ini";
  671. } else {
  672. path = path + "\\krb5.ini";
  673. }
  674. if (fileExists(path)) {
  675. name = path;
  676. }
  677. }
  678. if (name == null) {
  679. path = getWindowsDirectory(true);
  680. if (path != null) {
  681. if (path.endsWith("\\")) {
  682. path = path + "krb5.ini";
  683. } else {
  684. path = path + "\\krb5.ini";
  685. }
  686. name = path;
  687. }
  688. }
  689. }
  690. if (name == null) {
  691. name = "c:\\winnt\\krb5.ini";
  692. }
  693. } else if (osname.startsWith("SunOS")) {
  694. name = "/etc/krb5/krb5.conf";
  695. } else if (osname.contains("OS X")) {
  696. if (isMacosLionOrBetter()) return "";
  697. name = findMacosConfigFile();
  698. } else {
  699. name = "/etc/krb5.conf";
  700. }
  701. }
  702. }
  703. if (DEBUG) {
  704. System.out.println("Config name: " + name);
  705. }
  706. return name;
  707. }
  708. private String getProperty(String property) {
  709. return (String)java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction(property));
  710. }
  711. private String findMacosConfigFile() {
  712. String userHome = getProperty("user.home");
  713. final String PREF_FILE = "/Library/Preferences/edu.mit.Kerberos";
  714. String userPrefs=userHome + PREF_FILE;
  715. if (fileExists(userPrefs)) {
  716. return userPrefs;
  717. }
  718. if (fileExists(PREF_FILE)) {
  719. return PREF_FILE;
  720. }
  721. if (fileExists("/etc/krb5.conf")) {
  722. return "/etc/krb5.conf";
  723. }
  724. return "";
  725. }
  726. private static String trimmed(String s) {
  727. s = s.trim();
  728. if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' ||
  729. s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') {
  730. s = s.substring(1, s.length()-1).trim();
  731. }
  732. return s;
  733. }
  734. /**
  735. * Parses key-value pairs under a stanza name.
  736. */
  737. private Hashtable<String,String> parseField(Vector<String> v, int start, int end) {
  738. Hashtable<String,String> table = new Hashtable<>();
  739. String line;
  740. for (int i = start; i < end; i++) {
  741. line = v.elementAt(i);
  742. for (int j = 0; j < line.length(); j++) {
  743. if (line.charAt(j) == '=') {
  744. String key = (line.substring(0, j)).trim();
  745. String value = trimmed(line.substring(j + 1));
  746. table.put(key, value);
  747. break;
  748. }
  749. }
  750. }
  751. return table;
  752. }
  753. /**
  754. * Parses key-value pairs under [realms]. The key would be the realm
  755. * name, the value would be another hashtable which contains
  756. * information for the realm given within a pair of braces.
  757. */
  758. private Hashtable<String,Hashtable<String,Vector<String>>> parseRealmField(Vector<String> v, int start, int end) {
  759. Hashtable<String,Hashtable<String,Vector<String>>> table = new Hashtable<>();
  760. String line;
  761. for (int i = start; i < end; i++) {
  762. line = v.elementAt(i).trim();
  763. if (line.endsWith("{")) {
  764. String key = "";
  765. for (int j = 0; j < line.length(); j++) {
  766. if (line.charAt(j) == '=') {
  767. key = line.substring(0, j).trim();
  768. // get the key
  769. break;
  770. }
  771. }
  772. for (int k = i + 1; k < end; k++) {
  773. boolean found = false;
  774. line = v.elementAt(k).trim();
  775. for (int l = 0; l < line.length(); l++) {
  776. if (line.charAt(l) == '}') {
  777. found = true;
  778. break;
  779. }
  780. }
  781. if (found == true) {
  782. Hashtable<String,Vector<String>> temp = parseRealmFieldEx(v, i + 1, k);
  783. table.put(key, temp);
  784. i = k;
  785. found = false;
  786. break;
  787. }
  788. }
  789. }
  790. }
  791. return table;
  792. }
  793. /**
  794. * Parses key-value pairs within each braces under [realms].
  795. */
  796. private Hashtable<String,Vector<String>> parseRealmFieldEx(Vector<String> v, int start, int end) {
  797. Hashtable<String,Vector<String>> table = new Hashtable<>();
  798. Vector<String> keyVector = new Vector<>();
  799. Vector<String> nameVector = new Vector<>();
  800. String line = "";
  801. String key;
  802. for (int i = start; i < end; i++) {
  803. line = v.elementAt(i);
  804. for (int j = 0; j < line.length(); j++) {
  805. if (line.charAt(j) == '=') {
  806. int index;
  807. key = line.substring(0, j).trim();
  808. if (! exists(key, keyVector)) {
  809. keyVector.addElement(key);
  810. nameVector = new Vector<String> ();
  811. } else {
  812. nameVector = table.get(key);
  813. }
  814. nameVector.addElement(trimmed(line.substring(j + 1)));
  815. table.put(key, nameVector);
  816. break;
  817. }
  818. }
  819. }
  820. return table;
  821. }
  822. /**
  823. * Compares the key with the known keys to see if it exists.
  824. */
  825. private boolean exists(String key, Vector v) {
  826. boolean exists = false;
  827. for (int i = 0; i < v.size(); i++) {
  828. if (((String)(v.elementAt(i))).equals(key)) {
  829. exists = true;
  830. }
  831. }
  832. return exists;
  833. }
  834. /**
  835. * For testing purpose. This method lists all information being parsed from
  836. * the configuration file to the hashtable.
  837. */
  838. public void listTable() {
  839. listTable(stanzaTable);
  840. }
  841. private void listTable(Hashtable table) {
  842. Vector v = new Vector();
  843. String key;
  844. if (stanzaTable != null) {
  845. for (Enumeration e = table.keys(); e.hasMoreElements(); ) {
  846. key = (String)e.nextElement();
  847. Object object = table.get(key);
  848. if (table == stanzaTable) {
  849. System.out.println("[" + key + "]");
  850. }
  851. if (object instanceof Hashtable) {
  852. if (table != stanzaTable)
  853. System.out.println("\t" + key + " = {");
  854. listTable((Hashtable)object);
  855. if (table != stanzaTable)
  856. System.out.println("\t}");
  857. } else if (object instanceof String) {
  858. System.out.println("\t" + key + " = " +
  859. (String)table.get(key));
  860. } else if (object instanceof Vector) {
  861. v = (Vector)object;
  862. for (int i = 0; i < v.size(); i++) {
  863. System.out.println("\t" + key + " = " +
  864. (String)v.elementAt(i));
  865. }
  866. }
  867. }
  868. } else {
  869. System.out.println("Configuration file not found.");
  870. }
  871. }
  872. /**
  873. * Returns the default encryption types.
  874. *
  875. */
  876. public int[] defaultEtype(String enctypes) {
  877. String default_enctypes;
  878. default_enctypes = getDefault(enctypes, "libdefaults");
  879. String delim = " ";
  880. StringTokenizer st;
  881. int[] etype;
  882. if (default_enctypes == null) {
  883. if (DEBUG) {
  884. System.out.println("Using builtin default etypes for " +
  885. enctypes);
  886. }
  887. etype = EType.getBuiltInDefaults();
  888. } else {
  889. for (int j = 0; j < default_enctypes.length(); j++) {
  890. if (default_enctypes.substring(j, j + 1).equals(",")) {
  891. // only two delimiters are allowed to use
  892. // according to Kerberos DCE doc.
  893. delim = ",";
  894. break;
  895. }
  896. }
  897. st = new StringTokenizer(default_enctypes, delim);
  898. int len = st.countTokens();
  899. ArrayList<Integer> ls = new ArrayList<>(len);
  900. int type;
  901. for (int i = 0; i < len; i++) {
  902. type = getType(st.nextToken());
  903. if ((type != -1) &&
  904. (EType.isSupported(type))) {
  905. ls.add(type);
  906. }
  907. }
  908. if (ls.size() == 0) {
  909. if (DEBUG) {
  910. System.out.println(
  911. "no supported default etypes for " + enctypes);
  912. }
  913. return null;
  914. } else {
  915. etype = new int[ls.size()];
  916. for (int i = 0; i < etype.length; i++) {
  917. etype[i] = ls.get(i);
  918. }
  919. }
  920. }
  921. if (DEBUG) {
  922. System.out.print("default etypes for " + enctypes + ":");
  923. for (int i = 0; i < etype.length; i++) {
  924. System.out.print(" " + etype[i]);
  925. }
  926. System.out.println(".");
  927. }
  928. return etype;
  929. }
  930. /**
  931. * Get the etype and checksum value for the specified encryption and
  932. * checksum type.
  933. *
  934. */
  935. /*
  936. * This method converts the string representation of encryption type and
  937. * checksum type to int value that can be later used by EType and
  938. * Checksum classes.
  939. */
  940. public int getType(String input) {
  941. int result = -1;
  942. if (input == null) {
  943. return result;
  944. }
  945. if (input.startsWith("d") || (input.startsWith("D"))) {
  946. if (input.equalsIgnoreCase("des-cbc-crc")) {
  947. result = EncryptedData.ETYPE_DES_CBC_CRC;
  948. } else if (input.equalsIgnoreCase("des-cbc-md5")) {
  949. result = EncryptedData.ETYPE_DES_CBC_MD5;
  950. } else if (input.equalsIgnoreCase("des-mac")) {
  951. result = Checksum.CKSUMTYPE_DES_MAC;
  952. } else if (input.equalsIgnoreCase("des-mac-k")) {
  953. result = Checksum.CKSUMTYPE_DES_MAC_K;
  954. } else if (input.equalsIgnoreCase("des-cbc-md4")) {
  955. result = EncryptedData.ETYPE_DES_CBC_MD4;
  956. } else if (input.equalsIgnoreCase("des3-cbc-sha1") ||
  957. input.equalsIgnoreCase("des3-hmac-sha1") ||
  958. input.equalsIgnoreCase("des3-cbc-sha1-kd") ||
  959. input.equalsIgnoreCase("des3-cbc-hmac-sha1-kd")) {
  960. result = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
  961. }
  962. } else if (input.startsWith("a") || (input.startsWith("A"))) {
  963. // AES
  964. if (input.equalsIgnoreCase("aes128-cts") ||
  965. input.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
  966. result = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
  967. } else if (input.equalsIgnoreCase("aes256-cts") ||
  968. input.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
  969. result = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
  970. // ARCFOUR-HMAC
  971. } else if (input.equalsIgnoreCase("arcfour-hmac") ||
  972. input.equalsIgnoreCase("arcfour-hmac-md5")) {
  973. result = EncryptedData.ETYPE_ARCFOUR_HMAC;
  974. }
  975. // RC4-HMAC
  976. } else if (input.equalsIgnoreCase("rc4-hmac")) {
  977. result = EncryptedData.ETYPE_ARCFOUR_HMAC;
  978. } else if (input.equalsIgnoreCase("CRC32")) {
  979. result = Checksum.CKSUMTYPE_CRC32;
  980. } else if (input.startsWith("r") || (input.startsWith("R"))) {
  981. if (input.equalsIgnoreCase("rsa-md5")) {
  982. result = Checksum.CKSUMTYPE_RSA_MD5;
  983. } else if (input.equalsIgnoreCase("rsa-md5-des")) {
  984. result = Checksum.CKSUMTYPE_RSA_MD5_DES;
  985. }
  986. } else if (input.equalsIgnoreCase("hmac-sha1-des3-kd")) {
  987. result = Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD;
  988. } else if (input.equalsIgnoreCase("hmac-sha1-96-aes128")) {
  989. result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
  990. } else if (input.equalsIgnoreCase("hmac-sha1-96-aes256")) {
  991. result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
  992. } else if (input.equalsIgnoreCase("hmac-md5-rc4") ||
  993. input.equalsIgnoreCase("hmac-md5-arcfour") ||
  994. input.equalsIgnoreCase("hmac-md5-enc")) {
  995. result = Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR;
  996. } else if (input.equalsIgnoreCase("NULL")) {
  997. result = EncryptedData.ETYPE_NULL;
  998. }
  999. return result;
  1000. }
  1001. /**
  1002. * Resets the default kdc realm.
  1003. * We do not need to synchronize these methods since assignments are atomic
  1004. *
  1005. * This method was useless. Kept here in case some class still calls it.
  1006. */
  1007. public void resetDefaultRealm(String realm) {
  1008. if (DEBUG) {
  1009. System.out.println(">>> Config try resetting default kdc " + realm);
  1010. }
  1011. }
  1012. /**
  1013. * Check to use addresses in tickets
  1014. * use addresses if "no_addresses" or "noaddresses" is set to false
  1015. */
  1016. public boolean useAddresses() {
  1017. boolean useAddr = false;
  1018. // use addresses if "no_addresses" is set to false
  1019. String value = getDefault("no_addresses", "libdefaults");
  1020. useAddr = (value != null && value.equalsIgnoreCase("false"));
  1021. if (useAddr == false) {
  1022. // use addresses if "noaddresses" is set to false
  1023. value = getDefault("noaddresses", "libdefaults");
  1024. useAddr = (value != null && value.equalsIgnoreCase("false"));
  1025. }
  1026. return useAddr;
  1027. }
  1028. /**
  1029. * Check if need to use DNS to locate Kerberos services
  1030. */
  1031. public boolean useDNS(String name) {
  1032. String value = getDefault(name, "libdefaults");
  1033. if (value == null) {
  1034. value = getDefault("dns_fallback", "libdefaults");
  1035. if ("false".equalsIgnoreCase(value)) {
  1036. return false;
  1037. } else {
  1038. return true;
  1039. }
  1040. } else {
  1041. return value.equalsIgnoreCase("true");
  1042. }
  1043. }
  1044. /**
  1045. * Check if need to use DNS to locate the KDC
  1046. */
  1047. public boolean useDNS_KDC() {
  1048. return useDNS("dns_lookup_kdc");
  1049. }
  1050. /*
  1051. * Check if need to use DNS to locate the Realm
  1052. */
  1053. public boolean useDNS_Realm() {
  1054. return useDNS("dns_lookup_realm");
  1055. }
  1056. /**
  1057. * Gets default realm.
  1058. * @throws KrbException where no realm can be located
  1059. * @return the default realm, always non null
  1060. */
  1061. public String getDefaultRealm() throws KrbException {
  1062. if (defaultRealm != null) {
  1063. return defaultRealm;
  1064. }
  1065. Exception cause = null;
  1066. String realm = getDefault("default_realm", "libdefaults");
  1067. if ((realm == null) && useDNS_Realm()) {
  1068. // use DNS to locate Kerberos realm
  1069. try {
  1070. realm = getRealmFromDNS();
  1071. } catch (KrbException ke) {
  1072. cause = ke;
  1073. }
  1074. }
  1075. if (realm == null) {
  1076. realm = java.security.AccessController.doPrivileged(
  1077. new java.security.PrivilegedAction<String>() {
  1078. @Override
  1079. public String run() {
  1080. String osname = System.getProperty("os.name");
  1081. if (osname.startsWith("Windows")) {
  1082. return System.getenv("USERDNSDOMAIN");
  1083. }
  1084. return null;
  1085. }
  1086. });
  1087. }
  1088. if (realm == null) {
  1089. KrbException ke = new KrbException("Cannot locate default realm");
  1090. if (cause != null) {
  1091. ke.initCause(cause);
  1092. }
  1093. throw ke;
  1094. }
  1095. return realm;
  1096. }
  1097. /**
  1098. * Returns a list of KDC's with each KDC separated by a space
  1099. *
  1100. * @param realm the realm for which the KDC list is desired
  1101. * @throws KrbException if there's no way to find KDC for the realm
  1102. * @return the list of KDCs separated by a space, always non null
  1103. */
  1104. public String getKDCList(String realm) throws KrbException {
  1105. if (realm == null) {
  1106. realm = getDefaultRealm();
  1107. }
  1108. if (realm.equalsIgnoreCase(defaultRealm)) {
  1109. return defaultKDC;
  1110. }
  1111. Exception cause = null;
  1112. String kdcs = getDefault("kdc", realm);
  1113. if ((kdcs == null) && useDNS_KDC()) {
  1114. // use DNS to locate KDC
  1115. try {
  1116. kdcs = getKDCFromDNS(realm);
  1117. } catch (KrbException ke) {
  1118. cause = ke;
  1119. }
  1120. }
  1121. if (kdcs == null) {
  1122. kdcs = java.security.AccessController.doPrivileged(
  1123. new java.security.PrivilegedAction<String>() {
  1124. @Override
  1125. public String run() {
  1126. String osname = System.getProperty("os.name");
  1127. if (osname.startsWith("Windows")) {
  1128. String logonServer = System.getenv("LOGONSERVER");
  1129. if (logonServer != null
  1130. && logonServer.startsWith("\\\\")) {
  1131. logonServer = logonServer.substring(2);
  1132. }
  1133. return logonServer;
  1134. }
  1135. return null;
  1136. }
  1137. });
  1138. }
  1139. if (kdcs == null) {
  1140. if (defaultKDC != null) {
  1141. return defaultKDC;
  1142. }
  1143. KrbException ke = new KrbException("Cannot locate KDC");
  1144. if (cause != null) {
  1145. ke.initCause(cause);
  1146. }
  1147. throw ke;
  1148. }
  1149. return kdcs;
  1150. }
  1151. /**
  1152. * Locate Kerberos realm using DNS
  1153. *
  1154. * @return the Kerberos realm
  1155. */
  1156. private String getRealmFromDNS() throws KrbException {
  1157. // use DNS to locate Kerberos realm
  1158. String realm = null;
  1159. String hostName = null;
  1160. try {
  1161. hostName = InetAddress.getLocalHost().getCanonicalHostName();
  1162. } catch (UnknownHostException e) {
  1163. KrbException ke = new KrbException(Krb5.KRB_ERR_GENERIC,
  1164. "Unable to locate Kerberos realm: " + e.getMessage());
  1165. ke.initCause(e);
  1166. throw (ke);
  1167. }
  1168. // get the domain realm mapping from the configuration
  1169. String mapRealm = PrincipalName.mapHostToRealm(hostName);
  1170. if (mapRealm == null) {
  1171. // No match. Try search and/or domain in /etc/resolv.conf
  1172. List<String> srchlist = ResolverConfiguration.open().searchlist();
  1173. for (String domain: srchlist) {
  1174. realm = checkRealm(domain);
  1175. if (realm != null) {
  1176. break;
  1177. }
  1178. }
  1179. } else {
  1180. realm = checkRealm(mapRealm);
  1181. }
  1182. if (realm == null) {
  1183. throw new KrbException(Krb5.KRB_ERR_GENERIC,
  1184. "Unable to locate Kerberos realm");
  1185. }
  1186. return realm;
  1187. }
  1188. /**
  1189. * Check if the provided realm is the correct realm
  1190. * @return the realm if correct, or null otherwise
  1191. */
  1192. private static String checkRealm(String mapRealm) {
  1193. if (DEBUG) {
  1194. System.out.println("getRealmFromDNS: trying " + mapRealm);
  1195. }
  1196. String[] records = null;
  1197. String newRealm = mapRealm;
  1198. while ((records == null) && (newRealm != null)) {
  1199. // locate DNS TXT record
  1200. records = KrbServiceLocator.getKerberosService(newRealm);
  1201. newRealm = Realm.parseRealmComponent(newRealm);
  1202. // if no DNS TXT records found, try again using sub-realm
  1203. }
  1204. if (records != null) {
  1205. for (int i = 0; i < records.length; i++) {
  1206. if (records[i].equalsIgnoreCase(mapRealm)) {
  1207. return records[i];
  1208. }
  1209. }
  1210. }
  1211. return null;
  1212. }
  1213. /**
  1214. * Locate KDC using DNS
  1215. *
  1216. * @param realm the realm for which the master KDC is desired
  1217. * @return the KDC
  1218. */
  1219. private String getKDCFromDNS(String realm) throws KrbException {
  1220. // use DNS to locate KDC
  1221. String kdcs = null;
  1222. String[] srvs = null;
  1223. // locate DNS SRV record using UDP
  1224. if (DEBUG) {
  1225. System.out.println("getKDCFromDNS using UDP");
  1226. }
  1227. srvs = KrbServiceLocator.getKerberosService(realm, "_udp");
  1228. if (srvs == null) {
  1229. // locate DNS SRV record using TCP
  1230. if (DEBUG) {
  1231. System.out.println("getKDCFromDNS using UDP");
  1232. }
  1233. srvs = KrbServiceLocator.getKerberosService(realm, "_tcp");
  1234. }
  1235. if (srvs == null) {
  1236. // no DNS SRV records
  1237. throw new KrbException(Krb5.KRB_ERR_GENERIC,
  1238. "Unable to locate KDC for realm " + realm);
  1239. }
  1240. for (int i = 0; i < srvs.length; i++) {
  1241. String value = srvs[i];
  1242. for (int j = 0; j < srvs[i].length(); j++) {
  1243. // filter the KDC name
  1244. if (value.charAt(j) == ':') {
  1245. kdcs = (value.substring(0, j)).trim();
  1246. }
  1247. }
  1248. }
  1249. return kdcs;
  1250. }
  1251. private boolean fileExists(String name) {
  1252. return java.security.AccessController.doPrivileged(
  1253. new FileExistsAction(name));
  1254. }
  1255. static class FileExistsAction
  1256. implements java.security.PrivilegedAction<Boolean> {
  1257. private String fileName;
  1258. public FileExistsAction(String fileName) {
  1259. this.fileName = fileName;
  1260. }
  1261. public Boolean run() {
  1262. return new File(fileName).exists();
  1263. }
  1264. }
  1265. @Override
  1266. public String toString() {
  1267. StringBuffer sb = new StringBuffer();
  1268. toStringIndented("", stanzaTable, sb);
  1269. return sb.toString();
  1270. }
  1271. private static void toStringIndented(String prefix, Object obj,
  1272. StringBuffer sb) {
  1273. if (obj instanceof S

Large files files are truncated, but you can click here to view the full file