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

/MRI-J/jdk/src/share/classes/sun/security/krb5/Config.java

http://github.com/GregBowyer/ManagedRuntimeInitiative
Java | 1073 lines | 829 code | 31 blank | 213 comment | 125 complexity | 7acf1d77d3c9025d28563ef4369efeba MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0
  1. /*
  2. * Portions Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22. * CA 95054 USA or visit www.sun.com if you need additional information or
  23. * have any questions.
  24. */
  25. /*
  26. * (C) Copyright IBM Corp. 1999 All Rights Reserved.
  27. * Copyright 1997 The Open Group Research Institute. All rights reserved.
  28. */
  29. package sun.security.krb5;
  30. import java.io.File;
  31. import java.io.FileInputStream;
  32. import java.util.Hashtable;
  33. import java.util.Vector;
  34. import java.util.ArrayList;
  35. import java.io.BufferedReader;
  36. import java.io.InputStreamReader;
  37. import java.io.IOException;
  38. import java.util.Enumeration;
  39. import java.util.List;
  40. import java.util.StringTokenizer;
  41. import sun.security.krb5.internal.crypto.EType;
  42. import sun.security.krb5.internal.ktab.*;
  43. /**
  44. * This class maintains key-value pairs of Kerberos configurable constants
  45. * from configuration file or from user specified system properties.
  46. */
  47. public class Config {
  48. /*
  49. * Only allow a single instance of Config.
  50. */
  51. private static Config singleton = null;
  52. /*
  53. * Hashtable used to store configuration infomation.
  54. */
  55. private Hashtable<String,Object> stanzaTable;
  56. private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
  57. // these are used for hexdecimal calculation.
  58. private static final int BASE16_0 = 1;
  59. private static final int BASE16_1 = 16;
  60. private static final int BASE16_2 = 16 * 16;
  61. private static final int BASE16_3 = 16 * 16 * 16;
  62. private String defaultRealm; // default kdc realm.
  63. // used for native interface
  64. private static native String getWindowsDirectory();
  65. /**
  66. * Gets an instance of Config class. One and only one instance (the
  67. * singleton) is returned.
  68. *
  69. * @exception KrbException if error occurs when constructing a Config
  70. * instance. Possible causes would be configuration file not
  71. * found, either of java.security.krb5.realm or java.security.krb5.kdc
  72. * not specified, error reading configuration file.
  73. */
  74. public static synchronized Config getInstance() throws KrbException {
  75. if (singleton == null) {
  76. singleton = new Config();
  77. }
  78. return singleton;
  79. }
  80. /**
  81. * Refresh and reload the Configuration. This could involve,
  82. * for example reading the Configuration file again or getting
  83. * the java.security.krb5.* system properties again.
  84. *
  85. * @exception KrbException if error occurs when constructing a Config
  86. * instance. Possible causes would be configuration file not
  87. * found, either of java.security.krb5.realm or java.security.krb5.kdc
  88. * not specified, error reading configuration file.
  89. */
  90. public static synchronized void refresh() throws KrbException {
  91. singleton = new Config();
  92. KeyTab.refresh();
  93. }
  94. /**
  95. * Private constructor - can not be instantiated externally.
  96. */
  97. private Config() throws KrbException {
  98. /*
  99. * If these two system properties are being specified by the user,
  100. * we ignore configuration file. If either one system property is
  101. * specified, we throw exception. If neither of them are specified,
  102. * we load the information from configuration file.
  103. */
  104. String kdchost =
  105. java.security.AccessController.doPrivileged(
  106. new sun.security.action.GetPropertyAction
  107. ("java.security.krb5.kdc"));
  108. defaultRealm =
  109. java.security.AccessController.doPrivileged(
  110. new sun.security.action.GetPropertyAction
  111. ("java.security.krb5.realm"));
  112. if ((kdchost == null && defaultRealm != null) ||
  113. (defaultRealm == null && kdchost != null)) {
  114. throw new KrbException
  115. ("System property java.security.krb5.kdc and " +
  116. "java.security.krb5.realm both must be set or " +
  117. "neither must be set.");
  118. }
  119. if (kdchost != null) {
  120. /*
  121. * If configuration information is only specified by
  122. * properties java.security.krb5.kdc and
  123. * java.security.krb5.realm, we put both in the hashtable
  124. * under [libdefaults].
  125. */
  126. Hashtable<String,String> kdcs = new Hashtable<String,String> ();
  127. kdcs.put("default_realm", defaultRealm);
  128. // The user can specify a list of kdc hosts separated by ":"
  129. kdchost = kdchost.replace(':', ' ');
  130. kdcs.put("kdc", kdchost);
  131. stanzaTable = new Hashtable<String,Object> ();
  132. stanzaTable.put("libdefaults", kdcs);
  133. } else {
  134. // Read the Kerberos configuration file
  135. try {
  136. Vector<String> configFile;
  137. configFile = loadConfigFile();
  138. stanzaTable = parseStanzaTable(configFile);
  139. } catch (IOException ioe) {
  140. KrbException ke = new KrbException("Could not load " +
  141. "configuration file " +
  142. ioe.getMessage());
  143. ke.initCause(ioe);
  144. throw(ke);
  145. }
  146. }
  147. }
  148. /**
  149. * Gets the default int value for the specified name.
  150. * @param name the name.
  151. * @return the default Integer, null is returned if no such name and
  152. * value are found in configuration file, or error occurs when parsing
  153. * string to integer.
  154. */
  155. public int getDefaultIntValue(String name) {
  156. String result = null;
  157. int value = Integer.MIN_VALUE;
  158. result = getDefault(name);
  159. if (result != null) {
  160. try {
  161. value = parseIntValue(result);
  162. } catch (NumberFormatException e) {
  163. if (DEBUG) {
  164. System.out.println("Exception in getting value of " +
  165. name + " " +
  166. e.getMessage());
  167. System.out.println("Setting " + name +
  168. " to minimum value");
  169. }
  170. value = Integer.MIN_VALUE;
  171. }
  172. }
  173. return value;
  174. }
  175. /**
  176. * Gets the default int value for the specified name in the specified
  177. * section. <br>This method is quicker by using section name as the
  178. * search key.
  179. * @param name the name.
  180. * @param sectio the name string of the section.
  181. * @return the default Integer, null is returned if no such name and
  182. * value are found in configuration file, or error occurs when parsing
  183. * string to integer.
  184. */
  185. public int getDefaultIntValue(String name, String section) {
  186. String result = null;
  187. int value = Integer.MIN_VALUE;
  188. result = getDefault(name, section);
  189. if (result != null) {
  190. try {
  191. value = parseIntValue(result);
  192. } catch (NumberFormatException e) {
  193. if (DEBUG) {
  194. System.out.println("Exception in getting value of " +
  195. name +" in section " +
  196. section + " " + e.getMessage());
  197. System.out.println("Setting " + name +
  198. " to minimum value");
  199. }
  200. value = Integer.MIN_VALUE;
  201. }
  202. }
  203. return value;
  204. }
  205. /**
  206. * Gets the default string value for the specified name.
  207. * @param name the name.
  208. * @return the default value, null is returned if it cannot be found.
  209. */
  210. public String getDefault(String name) {
  211. if (stanzaTable == null) {
  212. return null;
  213. } else {
  214. return getDefault(name, stanzaTable);
  215. }
  216. }
  217. /**
  218. * This method does the real job to recursively search through the
  219. * stanzaTable.
  220. * @param k the key string.
  221. * @param t stanzaTable or sub hashtable within it.
  222. * @return the value found in config file, returns null if no value
  223. * matched with the key is found.
  224. */
  225. private String getDefault(String k, Hashtable t) {
  226. String result = null;
  227. String key;
  228. if (stanzaTable != null) {
  229. for (Enumeration e = t.keys(); e.hasMoreElements(); ) {
  230. key = (String)e.nextElement();
  231. Object ob = t.get(key);
  232. if (ob instanceof Hashtable) {
  233. result = getDefault(k, (Hashtable)ob);
  234. if (result != null) {
  235. return result;
  236. }
  237. } else if (key.equalsIgnoreCase(k)) {
  238. if (ob instanceof String) {
  239. return (String)(t.get(key));
  240. } else if (ob instanceof Vector) {
  241. result = "";
  242. int length = ((Vector)ob).size();
  243. for (int i = 0; i < length; i++) {
  244. if (i == length -1) {
  245. result +=
  246. (String)(((Vector)ob).elementAt(i));
  247. } else {
  248. result +=
  249. (String)(((Vector)ob).elementAt(i)) + " ";
  250. }
  251. }
  252. return result;
  253. }
  254. }
  255. }
  256. }
  257. return result;
  258. }
  259. /**
  260. * Gets the default string value for the specified name in the
  261. * specified section.
  262. * <br>This method is quicker by using the section name as the search key.
  263. * @param name the name.
  264. * @param section the name of the section.
  265. * @return the default value, null is returned if it cannot be found.
  266. */
  267. public String getDefault(String name, String section) {
  268. String stanzaName;
  269. String result = null;
  270. Hashtable subTable;
  271. /*
  272. * In the situation when kdc is specified by
  273. * java.security.krb5.kdc, we get the kdc from [libdefaults] in
  274. * hashtable.
  275. */
  276. if (name.equalsIgnoreCase("kdc") &&
  277. (!section.equalsIgnoreCase("libdefaults")) &&
  278. (java.security.AccessController.doPrivileged(
  279. new sun.security.action.
  280. GetPropertyAction("java.security.krb5.kdc")) != null)) {
  281. result = getDefault("kdc", "libdefaults");
  282. return result;
  283. }
  284. if (stanzaTable != null) {
  285. for (Enumeration e = stanzaTable.keys(); e.hasMoreElements(); ) {
  286. stanzaName = (String)e.nextElement();
  287. subTable = (Hashtable)stanzaTable.get(stanzaName);
  288. if (stanzaName.equalsIgnoreCase(section)) {
  289. if (subTable.containsKey(name)) {
  290. return (String)(subTable.get(name));
  291. }
  292. } else if (subTable.containsKey(section)) {
  293. Object ob = subTable.get(section);
  294. if (ob instanceof Hashtable) {
  295. Hashtable temp = (Hashtable)ob;
  296. if (temp.containsKey(name)) {
  297. Object object = temp.get(name);
  298. if (object instanceof Vector) {
  299. result = "";
  300. int length = ((Vector)object).size();
  301. for (int i = 0; i < length; i++) {
  302. if (i == length - 1) {
  303. result +=
  304. (String)(((Vector)object).elementAt(i));
  305. } else {
  306. result +=
  307. (String)(((Vector)object).elementAt(i))
  308. + " ";
  309. }
  310. }
  311. } else {
  312. result = (String)object;
  313. }
  314. }
  315. }
  316. }
  317. }
  318. }
  319. return result;
  320. }
  321. /**
  322. * Gets the default boolean value for the specified name.
  323. * @param name the name.
  324. * @return the default boolean value, false is returned if it cannot be
  325. * found.
  326. */
  327. public boolean getDefaultBooleanValue(String name) {
  328. String val = null;
  329. if (stanzaTable == null) {
  330. val = null;
  331. } else {
  332. val = getDefault(name, stanzaTable);
  333. }
  334. if (val != null && val.equalsIgnoreCase("true")) {
  335. return true;
  336. } else {
  337. return false;
  338. }
  339. }
  340. /**
  341. * Gets the default boolean value for the specified name in the
  342. * specified section.
  343. * <br>This method is quicker by using the section name as the search key.
  344. * @param name the name.
  345. * @param section the name of the section.
  346. * @return the default boolean value, false is returned if it cannot be
  347. * found.
  348. */
  349. public boolean getDefaultBooleanValue(String name, String section) {
  350. String val = getDefault(name, section);
  351. if (val != null && val.equalsIgnoreCase("true")) {
  352. return true;
  353. } else {
  354. return false;
  355. }
  356. }
  357. /**
  358. * Parses a string to an integer. The convertible strings include the
  359. * string representations of positive integers, negative integers, and
  360. * hex decimal integers. Valid inputs are, e.g., -1234, +1234,
  361. * 0x40000.
  362. *
  363. * @param input the String to be converted to an Integer.
  364. * @return an numeric value represented by the string
  365. * @exception NumberFormationException if the String does not contain a
  366. * parsable integer.
  367. */
  368. private int parseIntValue(String input) throws NumberFormatException {
  369. int value = 0;
  370. if (input.startsWith("+")) {
  371. String temp = input.substring(1);
  372. return Integer.parseInt(temp);
  373. } else if (input.startsWith("0x")) {
  374. String temp = input.substring(2);
  375. char[] chars = temp.toCharArray();
  376. if (chars.length > 8) {
  377. throw new NumberFormatException();
  378. } else {
  379. for (int i = 0; i < chars.length; i++) {
  380. int index = chars.length - i - 1;
  381. switch (chars[i]) {
  382. case '0':
  383. value += 0;
  384. break;
  385. case '1':
  386. value += 1 * getBase(index);
  387. break;
  388. case '2':
  389. value += 2 * getBase(index);
  390. break;
  391. case '3':
  392. value += 3 * getBase(index);
  393. break;
  394. case '4':
  395. value += 4 * getBase(index);
  396. break;
  397. case '5':
  398. value += 5 * getBase(index);
  399. break;
  400. case '6':
  401. value += 6 * getBase(index);
  402. break;
  403. case '7':
  404. value += 7 * getBase(index);
  405. break;
  406. case '8':
  407. value += 8 * getBase(index);
  408. break;
  409. case '9':
  410. value += 9 * getBase(index);
  411. break;
  412. case 'a':
  413. case 'A':
  414. value += 10 * getBase(index);
  415. break;
  416. case 'b':
  417. case 'B':
  418. value += 11 * getBase(index);
  419. break;
  420. case 'c':
  421. case 'C':
  422. value += 12 * getBase(index);
  423. break;
  424. case 'd':
  425. case 'D':
  426. value += 13 * getBase(index);
  427. break;
  428. case 'e':
  429. case 'E':
  430. value += 14 * getBase(index);
  431. break;
  432. case 'f':
  433. case 'F':
  434. value += 15 * getBase(index);
  435. break;
  436. default:
  437. throw new NumberFormatException("Invalid numerical format");
  438. }
  439. }
  440. }
  441. if (value < 0) {
  442. throw new NumberFormatException("Data overflow.");
  443. }
  444. } else {
  445. value = Integer.parseInt(input);
  446. }
  447. return value;
  448. }
  449. private int getBase(int i) {
  450. int result = 16;
  451. switch (i) {
  452. case 0:
  453. result = BASE16_0;
  454. break;
  455. case 1:
  456. result = BASE16_1;
  457. break;
  458. case 2:
  459. result = BASE16_2;
  460. break;
  461. case 3:
  462. result = BASE16_3;
  463. break;
  464. default:
  465. for (int j = 1; j < i; j++) {
  466. result *= 16;
  467. }
  468. }
  469. return result;
  470. }
  471. /**
  472. * Finds the matching value in the hashtable.
  473. */
  474. private String find(String key1, String key2) {
  475. String result;
  476. if ((stanzaTable != null) &&
  477. ((result = (String)
  478. (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) {
  479. return result;
  480. } else {
  481. return "";
  482. }
  483. }
  484. /**
  485. * Reads name/value pairs to the memory from the configuration
  486. * file. The default location of the configuration file is in java home
  487. * directory.
  488. *
  489. * Configuration file contains information about the default realm,
  490. * ticket parameters, location of the KDC and the admin server for
  491. * known realms, etc. The file is divided into sections. Each section
  492. * contains one or more name/value pairs with one pair per line. A
  493. * typical file would be:
  494. * [libdefaults]
  495. * default_realm = EXAMPLE.COM
  496. * default_tgs_enctypes = des-cbc-md5
  497. * default_tkt_enctypes = des-cbc-md5
  498. * [realms]
  499. * EXAMPLE.COM = {
  500. * kdc = kerberos.example.com
  501. * kdc = kerberos-1.example.com
  502. * admin_server = kerberos.example.com
  503. * }
  504. * SAMPLE_COM = {
  505. * kdc = orange.sample.com
  506. * admin_server = orange.sample.com
  507. * }
  508. * [domain_realm]
  509. * blue.sample.com = TEST.SAMPLE.COM
  510. * .backup.com = EXAMPLE.COM
  511. */
  512. private Vector<String> loadConfigFile() throws IOException {
  513. try {
  514. final String fileName = getFileName();
  515. if (!fileName.equals("")) {
  516. BufferedReader br = new BufferedReader(new InputStreamReader(
  517. java.security.AccessController.doPrivileged(
  518. new java.security.PrivilegedExceptionAction<FileInputStream> () {
  519. public FileInputStream run() throws IOException {
  520. return new FileInputStream(fileName);
  521. }
  522. })));
  523. String Line;
  524. Vector<String> v = new Vector<String> ();
  525. String previous = null;
  526. while ((Line = br.readLine()) != null) {
  527. // ignore comments and blank line in the configuration file.
  528. // Comments start with #.
  529. if (!(Line.startsWith("#") || Line.trim().isEmpty())) {
  530. String current = Line.trim();
  531. // In practice, a subsection might look like:
  532. // EXAMPLE.COM =
  533. // {
  534. // kdc = kerberos.example.com
  535. // ...
  536. // }
  537. // Before parsed into stanza table, it needs to be
  538. // converted into formal style:
  539. // EXAMPLE.COM = {
  540. // kdc = kerberos.example.com
  541. // ...
  542. // }
  543. //
  544. // So, if a line is "{", adhere to the previous line.
  545. if (current.equals("{")) {
  546. if (previous == null) {
  547. throw new IOException(
  548. "Config file should not start with \"{\"");
  549. }
  550. previous += " " + current;
  551. } else {
  552. if (previous != null) {
  553. v.addElement(previous);
  554. }
  555. previous = current;
  556. }
  557. }
  558. }
  559. if (previous != null) {
  560. v.addElement(previous);
  561. }
  562. br.close();
  563. return v;
  564. }
  565. return null;
  566. } catch (java.security.PrivilegedActionException pe) {
  567. throw (IOException)pe.getException();
  568. }
  569. }
  570. /**
  571. * Parses stanza names and values from configuration file to
  572. * stanzaTable (Hashtable). Hashtable key would be stanza names,
  573. * (libdefaults, realms, domain_realms, etc), and the hashtable value
  574. * would be another hashtable which contains the key-value pairs under
  575. * a stanza name.
  576. */
  577. private Hashtable<String,Object> parseStanzaTable(Vector<String> v) throws KrbException {
  578. if (v == null) {
  579. throw new KrbException("I/O error while reading" +
  580. " configuration file.");
  581. }
  582. Hashtable<String,Object> table = new Hashtable<String,Object> ();
  583. for (int i = 0; i < v.size(); i++) {
  584. String line = v.elementAt(i).trim();
  585. if (line.equalsIgnoreCase("[realms]")) {
  586. for (int count = i + 1; count < v.size() + 1; count++) {
  587. // find the next stanza name
  588. if ((count == v.size()) ||
  589. (v.elementAt(count).startsWith("["))) {
  590. Hashtable<String,Hashtable<String,Vector<String>>> temp =
  591. new Hashtable<String,Hashtable<String,Vector<String>>>();
  592. temp = parseRealmField(v, i + 1, count);
  593. table.put("realms", temp);
  594. i = count - 1;
  595. break;
  596. }
  597. }
  598. } else if (line.equalsIgnoreCase("[capaths]")) {
  599. for (int count = i + 1; count < v.size() + 1; count++) {
  600. // find the next stanza name
  601. if ((count == v.size()) ||
  602. (v.elementAt(count).startsWith("["))) {
  603. Hashtable<String,Hashtable<String,Vector<String>>> temp =
  604. new Hashtable<String,Hashtable<String,Vector<String>>>();
  605. temp = parseRealmField(v, i + 1, count);
  606. table.put("capaths", temp);
  607. i = count - 1;
  608. break;
  609. }
  610. }
  611. } else if (line.startsWith("[") && line.endsWith("]")) {
  612. String key = line.substring(1, line.length() - 1);
  613. for (int count = i + 1; count < v.size() + 1; count++) {
  614. // find the next stanza name
  615. if ((count == v.size()) ||
  616. (v.elementAt(count).startsWith("["))) {
  617. Hashtable<String,String> temp =
  618. parseField(v, i + 1, count);
  619. table.put(key, temp);
  620. i = count - 1;
  621. break;
  622. }
  623. }
  624. }
  625. }
  626. return table;
  627. }
  628. /**
  629. * Gets the default configuration file name. The file will be searched
  630. * in a list of possible loations in the following order:
  631. * 1. the location and file name defined by system property
  632. * "java.security.krb5.conf",
  633. * 2. at Java home lib\security directory with "krb5.conf" name,
  634. * 3. "krb5.ini" at Java home,
  635. * 4. at windows directory with the name of "krb5.ini" for Windows,
  636. * /etc/krb5/krb5.conf for Solaris, /etc/krb5.conf for Linux.
  637. */
  638. private String getFileName() {
  639. String name =
  640. java.security.AccessController.doPrivileged(
  641. new sun.security.action.
  642. GetPropertyAction("java.security.krb5.conf"));
  643. if (name != null) {
  644. boolean temp =
  645. java.security.AccessController.doPrivileged(
  646. new FileExistsAction(name));
  647. if (temp)
  648. return name;
  649. } else {
  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. boolean temp =
  656. java.security.AccessController.doPrivileged(
  657. new FileExistsAction(name));
  658. if (temp) {
  659. return name;
  660. } else {
  661. String osname =
  662. java.security.AccessController.doPrivileged(
  663. new sun.security.action.GetPropertyAction("os.name"));
  664. if (osname.startsWith("Windows")) {
  665. try {
  666. Credentials.ensureLoaded();
  667. } catch (Exception e) {
  668. // ignore exceptions
  669. }
  670. if (Credentials.alreadyLoaded) {
  671. if ((name = getWindowsDirectory()) == null) {
  672. name = "c:\\winnt\\krb5.ini";
  673. } else if (name.endsWith("\\")) {
  674. name += "krb5.ini";
  675. } else {
  676. name += "\\krb5.ini";
  677. }
  678. } else {
  679. name = "c:\\winnt\\krb5.ini";
  680. }
  681. } else if (osname.startsWith("SunOS")) {
  682. name = "/etc/krb5/krb5.conf";
  683. } else if (osname.startsWith("Linux")) {
  684. name = "/etc/krb5.conf";
  685. }
  686. }
  687. }
  688. if (DEBUG) {
  689. System.out.println("Config name: " + name);
  690. }
  691. return name;
  692. }
  693. /**
  694. * Parses key-value pairs under a stanza name.
  695. */
  696. private Hashtable<String,String> parseField(Vector<String> v, int start, int end) {
  697. Hashtable<String,String> table = new Hashtable<String,String> ();
  698. String line;
  699. for (int i = start; i < end; i++) {
  700. line = v.elementAt(i);
  701. for (int j = 0; j < line.length(); j++) {
  702. if (line.charAt(j) == '=') {
  703. String key = (line.substring(0, j)).trim();
  704. String value = (line.substring(j + 1)).trim();
  705. table.put(key, value);
  706. break;
  707. }
  708. }
  709. }
  710. return table;
  711. }
  712. /**
  713. * Parses key-value pairs under [realms]. The key would be the realm
  714. * name, the value would be another hashtable which contains
  715. * information for the realm given within a pair of braces.
  716. */
  717. private Hashtable<String,Hashtable<String,Vector<String>>> parseRealmField(Vector<String> v, int start, int end) {
  718. Hashtable<String,Hashtable<String,Vector<String>>> table = new Hashtable<String,Hashtable<String,Vector<String>>> ();
  719. String line;
  720. for (int i = start; i < end; i++) {
  721. line = v.elementAt(i).trim();
  722. if (line.endsWith("{")) {
  723. String key = "";
  724. for (int j = 0; j < line.length(); j++) {
  725. if (line.charAt(j) == '=') {
  726. key = line.substring(0, j).trim();
  727. // get the key
  728. break;
  729. }
  730. }
  731. for (int k = i + 1; k < end; k++) {
  732. boolean found = false;
  733. line = v.elementAt(k).trim();
  734. for (int l = 0; l < line.length(); l++) {
  735. if (line.charAt(l) == '}') {
  736. found = true;
  737. break;
  738. }
  739. }
  740. if (found == true) {
  741. Hashtable<String,Vector<String>> temp = parseRealmFieldEx(v, i + 1, k);
  742. table.put(key, temp);
  743. i = k;
  744. found = false;
  745. break;
  746. }
  747. }
  748. }
  749. }
  750. return table;
  751. }
  752. /**
  753. * Parses key-value pairs within each braces under [realms].
  754. */
  755. private Hashtable<String,Vector<String>> parseRealmFieldEx(Vector<String> v, int start, int end) {
  756. Hashtable<String,Vector<String>> table =
  757. new Hashtable<String,Vector<String>> ();
  758. Vector<String> keyVector = new Vector<String> ();
  759. Vector<String> nameVector = new Vector<String> ();
  760. String line = "";
  761. String key;
  762. for (int i = start; i < end; i++) {
  763. line = v.elementAt(i);
  764. for (int j = 0; j < line.length(); j++) {
  765. if (line.charAt(j) == '=') {
  766. int index;
  767. key = line.substring(0, j - 1).trim();
  768. if (! exists(key, keyVector)) {
  769. keyVector.addElement(key);
  770. nameVector = new Vector<String> ();
  771. } else {
  772. nameVector = table.get(key);
  773. }
  774. nameVector.addElement((line.substring(j + 1)).trim());
  775. table.put(key, nameVector);
  776. break;
  777. }
  778. }
  779. }
  780. return table;
  781. }
  782. /**
  783. * Compares the key with the known keys to see if it exists.
  784. */
  785. private boolean exists(String key, Vector v) {
  786. boolean exists = false;
  787. for (int i = 0; i < v.size(); i++) {
  788. if (((String)(v.elementAt(i))).equals(key)) {
  789. exists = true;
  790. }
  791. }
  792. return exists;
  793. }
  794. /**
  795. * For testing purpose. This method lists all information being parsed from
  796. * the configuration file to the hashtable.
  797. */
  798. public void listTable() {
  799. listTable(stanzaTable);
  800. }
  801. private void listTable(Hashtable table) {
  802. Vector v = new Vector();
  803. String key;
  804. if (stanzaTable != null) {
  805. for (Enumeration e = table.keys(); e.hasMoreElements(); ) {
  806. key = (String)e.nextElement();
  807. Object object = table.get(key);
  808. if (table == stanzaTable) {
  809. System.out.println("[" + key + "]");
  810. }
  811. if (object instanceof Hashtable) {
  812. if (table != stanzaTable)
  813. System.out.println("\t" + key + " = {");
  814. listTable((Hashtable)object);
  815. if (table != stanzaTable)
  816. System.out.println("\t}");
  817. } else if (object instanceof String) {
  818. System.out.println("\t" + key + " = " +
  819. (String)table.get(key));
  820. } else if (object instanceof Vector) {
  821. v = (Vector)object;
  822. for (int i = 0; i < v.size(); i++) {
  823. System.out.println("\t" + key + " = " +
  824. (String)v.elementAt(i));
  825. }
  826. }
  827. }
  828. } else {
  829. System.out.println("Configuration file not found.");
  830. }
  831. }
  832. /**
  833. * Returns the default encryption types.
  834. *
  835. */
  836. public int[] defaultEtype(String enctypes) {
  837. String default_enctypes;
  838. default_enctypes = getDefault(enctypes, "libdefaults");
  839. String delim = " ";
  840. StringTokenizer st;
  841. int[] etype;
  842. if (default_enctypes == null) {
  843. if (DEBUG) {
  844. System.out.println("Using builtin default etypes for " +
  845. enctypes);
  846. }
  847. etype = EType.getBuiltInDefaults();
  848. } else {
  849. for (int j = 0; j < default_enctypes.length(); j++) {
  850. if (default_enctypes.substring(j, j + 1).equals(",")) {
  851. // only two delimiters are allowed to use
  852. // according to Kerberos DCE doc.
  853. delim = ",";
  854. break;
  855. }
  856. }
  857. st = new StringTokenizer(default_enctypes, delim);
  858. int len = st.countTokens();
  859. ArrayList<Integer> ls = new ArrayList<Integer> (len);
  860. int type;
  861. for (int i = 0; i < len; i++) {
  862. type = getType(st.nextToken());
  863. if ((type != -1) &&
  864. (EType.isSupported(type))) {
  865. ls.add(type);
  866. }
  867. }
  868. if (ls.size() == 0) {
  869. if (DEBUG) {
  870. System.out.println(
  871. "no supported default etypes for " + enctypes);
  872. }
  873. return null;
  874. } else {
  875. etype = new int[ls.size()];
  876. for (int i = 0; i < etype.length; i++) {
  877. etype[i] = ls.get(i);
  878. }
  879. }
  880. }
  881. if (DEBUG) {
  882. System.out.print("default etypes for " + enctypes + ":");
  883. for (int i = 0; i < etype.length; i++) {
  884. System.out.print(" " + etype[i]);
  885. }
  886. System.out.println(".");
  887. }
  888. return etype;
  889. }
  890. /**
  891. * Get the etype and checksum value for the specified encryption and
  892. * checksum type.
  893. *
  894. */
  895. /*
  896. * This method converts the string representation of encryption type and
  897. * checksum type to int value that can be later used by EType and
  898. * Checksum classes.
  899. */
  900. public int getType(String input) {
  901. int result = -1;
  902. if (input == null) {
  903. return result;
  904. }
  905. if (input.startsWith("d") || (input.startsWith("D"))) {
  906. if (input.equalsIgnoreCase("des-cbc-crc")) {
  907. result = EncryptedData.ETYPE_DES_CBC_CRC;
  908. } else if (input.equalsIgnoreCase("des-cbc-md5")) {
  909. result = EncryptedData.ETYPE_DES_CBC_MD5;
  910. } else if (input.equalsIgnoreCase("des-mac")) {
  911. result = Checksum.CKSUMTYPE_DES_MAC;
  912. } else if (input.equalsIgnoreCase("des-mac-k")) {
  913. result = Checksum.CKSUMTYPE_DES_MAC_K;
  914. } else if (input.equalsIgnoreCase("des-cbc-md4")) {
  915. result = EncryptedData.ETYPE_DES_CBC_MD4;
  916. } else if (input.equalsIgnoreCase("des3-cbc-sha1") ||
  917. input.equalsIgnoreCase("des3-hmac-sha1") ||
  918. input.equalsIgnoreCase("des3-cbc-sha1-kd") ||
  919. input.equalsIgnoreCase("des3-cbc-hmac-sha1-kd")) {
  920. result = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
  921. }
  922. } else if (input.startsWith("a") || (input.startsWith("A"))) {
  923. // AES
  924. if (input.equalsIgnoreCase("aes128-cts") ||
  925. input.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
  926. result = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
  927. } else if (input.equalsIgnoreCase("aes256-cts") ||
  928. input.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
  929. result = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
  930. // ARCFOUR-HMAC
  931. } else if (input.equalsIgnoreCase("arcfour-hmac") ||
  932. input.equalsIgnoreCase("arcfour-hmac-md5")) {
  933. result = EncryptedData.ETYPE_ARCFOUR_HMAC;
  934. }
  935. // RC4-HMAC
  936. } else if (input.equalsIgnoreCase("rc4-hmac")) {
  937. result = EncryptedData.ETYPE_ARCFOUR_HMAC;
  938. } else if (input.equalsIgnoreCase("CRC32")) {
  939. result = Checksum.CKSUMTYPE_CRC32;
  940. } else if (input.startsWith("r") || (input.startsWith("R"))) {
  941. if (input.equalsIgnoreCase("rsa-md5")) {
  942. result = Checksum.CKSUMTYPE_RSA_MD5;
  943. } else if (input.equalsIgnoreCase("rsa-md5-des")) {
  944. result = Checksum.CKSUMTYPE_RSA_MD5_DES;
  945. }
  946. } else if (input.equalsIgnoreCase("hmac-sha1-des3-kd")) {
  947. result = Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD;
  948. } else if (input.equalsIgnoreCase("hmac-sha1-96-aes128")) {
  949. result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
  950. } else if (input.equalsIgnoreCase("hmac-sha1-96-aes256")) {
  951. result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
  952. } else if (input.equalsIgnoreCase("hmac-md5-rc4") ||
  953. input.equalsIgnoreCase("hmac-md5-arcfour") ||
  954. input.equalsIgnoreCase("hmac-md5-enc")) {
  955. result = Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR;
  956. } else if (input.equalsIgnoreCase("NULL")) {
  957. result = EncryptedData.ETYPE_NULL;
  958. }
  959. return result;
  960. }
  961. /**
  962. * Resets the default kdc realm.
  963. * We do not need to synchronize these methods since assignments are atomic
  964. */
  965. public void resetDefaultRealm(String realm) {
  966. defaultRealm = realm;
  967. if (DEBUG) {
  968. System.out.println(">>> Config reset default kdc " + defaultRealm);
  969. }
  970. }
  971. /**
  972. * Check to use addresses in tickets
  973. * use addresses if "no_addresses" or "noaddresses" is set to false
  974. */
  975. public boolean useAddresses() {
  976. boolean useAddr = false;
  977. // use addresses if "no_addresses" is set to false
  978. String value = getDefault("no_addresses", "libdefaults");
  979. useAddr = (value != null && value.equalsIgnoreCase("false"));
  980. if (useAddr == false) {
  981. // use addresses if "noaddresses" is set to false
  982. value = getDefault("noaddresses", "libdefaults");
  983. useAddr = (value != null && value.equalsIgnoreCase("false"));
  984. }
  985. return useAddr;
  986. }
  987. /**
  988. * Gets default realm.
  989. */
  990. public String getDefaultRealm() {
  991. return getDefault("default_realm", "libdefaults");
  992. }
  993. /**
  994. * Returns a list of KDC's with each KDC separated by a space
  995. *
  996. * @param realm the realm for which the master KDC is desired
  997. * @return the list of KDCs
  998. */
  999. public String getKDCList(String realm) {
  1000. if (realm == null) {
  1001. realm = getDefaultRealm();
  1002. }
  1003. String kdcs = getDefault("kdc", realm);
  1004. if (kdcs == null) {
  1005. return null;
  1006. }
  1007. return kdcs;
  1008. }
  1009. static class FileExistsAction
  1010. implements java.security.PrivilegedAction<Boolean> {
  1011. private String fileName;
  1012. public FileExistsAction(String fileName) {
  1013. this.fileName = fileName;
  1014. }
  1015. public Boolean run() {
  1016. return new File(fileName).exists();
  1017. }
  1018. }
  1019. }