PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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