blob: b98dcea6fce1998831a95370261b3dfa4e952edd [file] [log] [blame]
/*
* Copyright (c) 2005, 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.
*/
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.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;
/**
* 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();
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 new Long(pName).hashCode();
}
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++]));
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;
}
}
protected void finalize() throws Throwable {
dispose();
}
}