PageRenderTime 79ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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