src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/GSSNameElement.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2005, 2017, 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.
+ */
+
+package sun.security.jgss.wrapper;
+
+import org.ietf.jgss.*;
+import java.security.Provider;
+import java.security.Security;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import sun.security.krb5.Realm;
+import sun.security.jgss.GSSUtil;
+import sun.security.util.ObjectIdentifier;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+import sun.security.jgss.GSSUtil;
+import sun.security.jgss.GSSExceptionImpl;
+import sun.security.jgss.spi.GSSNameSpi;
+
+import javax.security.auth.kerberos.ServicePermission;
+
+/**
+ * This class is essentially a wrapper class for the gss_name_t
+ * structure of the native GSS library.
+ * @author Valerie Peng
+ * @since 1.6
+ */
+
+public class GSSNameElement implements GSSNameSpi {
+
+ long pName = 0; // Pointer to the gss_name_t structure
+ private String printableName;
+ private Oid printableType;
+ private GSSLibStub cStub;
+
+ static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement();
+
+ private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) {
+ if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) {
+ Oid[] supportedNTs = null;
+ try {
+ supportedNTs = stub.inquireNamesForMech();
+ } catch (GSSException ge) {
+ if (ge.getMajor() == GSSException.BAD_MECH &&
+ GSSUtil.isSpNegoMech(stub.getMech())) {
+ // Workaround known Heimdal issue and retry with KRB5
+ try {
+ stub = GSSLibStub.getInstance
+ (GSSUtil.GSS_KRB5_MECH_OID);
+ supportedNTs = stub.inquireNamesForMech();
+ } catch (GSSException ge2) {
+ // Should never happen
+ SunNativeProvider.debug("Name type list unavailable: " +
+ ge2.getMajorString());
+ }
+ } else {
+ SunNativeProvider.debug("Name type list unavailable: " +
+ ge.getMajorString());
+ }
+ }
+ if (supportedNTs != null) {
+ for (int i = 0; i < supportedNTs.length; i++) {
+ if (supportedNTs[i].equals(nameType)) return nameType;
+ }
+ // Special handling the specified name type
+ SunNativeProvider.debug("Override " + nameType +
+ " with mechanism default(null)");
+ return null; // Use mechanism specific default
+ }
+ }
+ return nameType;
+ }
+
+ private GSSNameElement() {
+ printableName = "<DEFAULT ACCEPTOR>";
+ }
+
+ GSSNameElement(long pNativeName, GSSLibStub stub) throws GSSException {
+ assert(stub != null);
+ if (pNativeName == 0) {
+ throw new GSSException(GSSException.BAD_NAME);
+ }
+ // Note: pNativeName is assumed to be a MN.
+ pName = pNativeName;
+ cStub = stub;
+ setPrintables();
+ }
+
+ GSSNameElement(byte[] nameBytes, Oid nameType, GSSLibStub stub)
+ throws GSSException {
+ assert(stub != null);
+ if (nameBytes == null) {
+ throw new GSSException(GSSException.BAD_NAME);
+ }
+ cStub = stub;
+ byte[] name = nameBytes;
+
+ if (nameType != null) {
+ // Special handling the specified name type if
+ // necessary
+ nameType = getNativeNameType(nameType, stub);
+
+ if (GSSName.NT_EXPORT_NAME.equals(nameType)) {
+ // Need to add back the mech Oid portion (stripped
+ // off by GSSNameImpl class prior to calling this
+ // method) for "NT_EXPORT_NAME"
+ byte[] mechBytes = null;
+ DerOutputStream dout = new DerOutputStream();
+ Oid mech = cStub.getMech();
+ try {
+ dout.putOID(new ObjectIdentifier(mech.toString()));
+ } catch (IOException e) {
+ throw new GSSExceptionImpl(GSSException.FAILURE, e);
+ }
+ mechBytes = dout.toByteArray();
+ name = new byte[2 + 2 + mechBytes.length + 4 + nameBytes.length];
+ int pos = 0;
+ name[pos++] = 0x04;
+ name[pos++] = 0x01;
+ name[pos++] = (byte) (mechBytes.length>>>8);
+ name[pos++] = (byte) mechBytes.length;
+ System.arraycopy(mechBytes, 0, name, pos, mechBytes.length);
+ pos += mechBytes.length;
+ name[pos++] = (byte) (nameBytes.length>>>24);
+ name[pos++] = (byte) (nameBytes.length>>>16);
+ name[pos++] = (byte) (nameBytes.length>>>8);
+ name[pos++] = (byte) nameBytes.length;
+ System.arraycopy(nameBytes, 0, name, pos, nameBytes.length);
+ }
+ }
+ pName = cStub.importName(name, nameType);
+ setPrintables();
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null && !Realm.AUTODEDUCEREALM) {
+ String krbName = getKrbName();
+ int atPos = krbName.lastIndexOf('@');
+ if (atPos != -1) {
+ String atRealm = krbName.substring(atPos);
+ // getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null
+ if ((nameType == null
+ || nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
+ && new String(nameBytes).endsWith(atRealm)) {
+ // Created from Kerberos name with realm, no need to check
+ } else {
+ try {
+ sm.checkPermission(new ServicePermission(atRealm, "-"));
+ } catch (SecurityException se) {
+ // Do not chain the actual exception to hide info
+ throw new GSSException(GSSException.FAILURE);
+ }
+ }
+ }
+ }
+
+ SunNativeProvider.debug("Imported " + printableName + " w/ type " +
+ printableType);
+ }
+
+ private void setPrintables() throws GSSException {
+ Object[] printables = null;
+ printables = cStub.displayName(pName);
+ assert((printables != null) && (printables.length == 2));
+ printableName = (String) printables[0];
+ assert(printableName != null);
+ printableType = (Oid) printables[1];
+ if (printableType == null) {
+ printableType = GSSName.NT_USER_NAME;
+ }
+ }
+
+ // Need to be public for GSSUtil.getSubject()
+ public String getKrbName() throws GSSException {
+ long mName = 0;
+ GSSLibStub stub = cStub;
+ if (!GSSUtil.isKerberosMech(cStub.getMech())) {
+ stub = GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID);
+ }
+ mName = stub.canonicalizeName(pName);
+ Object[] printables2 = stub.displayName(mName);
+ stub.releaseName(mName);
+ SunNativeProvider.debug("Got kerberized name: " + printables2[0]);
+ return (String) printables2[0];
+ }
+
+ public Provider getProvider() {
+ return SunNativeProvider.INSTANCE;
+ }
+
+ public boolean equals(GSSNameSpi other) throws GSSException {
+ if (!(other instanceof GSSNameElement)) {
+ return false;
+ }
+ return cStub.compareName(pName, ((GSSNameElement)other).pName);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof GSSNameElement)) {
+ return false;
+ }
+ try {
+ return equals((GSSNameElement) other);
+ } catch (GSSException ex) {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return Long.hashCode(pName);
+ }
+
+ public byte[] export() throws GSSException {
+ byte[] nameVal = cStub.exportName(pName);
+
+ // Need to strip off the mech Oid portion of the exported
+ // bytes since GSSNameImpl class will subsequently add it.
+ int pos = 0;
+ if ((nameVal[pos++] != 0x04) ||
+ (nameVal[pos++] != 0x01))
+ throw new GSSException(GSSException.BAD_NAME);
+
+ int mechOidLen = (((0xFF & nameVal[pos++]) << 8) |
+ (0xFF & nameVal[pos++]));
+ ObjectIdentifier temp = null;
+ try {
+ DerInputStream din = new DerInputStream(nameVal, pos,
+ mechOidLen);
+ temp = new ObjectIdentifier(din);
+ } catch (IOException e) {
+ throw new GSSExceptionImpl(GSSException.BAD_NAME, e);
+ }
+ Oid mech2 = new Oid(temp.toString());
+ assert(mech2.equals(getMechanism()));
+ pos += mechOidLen;
+ int mechPortionLen = (((0xFF & nameVal[pos++]) << 24) |
+ ((0xFF & nameVal[pos++]) << 16) |
+ ((0xFF & nameVal[pos++]) << 8) |
+ (0xFF & nameVal[pos++]));
+ if (mechPortionLen < 0) {
+ throw new GSSException(GSSException.BAD_NAME);
+ }
+ byte[] mechPortion = new byte[mechPortionLen];
+ System.arraycopy(nameVal, pos, mechPortion, 0, mechPortionLen);
+ return mechPortion;
+ }
+
+ public Oid getMechanism() {
+ return cStub.getMech();
+ }
+
+ public String toString() {
+ return printableName;
+ }
+
+ public Oid getStringNameType() {
+ return printableType;
+ }
+
+ public boolean isAnonymousName() {
+ return (GSSName.NT_ANONYMOUS.equals(printableType));
+ }
+
+ public void dispose() {
+ if (pName != 0) {
+ cStub.releaseName(pName);
+ pName = 0;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ dispose();
+ }
+}