1314 lines · 47.9 KB · Java
RawDownload
/* * 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.