--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,353 @@
+/*
+ * Portions Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 sun.security.krb5.internal.Krb5;
+import sun.security.krb5.internal.UDPClient;
+import sun.security.krb5.internal.TCPClient;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.util.StringTokenizer;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+public abstract class KrbKdcReq {
+
+ /**
+ * Default port for a KDC.
+ */
+ private static final int DEFAULT_KDC_PORT = Krb5.KDC_INET_DEFAULT_PORT;
+
+ // Currently there is no option to specify retries
+ // in the kerberos configuration file
+
+ private static final int DEFAULT_KDC_RETRY_LIMIT = Krb5.KDC_RETRY_LIMIT;
+
+ /**
+ * Default timeout period when requesting a ticket from a KDC.
+ * If not specified in the configuration file,
+ * a value of 30 seconds is used.
+ */
+ public static final int DEFAULT_KDC_TIMEOUT; // milliseconds
+
+ private static final boolean DEBUG = Krb5.DEBUG;
+
+ private static int udpPrefLimit = -1;
+
+ static {
+
+ /*
+ * Get default timeout.
+ */
+
+ int timeout = -1;
+ try {
+ Config cfg = Config.getInstance();
+ String temp = cfg.getDefault("kdc_timeout", "libdefaults");
+ timeout = parsePositiveIntString(temp);
+ temp = cfg.getDefault("udp_preference_limit", "libdefaults");
+ udpPrefLimit = parsePositiveIntString(temp);
+ } catch (Exception exc) {
+ // ignore any exceptions; use the default time out values
+ if (DEBUG) {
+ System.out.println ("Exception in getting kdc_timeout value, " +
+ "using default value " +
+ exc.getMessage());
+ }
+ }
+
+ if (timeout > 0)
+ DEFAULT_KDC_TIMEOUT = timeout;
+ else
+ DEFAULT_KDC_TIMEOUT = 30*1000; // 30 seconds
+ }
+
+ protected byte[] obuf;
+ protected byte[] ibuf;
+
+ /**
+ * Sends the provided data to the KDC of the specified realm.
+ * Returns the response from the KDC.
+ * Default realm/KDC is used if realm is null.
+ * @param realm the realm of the KDC where data is to be sent.
+ * @returns the kdc to which the AS request was sent to
+ * @exception InterruptedIOException if timeout expires
+ * @exception KrbException
+ */
+
+ public String send(String realm)
+ throws IOException, KrbException {
+ boolean useTCP = (udpPrefLimit > 0 &&
+ (obuf != null && obuf.length > udpPrefLimit));
+
+ return (send(realm, useTCP));
+ }
+
+ public String send(String realm, boolean useTCP)
+ throws IOException, KrbException {
+
+ if (obuf == null)
+ return null;
+ Exception savedException = null;
+ Config cfg = Config.getInstance();
+
+ if (realm == null) {
+ realm = cfg.getDefaultRealm();
+ if (realm == null) {
+ throw new KrbException(Krb5.KRB_ERR_GENERIC,
+ "Cannot find default realm");
+ }
+ }
+
+ /*
+ * Get timeout.
+ */
+
+ int timeout = getKdcTimeout(realm);
+
+ String kdcList = cfg.getKDCList(realm);
+ if (kdcList == null) {
+ throw new KrbException("Cannot get kdc for realm " + realm);
+ }
+ String tempKdc = null; // may include the port number also
+ StringTokenizer st = new StringTokenizer(kdcList);
+ while (st.hasMoreTokens()) {
+ tempKdc = st.nextToken();
+ try {
+ send(realm,tempKdc,useTCP);
+ break;
+ } catch (Exception e) {
+ savedException = e;
+ }
+ }
+ if (ibuf == null && savedException != null) {
+ if (savedException instanceof IOException) {
+ throw (IOException) savedException;
+ } else {
+ throw (KrbException) savedException;
+ }
+ }
+ return tempKdc;
+ }
+
+ // send the AS Request to the specified KDC
+
+ public void send(String realm, String tempKdc, boolean useTCP)
+ throws IOException, KrbException {
+
+ if (obuf == null)
+ return;
+ PrivilegedActionException savedException = null;
+ int port = Krb5.KDC_INET_DEFAULT_PORT;
+
+ /*
+ * Get timeout.
+ */
+ int timeout = getKdcTimeout(realm);
+ /*
+ * Get port number for this KDC.
+ */
+ StringTokenizer strTok = new StringTokenizer(tempKdc, ":");
+ String kdc = strTok.nextToken();
+ if (strTok.hasMoreTokens()) {
+ String portStr = strTok.nextToken();
+ int tempPort = parsePositiveIntString(portStr);
+ if (tempPort > 0)
+ port = tempPort;
+ }
+
+ if (DEBUG) {
+ System.out.println(">>> KrbKdcReq send: kdc=" + kdc
+ + (useTCP ? " TCP:":" UDP:")
+ + port + ", timeout="
+ + timeout
+ + ", number of retries ="
+ + DEFAULT_KDC_RETRY_LIMIT
+ + ", #bytes=" + obuf.length);
+ }
+
+ KdcCommunication kdcCommunication =
+ new KdcCommunication(kdc, port, useTCP, timeout, obuf);
+ try {
+ ibuf = AccessController.doPrivileged(kdcCommunication);
+ if (DEBUG) {
+ System.out.println(">>> KrbKdcReq send: #bytes read="
+ + (ibuf != null ? ibuf.length : 0));
+ }
+ } catch (PrivilegedActionException e) {
+ Exception wrappedException = e.getException();
+ if (wrappedException instanceof IOException) {
+ throw (IOException) wrappedException;
+ } else {
+ throw (KrbException) wrappedException;
+ }
+ }
+ if (DEBUG) {
+ System.out.println(">>> KrbKdcReq send: #bytes read="
+ + (ibuf != null ? ibuf.length : 0));
+ }
+ }
+
+ private static class KdcCommunication
+ implements PrivilegedExceptionAction<byte[]> {
+
+ private String kdc;
+ private int port;
+ private boolean useTCP;
+ private int timeout;
+ private byte[] obuf;
+
+ public KdcCommunication(String kdc, int port, boolean useTCP,
+ int timeout, byte[] obuf) {
+ this.kdc = kdc;
+ this.port = port;
+ this.useTCP = useTCP;
+ this.timeout = timeout;
+ this.obuf = obuf;
+ }
+
+ // The caller only casts IOException and KrbException so don't
+ // add any new ones!
+
+ public byte[] run() throws IOException, KrbException {
+
+ byte[] ibuf = null;
+
+ if (useTCP) {
+ TCPClient kdcClient = new TCPClient(kdc, port);
+ try {
+ /*
+ * Send the data to the kdc.
+ */
+ kdcClient.send(obuf);
+ /*
+ * And get a response.
+ */
+ ibuf = kdcClient.receive();
+ } finally {
+ kdcClient.close();
+ }
+
+ } else {
+ // For each KDC we try DEFAULT_KDC_RETRY_LIMIT (3) times to
+ // get the response
+ for (int i=1; i <= DEFAULT_KDC_RETRY_LIMIT; i++) {
+ UDPClient kdcClient = new UDPClient(kdc, port, timeout);
+
+ if (DEBUG) {
+ System.out.println(">>> KDCCommunication: kdc=" + kdc
+ + (useTCP ? " TCP:":" UDP:")
+ + port + ", timeout="
+ + timeout
+ + ",Attempt =" + i
+ + ", #bytes=" + obuf.length);
+ }
+ /*
+ * Send the data to the kdc.
+ */
+
+ kdcClient.send(obuf);
+
+ /*
+ * And get a response.
+ */
+ try {
+ ibuf = kdcClient.receive();
+ break;
+ } catch (SocketTimeoutException se) {
+ if (DEBUG) {
+ System.out.println ("SocketTimeOutException with " +
+ "attempt: " + i);
+ }
+ if (i == DEFAULT_KDC_RETRY_LIMIT) {
+ ibuf = null;
+ throw se;
+ }
+ }
+ }
+ }
+ return ibuf;
+ }
+ }
+
+ /**
+ * Returns a timeout value for the KDC of the given realm.
+ * A KDC-specific timeout, if specified in the config file,
+ * overrides the default timeout (which may also be specified
+ * in the config file). Default timeout is returned if null
+ * is specified for realm.
+ * @param realm the realm which kdc's timeout is requested
+ * @return KDC timeout
+ */
+ private int getKdcTimeout(String realm)
+ {
+ int timeout = DEFAULT_KDC_TIMEOUT;
+
+ if (realm == null)
+ return timeout;
+
+ int tempTimeout = -1;
+ try {
+ String temp =
+ Config.getInstance().getDefault("kdc_timeout", realm);
+ tempTimeout = parsePositiveIntString(temp);
+ } catch (Exception exc) {
+ }
+
+ if (tempTimeout > 0)
+ timeout = tempTimeout;
+
+ return timeout;
+ }
+
+ private static int parsePositiveIntString(String intString)
+ {
+ if (intString == null)
+ return -1;
+
+ int ret = -1;
+
+ try {
+ ret = Integer.parseInt(intString);
+ } catch (Exception exc) {
+ return -1;
+ }
+
+ if (ret >= 0)
+ return ret;
+
+ return -1;
+ }
+}