mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2014, 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.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.util.Locale;
|
||||
import sun.security.krb5.internal.Krb5;
|
||||
import sun.security.krb5.internal.NetClient;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import sun.security.krb5.internal.KRBError;
|
||||
|
||||
/**
|
||||
* KDC-REQ/KDC-REP communication. No more base class for KrbAsReq and
|
||||
* KrbTgsReq. This class is now communication only.
|
||||
*/
|
||||
public final class KdcComm {
|
||||
|
||||
// The following settings can be configured in [libdefaults]
|
||||
// section of krb5.conf, which are global for all realms. Each of
|
||||
// them can also be defined in a realm, which overrides value here.
|
||||
|
||||
/**
|
||||
* max retry time for a single KDC, default Krb5.KDC_RETRY_LIMIT (3)
|
||||
*/
|
||||
private static int defaultKdcRetryLimit;
|
||||
/**
|
||||
* timeout requesting a ticket from KDC, in millisec, default 30 sec
|
||||
*/
|
||||
private static int defaultKdcTimeout;
|
||||
/**
|
||||
* max UDP packet size, default unlimited (-1)
|
||||
*/
|
||||
private static int defaultUdpPrefLimit;
|
||||
|
||||
private static final boolean DEBUG = Krb5.DEBUG;
|
||||
|
||||
private static final String BAD_POLICY_KEY = "krb5.kdc.bad.policy";
|
||||
|
||||
/**
|
||||
* What to do when a KDC is unavailable, specified in the
|
||||
* java.security file with key krb5.kdc.bad.policy.
|
||||
* Possible values can be TRY_LAST or TRY_LESS. Reloaded when refreshed.
|
||||
*/
|
||||
private enum BpType {
|
||||
NONE, TRY_LAST, TRY_LESS
|
||||
}
|
||||
private static int tryLessMaxRetries = 1;
|
||||
private static int tryLessTimeout = 5000;
|
||||
|
||||
private static BpType badPolicy;
|
||||
|
||||
static {
|
||||
initStatic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read global settings
|
||||
*/
|
||||
public static void initStatic() {
|
||||
String value = AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return Security.getProperty(BAD_POLICY_KEY);
|
||||
}
|
||||
});
|
||||
if (value != null) {
|
||||
value = value.toLowerCase(Locale.ENGLISH);
|
||||
String[] ss = value.split(":");
|
||||
if ("tryless".equals(ss[0])) {
|
||||
if (ss.length > 1) {
|
||||
String[] params = ss[1].split(",");
|
||||
try {
|
||||
int tmp0 = Integer.parseInt(params[0]);
|
||||
if (params.length > 1) {
|
||||
tryLessTimeout = Integer.parseInt(params[1]);
|
||||
}
|
||||
// Assign here in case of exception at params[1]
|
||||
tryLessMaxRetries = tmp0;
|
||||
} catch (NumberFormatException nfe) {
|
||||
// Ignored. Please note that tryLess is recognized and
|
||||
// used, parameters using default values
|
||||
if (DEBUG) {
|
||||
System.out.println("Invalid " + BAD_POLICY_KEY +
|
||||
" parameter for tryLess: " +
|
||||
value + ", use default");
|
||||
}
|
||||
}
|
||||
}
|
||||
badPolicy = BpType.TRY_LESS;
|
||||
} else if ("trylast".equals(ss[0])) {
|
||||
badPolicy = BpType.TRY_LAST;
|
||||
} else {
|
||||
badPolicy = BpType.NONE;
|
||||
}
|
||||
} else {
|
||||
badPolicy = BpType.NONE;
|
||||
}
|
||||
|
||||
|
||||
int timeout = -1;
|
||||
int max_retries = -1;
|
||||
int udp_pref_limit = -1;
|
||||
|
||||
try {
|
||||
Config cfg = Config.getInstance();
|
||||
String temp = cfg.get("libdefaults", "kdc_timeout");
|
||||
timeout = parseTimeString(temp);
|
||||
|
||||
temp = cfg.get("libdefaults", "max_retries");
|
||||
max_retries = parsePositiveIntString(temp);
|
||||
temp = cfg.get("libdefaults", "udp_preference_limit");
|
||||
udp_pref_limit = parsePositiveIntString(temp);
|
||||
} catch (Exception exc) {
|
||||
// ignore any exceptions; use default values
|
||||
if (DEBUG) {
|
||||
System.out.println ("Exception in getting KDC communication " +
|
||||
"settings, using default value " +
|
||||
exc.getMessage());
|
||||
}
|
||||
}
|
||||
defaultKdcTimeout = timeout > 0 ? timeout : 30*1000; // 30 seconds
|
||||
defaultKdcRetryLimit =
|
||||
max_retries > 0 ? max_retries : Krb5.KDC_RETRY_LIMIT;
|
||||
|
||||
if (udp_pref_limit < 0) {
|
||||
defaultUdpPrefLimit = Krb5.KDC_DEFAULT_UDP_PREF_LIMIT;
|
||||
} else if (udp_pref_limit > Krb5.KDC_HARD_UDP_LIMIT) {
|
||||
defaultUdpPrefLimit = Krb5.KDC_HARD_UDP_LIMIT;
|
||||
} else {
|
||||
defaultUdpPrefLimit = udp_pref_limit;
|
||||
}
|
||||
|
||||
KdcAccessibility.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* The instance fields
|
||||
*/
|
||||
private String realm;
|
||||
|
||||
public KdcComm(String realm) throws KrbException {
|
||||
if (realm == null) {
|
||||
realm = Config.getInstance().getDefaultRealm();
|
||||
if (realm == null) {
|
||||
throw new KrbException(Krb5.KRB_ERR_GENERIC,
|
||||
"Cannot find default realm");
|
||||
}
|
||||
}
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public byte[] send(byte[] obuf)
|
||||
throws IOException, KrbException {
|
||||
int udpPrefLimit = getRealmSpecificValue(
|
||||
realm, "udp_preference_limit", defaultUdpPrefLimit);
|
||||
|
||||
boolean useTCP = (udpPrefLimit > 0 &&
|
||||
(obuf != null && obuf.length > udpPrefLimit));
|
||||
|
||||
return send(obuf, useTCP);
|
||||
}
|
||||
|
||||
private byte[] send(byte[] obuf, boolean useTCP)
|
||||
throws IOException, KrbException {
|
||||
|
||||
if (obuf == null)
|
||||
return 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");
|
||||
}
|
||||
}
|
||||
|
||||
String kdcList = cfg.getKDCList(realm);
|
||||
if (kdcList == null) {
|
||||
throw new KrbException("Cannot get kdc for realm " + realm);
|
||||
}
|
||||
// tempKdc may include the port number also
|
||||
Iterator<String> tempKdc = KdcAccessibility.list(kdcList).iterator();
|
||||
if (!tempKdc.hasNext()) {
|
||||
throw new KrbException("Cannot get kdc for realm " + realm);
|
||||
}
|
||||
byte[] ibuf = null;
|
||||
try {
|
||||
ibuf = sendIfPossible(obuf, tempKdc.next(), useTCP);
|
||||
} catch(Exception first) {
|
||||
boolean ok = false;
|
||||
while(tempKdc.hasNext()) {
|
||||
try {
|
||||
ibuf = sendIfPossible(obuf, tempKdc.next(), useTCP);
|
||||
ok = true;
|
||||
break;
|
||||
} catch(Exception ignore) {}
|
||||
}
|
||||
if (!ok) throw first;
|
||||
}
|
||||
if (ibuf == null) {
|
||||
throw new IOException("Cannot get a KDC reply");
|
||||
}
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
// send the AS Request to the specified KDC
|
||||
// failover to using TCP if useTCP is not set and response is too big
|
||||
private byte[] sendIfPossible(byte[] obuf, String tempKdc, boolean useTCP)
|
||||
throws IOException, KrbException {
|
||||
|
||||
try {
|
||||
byte[] ibuf = send(obuf, tempKdc, useTCP);
|
||||
KRBError ke = null;
|
||||
try {
|
||||
ke = new KRBError(ibuf);
|
||||
} catch (Exception e) {
|
||||
// OK
|
||||
}
|
||||
if (ke != null && ke.getErrorCode() ==
|
||||
Krb5.KRB_ERR_RESPONSE_TOO_BIG) {
|
||||
ibuf = send(obuf, tempKdc, true);
|
||||
}
|
||||
KdcAccessibility.removeBad(tempKdc);
|
||||
return ibuf;
|
||||
} catch(Exception e) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KrbKdcReq send: error trying " +
|
||||
tempKdc);
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
KdcAccessibility.addBad(tempKdc);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// send the AS Request to the specified KDC
|
||||
|
||||
private byte[] send(byte[] obuf, String tempKdc, boolean useTCP)
|
||||
throws IOException, KrbException {
|
||||
|
||||
if (obuf == null)
|
||||
return null;
|
||||
|
||||
int port = Krb5.KDC_INET_DEFAULT_PORT;
|
||||
int retries = getRealmSpecificValue(
|
||||
realm, "max_retries", defaultKdcRetryLimit);
|
||||
int timeout = getRealmSpecificValue(
|
||||
realm, "kdc_timeout", defaultKdcTimeout);
|
||||
if (badPolicy == BpType.TRY_LESS &&
|
||||
KdcAccessibility.isBad(tempKdc)) {
|
||||
if (retries > tryLessMaxRetries) {
|
||||
retries = tryLessMaxRetries; // less retries
|
||||
}
|
||||
if (timeout > tryLessTimeout) {
|
||||
timeout = tryLessTimeout; // less time
|
||||
}
|
||||
}
|
||||
|
||||
String kdc = null;
|
||||
String portStr = null;
|
||||
|
||||
if (tempKdc.charAt(0) == '[') { // Explicit IPv6 in []
|
||||
int pos = tempKdc.indexOf(']', 1);
|
||||
if (pos == -1) {
|
||||
throw new IOException("Illegal KDC: " + tempKdc);
|
||||
}
|
||||
kdc = tempKdc.substring(1, pos);
|
||||
if (pos != tempKdc.length() - 1) { // with port number
|
||||
if (tempKdc.charAt(pos+1) != ':') {
|
||||
throw new IOException("Illegal KDC: " + tempKdc);
|
||||
}
|
||||
portStr = tempKdc.substring(pos+2);
|
||||
}
|
||||
} else {
|
||||
int colon = tempKdc.indexOf(':');
|
||||
if (colon == -1) { // Hostname or IPv4 host only
|
||||
kdc = tempKdc;
|
||||
} else {
|
||||
int nextColon = tempKdc.indexOf(':', colon+1);
|
||||
if (nextColon > 0) { // >=2 ":", IPv6 with no port
|
||||
kdc = tempKdc;
|
||||
} else { // 1 ":", hostname or IPv4 with port
|
||||
kdc = tempKdc.substring(0, colon);
|
||||
portStr = tempKdc.substring(colon+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (portStr != null) {
|
||||
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 ="
|
||||
+ retries
|
||||
+ ", #bytes=" + obuf.length);
|
||||
}
|
||||
|
||||
KdcCommunication kdcCommunication =
|
||||
new KdcCommunication(kdc, port, useTCP, timeout, retries, obuf);
|
||||
try {
|
||||
byte[] ibuf = AccessController.doPrivileged(kdcCommunication);
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KrbKdcReq send: #bytes read="
|
||||
+ (ibuf != null ? ibuf.length : 0));
|
||||
}
|
||||
return ibuf;
|
||||
} catch (PrivilegedActionException e) {
|
||||
Exception wrappedException = e.getException();
|
||||
if (wrappedException instanceof IOException) {
|
||||
throw (IOException) wrappedException;
|
||||
} else {
|
||||
throw (KrbException) wrappedException;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class KdcCommunication
|
||||
implements PrivilegedExceptionAction<byte[]> {
|
||||
|
||||
private String kdc;
|
||||
private int port;
|
||||
private boolean useTCP;
|
||||
private int timeout;
|
||||
private int retries;
|
||||
private byte[] obuf;
|
||||
|
||||
public KdcCommunication(String kdc, int port, boolean useTCP,
|
||||
int timeout, int retries, byte[] obuf) {
|
||||
this.kdc = kdc;
|
||||
this.port = port;
|
||||
this.useTCP = useTCP;
|
||||
this.timeout = timeout;
|
||||
this.retries = retries;
|
||||
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;
|
||||
|
||||
for (int i=1; i <= retries; i++) {
|
||||
String proto = useTCP?"TCP":"UDP";
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KDCCommunication: kdc=" + kdc
|
||||
+ " " + proto + ":"
|
||||
+ port + ", timeout="
|
||||
+ timeout
|
||||
+ ",Attempt =" + i
|
||||
+ ", #bytes=" + obuf.length);
|
||||
}
|
||||
try (NetClient kdcClient = NetClient.getInstance(
|
||||
proto, kdc, port, timeout)) {
|
||||
kdcClient.send(obuf);
|
||||
ibuf = kdcClient.receive();
|
||||
break;
|
||||
} catch (SocketTimeoutException se) {
|
||||
if (DEBUG) {
|
||||
System.out.println ("SocketTimeOutException with " +
|
||||
"attempt: " + i);
|
||||
}
|
||||
if (i == retries) {
|
||||
ibuf = null;
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ibuf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a time value string. If it ends with "s", parses as seconds.
|
||||
* Otherwise, parses as milliseconds.
|
||||
* @param s the time string
|
||||
* @return the integer value in milliseconds, or -1 if input is null or
|
||||
* has an invalid format
|
||||
*/
|
||||
private static int parseTimeString(String s) {
|
||||
if (s == null) {
|
||||
return -1;
|
||||
}
|
||||
if (s.endsWith("s")) {
|
||||
int seconds = parsePositiveIntString(s.substring(0, s.length()-1));
|
||||
return (seconds < 0) ? -1 : (seconds*1000);
|
||||
} else {
|
||||
return parsePositiveIntString(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns krb5.conf setting of {@code key} for a specific realm,
|
||||
* which can be:
|
||||
* 1. defined in the sub-stanza for the given realm inside [realms], or
|
||||
* 2. defined in [libdefaults], or
|
||||
* 3. defValue
|
||||
* @param realm the given realm in which the setting is requested. Returns
|
||||
* the global setting if null
|
||||
* @param key the key for the setting
|
||||
* @param defValue default value
|
||||
* @return a value for the key
|
||||
*/
|
||||
private int getRealmSpecificValue(String realm, String key, int defValue) {
|
||||
int v = defValue;
|
||||
|
||||
if (realm == null) return v;
|
||||
|
||||
int temp = -1;
|
||||
try {
|
||||
String value =
|
||||
Config.getInstance().get("realms", realm, key);
|
||||
if (key.equals("kdc_timeout")) {
|
||||
temp = parseTimeString(value);
|
||||
} else {
|
||||
temp = parsePositiveIntString(value);
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
// Ignored, defValue will be picked up
|
||||
}
|
||||
|
||||
if (temp > 0) v = temp;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintains a KDC accessible list. Unavailable KDCs are put into a
|
||||
* blacklist, when a KDC in the blacklist is available, it's removed
|
||||
* from there. No insertion order in the blacklist.
|
||||
*
|
||||
* There are two methods to deal with KDCs in the blacklist. 1. Only try
|
||||
* them when there's no KDC not on the blacklist. 2. Still try them, but
|
||||
* with lesser number of retries and smaller timeout value.
|
||||
*/
|
||||
static class KdcAccessibility {
|
||||
// Known bad KDCs
|
||||
private static Set<String> bads = new HashSet<>();
|
||||
|
||||
private static synchronized void addBad(String kdc) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KdcAccessibility: add " + kdc);
|
||||
}
|
||||
bads.add(kdc);
|
||||
}
|
||||
|
||||
private static synchronized void removeBad(String kdc) {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KdcAccessibility: remove " + kdc);
|
||||
}
|
||||
bads.remove(kdc);
|
||||
}
|
||||
|
||||
private static synchronized boolean isBad(String kdc) {
|
||||
return bads.contains(kdc);
|
||||
}
|
||||
|
||||
private static synchronized void reset() {
|
||||
if (DEBUG) {
|
||||
System.out.println(">>> KdcAccessibility: reset");
|
||||
}
|
||||
bads.clear();
|
||||
}
|
||||
|
||||
// Returns a preferred KDC list by putting the bad ones at the end
|
||||
private static synchronized List<String> list(String kdcList) {
|
||||
StringTokenizer st = new StringTokenizer(kdcList);
|
||||
List<String> list = new ArrayList<>();
|
||||
if (badPolicy == BpType.TRY_LAST) {
|
||||
List<String> badkdcs = new ArrayList<>();
|
||||
while (st.hasMoreTokens()) {
|
||||
String t = st.nextToken();
|
||||
if (bads.contains(t)) badkdcs.add(t);
|
||||
else list.add(t);
|
||||
}
|
||||
// Bad KDCs are put at last
|
||||
list.addAll(badkdcs);
|
||||
} else {
|
||||
// All KDCs are returned in their original order,
|
||||
// This include TRY_LESS and NONE
|
||||
while (st.hasMoreTokens()) {
|
||||
list.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue