/*
* Copyright (c) 2000, 2010, 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.List;
import java.util.StringTokenizer;
import sun.security.krb5.internal.crypto.EType;
import sun.security.krb5.internal.ktab.KeyTab;
This class maintains key-value pairs of Kerberos configurable constants
from configuration file or from user specified system properties.
/**
* 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.
/**
* 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();
Gets an instance of Config class. One and only one instance (the
singleton) is returned.
Throws: - 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.
/**
* 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.
Throws: - 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.
/**
* 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();
KeyTab.refresh();
KdcComm.initStatic();
}
Private constructor - can not be instantiated externally.
/**
* 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 etc.
}
}
Gets the default int value for the specified name.
Params: - name – the name.
Returns: 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.
/**
* 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.
This method is quicker by using section name as the
search key.
Params: - name – the name.
- sectio – the name string of the section.
Returns: 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.
/**
* 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.
Params: - name – the name.
Returns: the default value, null is returned if it cannot be found.
/**
* 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.
Params: - k – the key string.
- t – stanzaTable or sub hashtable within it.
Returns: the value found in config file, returns null if no value
matched with the key is found.
/**
* 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<String, Object> t) {
String result = null;
String key;
if (stanzaTable != null) {
for (Enumeration<String> e = t.keys(); e.hasMoreElements(); ) {
key = e.nextElement();
Object ob = t.get(key);
if (ob instanceof Hashtable) {
@SuppressWarnings("unchecked") // Checked with an instanceof check
Hashtable<String, Object> table =
(Hashtable<String, Object>)ob;
result = getDefault(k, table);
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.
This method is quicker by using the section name as the search key.
Params: - name – the name.
- section – the name of the section.
Returns: the default value, null is returned if it cannot be found.
/**
* 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.
*/
// stanzaTable leads to a lot of unchecked casts since its value type is
// STANZATABLE = String | Hashtable<String, STANZATABLE>
@SuppressWarnings("unchecked")
public String getDefault(String name, String section) {
String stanzaName;
String result = null;
Hashtable<String, Object> subTable;
if (stanzaTable != null) {
for (Enumeration<String> e = stanzaTable.keys();
e.hasMoreElements(); ) {
stanzaName = e.nextElement();
subTable = (Hashtable<String, Object>)
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<String, Object> temp =
(Hashtable<String, Object>)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.
Params: - name – the name.
Returns: the default boolean value, false is returned if it cannot be
found.
/**
* 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.
This method is quicker by using the section name as the search key.
Params: - name – the name.
- section – the name of the section.
Returns: the default boolean value, false is returned if it cannot be
found.
/**
* 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.
Params: - input – the String to be converted to an Integer.
Throws: - NumberFormationException – if the String does not contain a
parsable integer.
Returns: an numeric value represented by the string
/**
* 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.
/**
* 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]
default_realm = EXAMPLE.COM
default_tgs_enctypes = des-cbc-md5
default_tkt_enctypes = des-cbc-md5
[realms]
EXAMPLE.COM = {
kdc = kerberos.example.com
kdc = kerberos-1.example.com
admin_server = kerberos.example.com
}
SAMPLE_COM = {
kdc = orange.sample.com
admin_server = orange.sample.com
}
[domain_realm]
blue.sample.com = TEST.SAMPLE.COM
.backup.com = EXAMPLE.COM
/**
* 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]
* default_realm = EXAMPLE.COM
* default_tgs_enctypes = des-cbc-md5
* default_tkt_enctypes = des-cbc-md5
* [realms]
* EXAMPLE.COM = {
* kdc = kerberos.example.com
* kdc = kerberos-1.example.com
* admin_server = kerberos.example.com
* }
* SAMPLE_COM = {
* kdc = orange.sample.com
* admin_server = orange.sample.com
* }
* [domain_realm]
* blue.sample.com = TEST.SAMPLE.COM
* .backup.com = EXAMPLE.COM
*/
private Vector<String> loadConfigFile() throws IOException {
try {
final String fileName = getFileName();
if (!fileName.equals("")) {
BufferedReader br = new BufferedReader(new InputStreamReader(
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<FileInputStream> () {
public FileInputStream run() throws IOException {
return new FileInputStream(fileName);
}
})));
String Line;
Vector<String> v = new Vector<String> ();
String previous = null;
while ((Line = br.readLine()) != null) {
// ignore comments and blank line in the configuration file.
// Comments start with #.
if (!(Line.startsWith("#") || Line.trim().isEmpty())) {
String current = Line.trim();
// In practice, a subsection might look like:
// EXAMPLE.COM =
// {
// kdc = kerberos.example.com
// ...
// }
// Before parsed into stanza table, it needs to be
// converted into formal style:
// EXAMPLE.COM = {
// kdc = kerberos.example.com
// ...
// }
//
// So, if a line is "{", adhere to the previous line.
if (current.equals("{")) {
if (previous == null) {
throw new IOException(
"Config file should not start with \"{\"");
}
previous += " " + current;
} else {
if (previous != null) {
v.addElement(previous);
}
previous = current;
}
}
}
if (previous != null) {
v.addElement(previous);
}
br.close();
return v;
}
return null;
} catch (java.security.PrivilegedActionException pe) {
throw (IOException)pe.getException();
}
}
Parses stanza names and values from configuration file to
stanzaTable (Hashtable). Hashtable key would be stanza names,
(libdefaults, realms, domain_realms, etc), and the hashtable value
would be another hashtable which contains the key-value pairs under
a stanza name.
/**
* Parses stanza names and values from configuration file to
* stanzaTable (Hashtable). Hashtable key would be stanza names,
* (libdefaults, realms, domain_realms, etc), and the hashtable value
* would be another hashtable which contains the key-value pairs under
* a stanza name.
*/
private Hashtable<String,Object> parseStanzaTable(Vector<String> v) throws KrbException {
if (v == null) {
throw new KrbException("I/O error while reading" +
" configuration file.");
}
Hashtable<String,Object> table = new Hashtable<String,Object> ();
for (int i = 0; i < v.size(); i++) {
String line = v.elementAt(i).trim();
if (line.equalsIgnoreCase("[realms]")) {
for (int count = i + 1; count < v.size() + 1; count++) {
// find the next stanza name
if ((count == v.size()) ||
(v.elementAt(count).startsWith("["))) {
Hashtable<String,Hashtable<String,Vector<String>>> temp =
new Hashtable<String,Hashtable<String,Vector<String>>>();
temp = parseRealmField(v, i + 1, count);
table.put("realms", temp);
i = count - 1;
break;
}
}
} else if (line.equalsIgnoreCase("[capaths]")) {
for (int count = i + 1; count < v.size() + 1; count++) {
// find the next stanza name
if ((count == v.size()) ||
(v.elementAt(count).startsWith("["))) {
Hashtable<String,Hashtable<String,Vector<String>>> temp =
new Hashtable<String,Hashtable<String,Vector<String>>>();
temp = parseRealmField(v, i + 1, count);
table.put("capaths", temp);
i = count - 1;
break;
}
}
} else if (line.startsWith("[") && line.endsWith("]")) {
String key = line.substring(1, line.length() - 1);
for (int count = i + 1; count < v.size() + 1; count++) {
// find the next stanza name
if ((count == v.size()) ||
(v.elementAt(count).startsWith("["))) {
Hashtable<String,String> temp =
parseField(v, i + 1, count);
table.put(key, temp);
i = count - 1;
break;
}
}
}
}
return table;
}
Gets the default configuration file name. The file will be searched
in a list of possible loations in the following order:
1. the location and file name defined by system property
"java.security.krb5.conf",
2. at Java home lib\security directory with "krb5.conf" name,
3. "krb5.ini" at Java home,
4. at windows directory with the name of "krb5.ini" for Windows,
/etc/krb5/krb5.conf for Solaris, /etc/krb5.conf for Linux.
/**
* Gets the default configuration file name. The file will be searched
* in a list of possible loations in the following order:
* 1. the location and file name defined by system property
* "java.security.krb5.conf",
* 2. at Java home lib\security directory with "krb5.conf" name,
* 3. "krb5.ini" at Java home,
* 4. at windows directory with the name of "krb5.ini" for Windows,
* /etc/krb5/krb5.conf for Solaris, /etc/krb5.conf for Linux.
*/
private String getFileName() {
String name =
java.security.AccessController.doPrivileged(
new sun.security.action.
GetPropertyAction("java.security.krb5.conf"));
if (name != null) {
boolean temp =
java.security.AccessController.doPrivileged(
new FileExistsAction(name));
if (temp)
return name;
} else {
name = java.security.AccessController.doPrivileged(
new sun.security.action.
GetPropertyAction("java.home")) + File.separator +
"lib" + File.separator + "security" +
File.separator + "krb5.conf";
boolean temp =
java.security.AccessController.doPrivileged(
new FileExistsAction(name));
if (temp) {
return name;
} else {
String osname =
java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("os.name"));
if (osname.startsWith("Windows")) {
try {
Credentials.ensureLoaded();
} catch (Exception e) {
// ignore exceptions
}
if (Credentials.alreadyLoaded) {
if ((name = getWindowsDirectory()) == null) {
name = "c:\\winnt\\krb5.ini";
} else if (name.endsWith("\\")) {
name += "krb5.ini";
} else {
name += "\\krb5.ini";
}
} else {
name = "c:\\winnt\\krb5.ini";
}
} else if (osname.startsWith("SunOS")) {
name = "/etc/krb5/krb5.conf";
} else if (osname.startsWith("Linux")) {
name = "/etc/krb5.conf";
}
}
}
if (DEBUG) {
System.out.println("Config name: " + name);
}
return name;
}
Parses key-value pairs under a stanza name.
/**
* Parses key-value pairs under a stanza name.
*/
private Hashtable<String,String> parseField(Vector<String> v, int start, int end) {
Hashtable<String,String> table = new Hashtable<String,String> ();
String line;
for (int i = start; i < end; i++) {
line = v.elementAt(i);
for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == '=') {
String key = (line.substring(0, j)).trim();
String value = (line.substring(j + 1)).trim();
table.put(key, value);
break;
}
}
}
return table;
}
Parses key-value pairs under [realms]. The key would be the realm
name, the value would be another hashtable which contains
information for the realm given within a pair of braces.
/**
* Parses key-value pairs under [realms]. The key would be the realm
* name, the value would be another hashtable which contains
* information for the realm given within a pair of braces.
*/
private Hashtable<String,Hashtable<String,Vector<String>>> parseRealmField(Vector<String> v, int start, int end) {
Hashtable<String,Hashtable<String,Vector<String>>> table = new Hashtable<String,Hashtable<String,Vector<String>>> ();
String line;
for (int i = start; i < end; i++) {
line = v.elementAt(i).trim();
if (line.endsWith("{")) {
String key = "";
for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == '=') {
key = line.substring(0, j).trim();
// get the key
break;
}
}
for (int k = i + 1; k < end; k++) {
boolean found = false;
line = v.elementAt(k).trim();
for (int l = 0; l < line.length(); l++) {
if (line.charAt(l) == '}') {
found = true;
break;
}
}
if (found == true) {
Hashtable<String,Vector<String>> temp = parseRealmFieldEx(v, i + 1, k);
table.put(key, temp);
i = k;
found = false;
break;
}
}
}
}
return table;
}
Parses key-value pairs within each braces under [realms].
/**
* Parses key-value pairs within each braces under [realms].
*/
private Hashtable<String,Vector<String>> parseRealmFieldEx(Vector<String> v, int start, int end) {
Hashtable<String,Vector<String>> table =
new Hashtable<String,Vector<String>> ();
Vector<String> keyVector = new Vector<String> ();
Vector<String> nameVector = new Vector<String> ();
String line = "";
String key;
for (int i = start; i < end; i++) {
line = v.elementAt(i);
for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == '=') {
int index;
key = line.substring(0, j - 1).trim();
if (! exists(key, keyVector)) {
keyVector.addElement(key);
nameVector = new Vector<String> ();
} else {
nameVector = table.get(key);
}
nameVector.addElement((line.substring(j + 1)).trim());
table.put(key, nameVector);
break;
}
}
}
return table;
}
Compares the key with the known keys to see if it exists.
/**
* Compares the key with the known keys to see if it exists.
*/
private boolean exists(String key, Vector<String> v) {
boolean exists = false;
for (int i = 0; i < v.size(); i++) {
if (v.elementAt(i).equals(key)) {
exists = true;
}
}
return exists;
}
For testing purpose. This method lists all information being parsed from
the configuration file to the hashtable.
/**
* For testing purpose. This method lists all information being parsed from
* the configuration file to the hashtable.
*/
public void listTable() {
listTable(stanzaTable);
}
// stanzaTable leads to a lot of unchecked casts since its value type is
// STANZATABLE = String | Hashtable<String, STANZATABLE>
@SuppressWarnings("unchecked")
private void listTable(Hashtable<String, Object> table) {
Vector<String> v = new Vector<String>();
String key;
if (stanzaTable != null) {
for (Enumeration<String> e = table.keys(); e.hasMoreElements(); ) {
key = e.nextElement();
Object object = table.get(key);
if (table == stanzaTable) {
System.out.println("[" + key + "]");
}
if (object instanceof Hashtable) {
if (table != stanzaTable)
System.out.println("\t" + key + " = {");
listTable((Hashtable<String, Object>)object);
if (table != stanzaTable)
System.out.println("\t}");
} else if (object instanceof String) {
System.out.println("\t" + key + " = " +
(String)table.get(key));
} else if (object instanceof Vector) {
v = (Vector<String>)object;
for (int i = 0; i < v.size(); i++) {
System.out.println("\t" + key + " = " + v.elementAt(i));
}
}
}
} else {
System.out.println("Configuration file not found.");
}
}
Returns the default encryption types.
/**
* Returns the default encryption types.
*
*/
public int[] defaultEtype(String enctypes) {
String default_enctypes;
default_enctypes = getDefault(enctypes, "libdefaults");
String delim = " ";
StringTokenizer st;
int[] etype;
if (default_enctypes == null) {
if (DEBUG) {
System.out.println("Using builtin default etypes for " +
enctypes);
}
etype = EType.getBuiltInDefaults();
} else {
for (int j = 0; j < default_enctypes.length(); j++) {
if (default_enctypes.substring(j, j + 1).equals(",")) {
// only two delimiters are allowed to use
// according to Kerberos DCE doc.
delim = ",";
break;
}
}
st = new StringTokenizer(default_enctypes, delim);
int len = st.countTokens();
ArrayList<Integer> ls = new ArrayList<Integer> (len);
int type;
for (int i = 0; i < len; i++) {
type = getType(st.nextToken());
if ((type != -1) &&
(EType.isSupported(type))) {
ls.add(type);
}
}
if (ls.isEmpty()) {
if (DEBUG) {
System.out.println(
"no supported default etypes for " + enctypes);
}
return null;
} else {
etype = new int[ls.size()];
for (int i = 0; i < etype.length; i++) {
etype[i] = ls.get(i);
}
}
}
if (DEBUG) {
System.out.print("default etypes for " + enctypes + ":");
for (int i = 0; i < etype.length; i++) {
System.out.print(" " + etype[i]);
}
System.out.println(".");
}
return etype;
}
Get the etype and checksum value for the specified encryption and
checksum type.
/**
* Get the etype and checksum value for the specified encryption and
* checksum type.
*
*/
/*
* This method converts the string representation of encryption type and
* checksum type to int value that can be later used by EType and
* Checksum classes.
*/
public int getType(String input) {
int result = -1;
if (input == null) {
return result;
}
if (input.startsWith("d") || (input.startsWith("D"))) {
if (input.equalsIgnoreCase("des-cbc-crc")) {
result = EncryptedData.ETYPE_DES_CBC_CRC;
} else if (input.equalsIgnoreCase("des-cbc-md5")) {
result = EncryptedData.ETYPE_DES_CBC_MD5;
} else if (input.equalsIgnoreCase("des-mac")) {
result = Checksum.CKSUMTYPE_DES_MAC;
} else if (input.equalsIgnoreCase("des-mac-k")) {
result = Checksum.CKSUMTYPE_DES_MAC_K;
} else if (input.equalsIgnoreCase("des-cbc-md4")) {
result = EncryptedData.ETYPE_DES_CBC_MD4;
} else if (input.equalsIgnoreCase("des3-cbc-sha1") ||
input.equalsIgnoreCase("des3-hmac-sha1") ||
input.equalsIgnoreCase("des3-cbc-sha1-kd") ||
input.equalsIgnoreCase("des3-cbc-hmac-sha1-kd")) {
result = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD;
}
} else if (input.startsWith("a") || (input.startsWith("A"))) {
// AES
if (input.equalsIgnoreCase("aes128-cts") ||
input.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) {
result = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96;
} else if (input.equalsIgnoreCase("aes256-cts") ||
input.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) {
result = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96;
// ARCFOUR-HMAC
} else if (input.equalsIgnoreCase("arcfour-hmac") ||
input.equalsIgnoreCase("arcfour-hmac-md5")) {
result = EncryptedData.ETYPE_ARCFOUR_HMAC;
}
// RC4-HMAC
} else if (input.equalsIgnoreCase("rc4-hmac")) {
result = EncryptedData.ETYPE_ARCFOUR_HMAC;
} else if (input.equalsIgnoreCase("CRC32")) {
result = Checksum.CKSUMTYPE_CRC32;
} else if (input.startsWith("r") || (input.startsWith("R"))) {
if (input.equalsIgnoreCase("rsa-md5")) {
result = Checksum.CKSUMTYPE_RSA_MD5;
} else if (input.equalsIgnoreCase("rsa-md5-des")) {
result = Checksum.CKSUMTYPE_RSA_MD5_DES;
}
} else if (input.equalsIgnoreCase("hmac-sha1-des3-kd")) {
result = Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD;
} else if (input.equalsIgnoreCase("hmac-sha1-96-aes128")) {
result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128;
} else if (input.equalsIgnoreCase("hmac-sha1-96-aes256")) {
result = Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256;
} else if (input.equalsIgnoreCase("hmac-md5-rc4") ||
input.equalsIgnoreCase("hmac-md5-arcfour") ||
input.equalsIgnoreCase("hmac-md5-enc")) {
result = Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR;
} else if (input.equalsIgnoreCase("NULL")) {
result = EncryptedData.ETYPE_NULL;
}
return result;
}
Resets the default kdc realm.
We do not need to synchronize these methods since assignments are atomic
This method was useless. Kept here in case some class still calls it.
/**
* Resets the default kdc realm.
* We do not need to synchronize these methods since assignments are atomic
*
* This method was useless. Kept here in case some class still calls it.
*/
public void resetDefaultRealm(String realm) {
if (DEBUG) {
System.out.println(">>> Config try resetting default kdc " + realm);
}
}
Check to use addresses in tickets
use addresses if "no_addresses" or "noaddresses" is set to false
/**
* Check to use addresses in tickets
* use addresses if "no_addresses" or "noaddresses" is set to false
*/
public boolean useAddresses() {
boolean useAddr = false;
// use addresses if "no_addresses" is set to false
String value = getDefault("no_addresses", "libdefaults");
useAddr = (value != null && value.equalsIgnoreCase("false"));
if (useAddr == false) {
// use addresses if "noaddresses" is set to false
value = getDefault("noaddresses", "libdefaults");
useAddr = (value != null && value.equalsIgnoreCase("false"));
}
return useAddr;
}
Gets default realm.
Throws: - KrbException – where no realm can be located
Returns: the default realm, always non null
/**
* Gets default realm.
* @throws KrbException where no realm can be located
* @return the default realm, always non null
*/
public String getDefaultRealm() throws KrbException {
if (defaultRealm != null) {
return defaultRealm;
}
Exception cause = null;
String realm = getDefault("default_realm", "libdefaults");
if (realm == null) {
realm = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<String>() {
public String run() {
String osname = System.getProperty("os.name");
if (osname.startsWith("Windows")) {
return System.getenv("USERDNSDOMAIN");
}
return null;
}
});
}
if (realm == null) {
KrbException ke = new KrbException("Cannot locate default realm");
if (cause != null) {
ke.initCause(cause);
}
throw ke;
}
return realm;
}
Returns a list of KDC's with each KDC separated by a space
Params: - realm – the realm for which the KDC list is desired
Throws: - KrbException – if there's no way to find KDC for the realm
Returns: the list of KDCs separated by a space, always non null
/**
* Returns a list of KDC's with each KDC separated by a space
*
* @param realm the realm for which the KDC list is desired
* @throws KrbException if there's no way to find KDC for the realm
* @return the list of KDCs separated by a space, always non null
*/
public String getKDCList(String realm) throws KrbException {
if (realm == null) {
realm = getDefaultRealm();
}
if (realm.equalsIgnoreCase(defaultRealm)) {
return defaultKDC;
}
Exception cause = null;
String kdcs = getDefault("kdc", realm);
if (kdcs == null) {
kdcs = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<String>() {
public String run() {
String osname = System.getProperty("os.name");
if (osname.startsWith("Windows")) {
String logonServer = System.getenv("LOGONSERVER");
if (logonServer != null
&& logonServer.startsWith("\\\\")) {
logonServer = logonServer.substring(2);
}
return logonServer;
}
return null;
}
});
}
if (kdcs == null) {
if (defaultKDC != null) {
return defaultKDC;
}
KrbException ke = new KrbException("Cannot locate KDC");
if (cause != null) {
ke.initCause(cause);
}
throw ke;
}
return kdcs;
}
static class FileExistsAction
implements java.security.PrivilegedAction<Boolean> {
private String fileName;
public FileExistsAction(String fileName) {
this.fileName = fileName;
}
public Boolean run() {
return new File(fileName).exists();
}
}
}