/* * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * * (C) Copyright IBM Corp. 1999 All Rights Reserved. * Copyright 1997 The Open Group Research Institute. All rights reserved. */package sun.security.krb5; import java.io.File;import java.io.FileInputStream;import java.util.Hashtable;import java.util.Vector;import java.util.ArrayList;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;import java.util.Enumeration;import java.util.StringTokenizer;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.List;import sun.net.dns.ResolverConfiguration;import sun.security.krb5.internal.crypto.EType;import sun.security.krb5.internal.ktab.*;import sun.security.krb5.internal.Krb5; /** * This class maintains key-value pairs of Kerberos configurable constants * from configuration file or from user specified system properties. */ public class Config { /* * Only allow a single instance of Config. */ private static Config singleton = null; /* * Hashtable used to store configuration infomation. */ private Hashtable<String,Object> stanzaTable; private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; // these are used for hexdecimal calculation. private static final int BASE16_0 = 1; private static final int BASE16_1 = 16; private static final int BASE16_2 = 16 * 16; private static final int BASE16_3 = 16 * 16 * 16; /** * Specified by system properties. Must be both null or non-null. */ private final String defaultRealm; private final String defaultKDC; // used for native interface private static native String getWindowsDirectory(boolean isSystem); /** * Gets an instance of Config class. One and only one instance (the * singleton) is returned. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or * java.security.krb5.kdc not specified, error reading configuration file. */ public static synchronized Config getInstance() throws KrbException { if (singleton == null) { singleton = new Config(); } return singleton; } /** * Refresh and reload the Configuration. This could involve, * for example reading the Configuration file again or getting * the java.security.krb5.* system properties again. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or * java.security.krb5.kdc not specified, error reading configuration file. */ public static synchronized void refresh() throws KrbException { singleton = new Config(); KdcComm.initStatic(); } /** * Private constructor - can not be instantiated externally. */ private Config() throws KrbException { /* * If either one system property is specified, we throw exception. */ String tmp = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction ("java.security.krb5.kdc")); if (tmp != null) { // The user can specify a list of kdc hosts separated by ":" defaultKDC = tmp.replace(':', ' '); } else { defaultKDC = null; } defaultRealm = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction ("java.security.krb5.realm")); if ((defaultKDC == null && defaultRealm != null) || (defaultRealm == null && defaultKDC != null)) { throw new KrbException ("System property java.security.krb5.kdc and " + "java.security.krb5.realm both must be set or " + "neither must be set."); } // Always read the Kerberos configuration file try { Vector<String> configFile; configFile = loadConfigFile(); stanzaTable = parseStanzaTable(configFile); } catch (IOException ioe) { // No krb5.conf, no problem. We'll use DNS or system property etc. } } /** * Gets the default int value for the specified name. * @param name the name. * @return the default Integer, null is returned if no such name and * value are found in configuration file, or error occurs when parsing * string to integer. */ public int getDefaultIntValue(String name) { String result = null; int value = Integer.MIN_VALUE; result = getDefault(name); if (result != null) { try { value = parseIntValue(result); } catch (NumberFormatException e) { if (DEBUG) { System.out.println("Exception in getting value of " + name + " " + e.getMessage()); System.out.println("Setting " + name + " to minimum value"); } value = Integer.MIN_VALUE; } } return value; } /** * Gets the default int value for the specified name in the specified * section. <br>This method is quicker by using section name as the * search key. * @param name the name. * @param sectio the name string of the section. * @return the default Integer, null is returned if no such name and * value are found in configuration file, or error occurs when parsing * string to integer. */ public int getDefaultIntValue(String name, String section) { String result = null; int value = Integer.MIN_VALUE; result = getDefault(name, section); if (result != null) { try { value = parseIntValue(result); } catch (NumberFormatException e) { if (DEBUG) { System.out.println("Exception in getting value of " + name +" in section " + section + " " + e.getMessage()); System.out.println("Setting " + name + " to minimum value"); } value = Integer.MIN_VALUE; } } return value; } /** * Gets the default string value for the specified name. * @param name the name. * @return the default value, null is returned if it cannot be found. */ public String getDefault(String name) { if (stanzaTable == null) { return null; } else { return getDefault(name, stanzaTable); } } /** * This method does the real job to recursively search through the * stanzaTable. * @param k the key string. * @param t stanzaTable or sub hashtable within it. * @return the value found in config file, returns null if no value * matched with the key is found. */ private String getDefault(String k, Hashtable t) { String result = null; String key; if (stanzaTable != null) { for (Enumeration e = t.keys(); e.hasMoreElements(); ) { key = (String)e.nextElement(); Object ob = t.get(key); if (ob instanceof Hashtable) { result = getDefault(k, (Hashtable)ob); if (result != null) { return result; } } else if (key.equalsIgnoreCase(k)) { if (ob instanceof String) { return (String)(t.get(key)); } else if (ob instanceof Vector) { result = ""; int length = ((Vector)ob).size(); for (int i = 0; i < length; i++) { if (i == length -1) { result += (String)(((Vector)ob).elementAt(i)); } else { result += (String)(((Vector)ob).elementAt(i)) + " "; } } return result; } } } } return result; } /** * Gets the default string value for the specified name in the * specified section. * <br>This method is quicker by using the section name as the search key. * @param name the name. * @param section the name of the section. * @return the default value, null is returned if it cannot be found. */ public String getDefault(String name, String section) { String stanzaName; String result = null; Hashtable subTable; if (stanzaTable != null) { for (Enumeration e = stanzaTable.keys(); e.hasMoreElements(); ) { stanzaName = (String)e.nextElement(); subTable = (Hashtable)stanzaTable.get(stanzaName); if (stanzaName.equalsIgnoreCase(section)) { if (subTable.containsKey(name)) { return (String)(subTable.get(name)); } } else if (subTable.containsKey(section)) { Object ob = subTable.get(section); if (ob instanceof Hashtable) { Hashtable temp = (Hashtable)ob; if (temp.containsKey(name)) { Object object = temp.get(name); if (object instanceof Vector) { result = ""; int length = ((Vector)object).size(); for (int i = 0; i < length; i++) { if (i == length - 1) { result += (String)(((Vector)object).elementAt(i)); } else { result += (String)(((Vector)object).elementAt(i)) + " "; } } } else { result = (String)object; } } } } } } return result; } /** * Gets the default boolean value for the specified name. * @param name the name. * @return the default boolean value, false is returned if it cannot be * found. */ public boolean getDefaultBooleanValue(String name) { String val = null; if (stanzaTable == null) { val = null; } else { val = getDefault(name, stanzaTable); } if (val != null && val.equalsIgnoreCase("true")) { return true; } else { return false; } } /** * Gets the default boolean value for the specified name in the * specified section. * <br>This method is quicker by using the section name as the search key. * @param name the name. * @param section the name of the section. * @return the default boolean value, false is returned if it cannot be * found. */ public boolean getDefaultBooleanValue(String name, String section) { String val = getDefault(name, section); if (val != null && val.equalsIgnoreCase("true")) { return true; } else { return false; } } /** * Parses a string to an integer. The convertible strings include the * string representations of positive integers, negative integers, and * hex decimal integers. Valid inputs are, e.g., -1234, +1234, * 0x40000. * * @param input the String to be converted to an Integer. * @return an numeric value represented by the string * @exception NumberFormationException if the String does not contain a * parsable integer. */ private int parseIntValue(String input) throws NumberFormatException { int value = 0; if (input.startsWith("+")) { String temp = input.substring(1); return Integer.parseInt(temp); } else if (input.startsWith("0x")) { String temp = input.substring(2); char[] chars = temp.toCharArray(); if (chars.length > 8) { throw new NumberFormatException(); } else { for (int i = 0; i < chars.length; i++) { int index = chars.length - i - 1; switch (chars[i]) { case '0': value += 0; break; case '1': value += 1 * getBase(index); break; case '2': value += 2 * getBase(index); break; case '3': value += 3 * getBase(index); break; case '4': value += 4 * getBase(index); break; case '5': value += 5 * getBase(index); break; case '6': value += 6 * getBase(index); break; case '7': value += 7 * getBase(index); break; case '8': value += 8 * getBase(index); break; case '9': value += 9 * getBase(index); break; case 'a': case 'A': value += 10 * getBase(index); break; case 'b': case 'B': value += 11 * getBase(index); break; case 'c': case 'C': value += 12 * getBase(index); break; case 'd': case 'D': value += 13 * getBase(index); break; case 'e': case 'E': value += 14 * getBase(index); break; case 'f': case 'F': value += 15 * getBase(index); break; default: throw new NumberFormatException("Invalid numerical format"); } } } if (value < 0) { throw new NumberFormatException("Data overflow."); } } else { value = Integer.parseInt(input); } return value; } private int getBase(int i) { int result = 16; switch (i) { case 0: result = BASE16_0; break; case 1: result = BASE16_1; break; case 2: result = BASE16_2; break; case 3: result = BASE16_3; break; default: for (int j = 1; j < i; j++) { result *= 16; } } return result; } /** * Finds the matching value in the hashtable. */ private String find(String key1, String key2) { String result; if ((stanzaTable != null) && ((result = (String) (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) { return result; } else { return ""; } } /** * Reads name/value pairs to the memory from the configuration * file. The default location of the configuration file is in java home * directory. * * Configuration file contains information about the default realm, * ticket parameters, location of the KDC and the admin server for * known realms, etc. The file is divided into sections. Each section * contains one or more name/value pairs with one pair per line. A * typical file would be: * [libdefaults]Lines 1–500 of 1314. Load more
/* * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * * (C) Copyright IBM Corp. 1999 All Rights Reserved. * Copyright 1997 The Open Group Research Institute. All rights reserved. */ package sun.security.krb5; import java.io.File; import java.io.FileInputStream; import java.util.Hashtable; import java.util.Vector; import java.util.ArrayList; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.Enumeration; import java.util.StringTokenizer; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import sun.net.dns.ResolverConfiguration; import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.ktab.*; import sun.security.krb5.internal.Krb5; /** * This class maintains key-value pairs of Kerberos configurable constants * from configuration file or from user specified system properties. */ public class Config { /* * Only allow a single instance of Config. */ private static Config singleton = null; /* * Hashtable used to store configuration infomation. */ private Hashtable<String,Object> stanzaTable; private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; // these are used for hexdecimal calculation. private static final int BASE16_0 = 1; private static final int BASE16_1 = 16; private static final int BASE16_2 = 16 * 16; private static final int BASE16_3 = 16 * 16 * 16; /** * Specified by system properties. Must be both null or non-null. */ private final String defaultRealm; private final String defaultKDC; // used for native interface private static native String getWindowsDirectory(boolean isSystem); /** * Gets an instance of Config class. One and only one instance (the * singleton) is returned. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or * java.security.krb5.kdc not specified, error reading configuration file. */ public static synchronized Config getInstance() throws KrbException { if (singleton == null) { singleton = new Config(); } return singleton; } /** * Refresh and reload the Configuration. This could involve, * for example reading the Configuration file again or getting * the java.security.krb5.* system properties again. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or * java.security.krb5.kdc not specified, error reading configuration file. */ public static synchronized void refresh() throws KrbException { singleton = new Config(); KdcComm.initStatic(); } /** * Private constructor - can not be instantiated externally. */ private Config() throws KrbException { /* * If either one system property is specified, we throw exception. */ String tmp = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction ("java.security.krb5.kdc")); if (tmp != null) { // The user can specify a list of kdc hosts separated by ":" defaultKDC = tmp.replace(':', ' '); } else { defaultKDC = null; } defaultRealm = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction ("java.security.krb5.realm")); if ((defaultKDC == null && defaultRealm != null) || (defaultRealm == null && defaultKDC != null)) { throw new KrbException ("System property java.security.krb5.kdc and " + "java.security.krb5.realm both must be set or " + "neither must be set."); } // Always read the Kerberos configuration file try { Vector<String> configFile; configFile = loadConfigFile(); stanzaTable = parseStanzaTable(configFile); } catch (IOException ioe) { // No krb5.conf, no problem. We'll use DNS or system property etc. } } /** * Gets the default int value for the specified name. * @param name the name. * @return the default Integer, null is returned if no such name and * value are found in configuration file, or error occurs when parsing * string to integer. */ public int getDefaultIntValue(String name) { String result = null; int value = Integer.MIN_VALUE; result = getDefault(name); if (result != null) { try { value = parseIntValue(result); } catch (NumberFormatException e) { if (DEBUG) { System.out.println("Exception in getting value of " + name + " " + e.getMessage()); System.out.println("Setting " + name + " to minimum value"); } value = Integer.MIN_VALUE; } } return value; } /** * Gets the default int value for the specified name in the specified * section. <br>This method is quicker by using section name as the * search key. * @param name the name. * @param sectio the name string of the section. * @return the default Integer, null is returned if no such name and * value are found in configuration file, or error occurs when parsing * string to integer. */ public int getDefaultIntValue(String name, String section) { String result = null; int value = Integer.MIN_VALUE; result = getDefault(name, section); if (result != null) { try { value = parseIntValue(result); } catch (NumberFormatException e) { if (DEBUG) { System.out.println("Exception in getting value of " + name +" in section " + section + " " + e.getMessage()); System.out.println("Setting " + name + " to minimum value"); } value = Integer.MIN_VALUE; } } return value; } /** * Gets the default string value for the specified name. * @param name the name. * @return the default value, null is returned if it cannot be found. */ public String getDefault(String name) { if (stanzaTable == null) { return null; } else { return getDefault(name, stanzaTable); } } /** * This method does the real job to recursively search through the * stanzaTable. * @param k the key string. * @param t stanzaTable or sub hashtable within it. * @return the value found in config file, returns null if no value * matched with the key is found. */ private String getDefault(String k, Hashtable t) { String result = null; String key; if (stanzaTable != null) { for (Enumeration e = t.keys(); e.hasMoreElements(); ) { key = (String)e.nextElement(); Object ob = t.get(key); if (ob instanceof Hashtable) { result = getDefault(k, (Hashtable)ob); if (result != null) { return result; } } else if (key.equalsIgnoreCase(k)) { if (ob instanceof String) { return (String)(t.get(key)); } else if (ob instanceof Vector) { result = ""; int length = ((Vector)ob).size(); for (int i = 0; i < length; i++) { if (i == length -1) { result += (String)(((Vector)ob).elementAt(i)); } else { result += (String)(((Vector)ob).elementAt(i)) + " "; } } return result; } } } } return result; } /** * Gets the default string value for the specified name in the * specified section. * <br>This method is quicker by using the section name as the search key. * @param name the name. * @param section the name of the section. * @return the default value, null is returned if it cannot be found. */ public String getDefault(String name, String section) { String stanzaName; String result = null; Hashtable subTable; if (stanzaTable != null) { for (Enumeration e = stanzaTable.keys(); e.hasMoreElements(); ) { stanzaName = (String)e.nextElement(); subTable = (Hashtable)stanzaTable.get(stanzaName); if (stanzaName.equalsIgnoreCase(section)) { if (subTable.containsKey(name)) { return (String)(subTable.get(name)); } } else if (subTable.containsKey(section)) { Object ob = subTable.get(section); if (ob instanceof Hashtable) { Hashtable temp = (Hashtable)ob; if (temp.containsKey(name)) { Object object = temp.get(name); if (object instanceof Vector) { result = ""; int length = ((Vector)object).size(); for (int i = 0; i < length; i++) { if (i == length - 1) { result += (String)(((Vector)object).elementAt(i)); } else { result += (String)(((Vector)object).elementAt(i)) + " "; } } } else { result = (String)object; } } } } } } return result; } /** * Gets the default boolean value for the specified name. * @param name the name. * @return the default boolean value, false is returned if it cannot be * found. */ public boolean getDefaultBooleanValue(String name) { String val = null; if (stanzaTable == null) { val = null; } else { val = getDefault(name, stanzaTable); } if (val != null && val.equalsIgnoreCase("true")) { return true; } else { return false; } } /** * Gets the default boolean value for the specified name in the * specified section. * <br>This method is quicker by using the section name as the search key. * @param name the name. * @param section the name of the section. * @return the default boolean value, false is returned if it cannot be * found. */ public boolean getDefaultBooleanValue(String name, String section) { String val = getDefault(name, section); if (val != null && val.equalsIgnoreCase("true")) { return true; } else { return false; } } /** * Parses a string to an integer. The convertible strings include the * string representations of positive integers, negative integers, and * hex decimal integers. Valid inputs are, e.g., -1234, +1234, * 0x40000. * * @param input the String to be converted to an Integer. * @return an numeric value represented by the string * @exception NumberFormationException if the String does not contain a * parsable integer. */ private int parseIntValue(String input) throws NumberFormatException { int value = 0; if (input.startsWith("+")) { String temp = input.substring(1); return Integer.parseInt(temp); } else if (input.startsWith("0x")) { String temp = input.substring(2); char[] chars = temp.toCharArray(); if (chars.length > 8) { throw new NumberFormatException(); } else { for (int i = 0; i < chars.length; i++) { int index = chars.length - i - 1; switch (chars[i]) { case '0': value += 0; break; case '1': value += 1 * getBase(index); break; case '2': value += 2 * getBase(index); break; case '3': value += 3 * getBase(index); break; case '4': value += 4 * getBase(index); break; case '5': value += 5 * getBase(index); break; case '6': value += 6 * getBase(index); break; case '7': value += 7 * getBase(index); break; case '8': value += 8 * getBase(index); break; case '9': value += 9 * getBase(index); break; case 'a': case 'A': value += 10 * getBase(index); break; case 'b': case 'B': value += 11 * getBase(index); break; case 'c': case 'C': value += 12 * getBase(index); break; case 'd': case 'D': value += 13 * getBase(index); break; case 'e': case 'E': value += 14 * getBase(index); break; case 'f': case 'F': value += 15 * getBase(index); break; default: throw new NumberFormatException("Invalid numerical format"); } } } if (value < 0) { throw new NumberFormatException("Data overflow."); } } else { value = Integer.parseInt(input); } return value; } private int getBase(int i) { int result = 16; switch (i) { case 0: result = BASE16_0; break; case 1: result = BASE16_1; break; case 2: result = BASE16_2; break; case 3: result = BASE16_3; break; default: for (int j = 1; j < i; j++) { result *= 16; } } return result; } /** * Finds the matching value in the hashtable. */ private String find(String key1, String key2) { String result; if ((stanzaTable != null) && ((result = (String) (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) { return result; } else { return ""; } } /** * Reads name/value pairs to the memory from the configuration * file. The default location of the configuration file is in java home * directory. * * Configuration file contains information about the default realm, * ticket parameters, location of the KDC and the admin server for * known realms, etc. The file is divided into sections. Each section * contains one or more name/value pairs with one pair per line. A * typical file would be: * [libdefaults]