1 /* 2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.jgss.wrapper; 27 28 import org.ietf.jgss.*; 29 import java.security.Provider; 30 import java.security.Security; 31 import java.io.IOException; 32 import java.io.UnsupportedEncodingException; 33 import sun.security.krb5.Realm; 34 import sun.security.jgss.GSSUtil; 35 import sun.security.util.ObjectIdentifier; 36 import sun.security.util.DerInputStream; 37 import sun.security.util.DerOutputStream; 38 import sun.security.jgss.GSSUtil; 39 import sun.security.jgss.GSSExceptionImpl; 40 import sun.security.jgss.spi.GSSNameSpi; 41 42 import javax.security.auth.kerberos.ServicePermission; 43 44 /** 45 * This class is essentially a wrapper class for the gss_name_t 46 * structure of the native GSS library. 47 * @author Valerie Peng 48 * @since 1.6 49 */ 50 51 public class GSSNameElement implements GSSNameSpi { 52 53 long pName = 0; // Pointer to the gss_name_t structure 54 private String printableName; 55 private Oid printableType; 56 private GSSLibStub cStub; 57 58 static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement(); 59 getNativeNameType(Oid nameType, GSSLibStub stub)60 private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) { 61 if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) { 62 Oid[] supportedNTs = null; 63 try { 64 supportedNTs = stub.inquireNamesForMech(); 65 } catch (GSSException ge) { 66 if (ge.getMajor() == GSSException.BAD_MECH && 67 GSSUtil.isSpNegoMech(stub.getMech())) { 68 // Workaround known Heimdal issue and retry with KRB5 69 try { 70 stub = GSSLibStub.getInstance 71 (GSSUtil.GSS_KRB5_MECH_OID); 72 supportedNTs = stub.inquireNamesForMech(); 73 } catch (GSSException ge2) { 74 // Should never happen 75 SunNativeProvider.debug("Name type list unavailable: " + 76 ge2.getMajorString()); 77 } 78 } else { 79 SunNativeProvider.debug("Name type list unavailable: " + 80 ge.getMajorString()); 81 } 82 } 83 if (supportedNTs != null) { 84 for (int i = 0; i < supportedNTs.length; i++) { 85 if (supportedNTs[i].equals(nameType)) return nameType; 86 } 87 // Special handling the specified name type 88 SunNativeProvider.debug("Override " + nameType + 89 " with mechanism default(null)"); 90 return null; // Use mechanism specific default 91 } 92 } 93 return nameType; 94 } 95 GSSNameElement()96 private GSSNameElement() { 97 printableName = "<DEFAULT ACCEPTOR>"; 98 } 99 GSSNameElement(long pNativeName, GSSLibStub stub)100 GSSNameElement(long pNativeName, GSSLibStub stub) throws GSSException { 101 assert(stub != null); 102 if (pNativeName == 0) { 103 throw new GSSException(GSSException.BAD_NAME); 104 } 105 // Note: pNativeName is assumed to be a MN. 106 pName = pNativeName; 107 cStub = stub; 108 setPrintables(); 109 } 110 GSSNameElement(byte[] nameBytes, Oid nameType, GSSLibStub stub)111 GSSNameElement(byte[] nameBytes, Oid nameType, GSSLibStub stub) 112 throws GSSException { 113 assert(stub != null); 114 if (nameBytes == null) { 115 throw new GSSException(GSSException.BAD_NAME); 116 } 117 cStub = stub; 118 byte[] name = nameBytes; 119 120 if (nameType != null) { 121 // Special handling the specified name type if 122 // necessary 123 nameType = getNativeNameType(nameType, stub); 124 125 if (GSSName.NT_EXPORT_NAME.equals(nameType)) { 126 // Need to add back the mech Oid portion (stripped 127 // off by GSSNameImpl class prior to calling this 128 // method) for "NT_EXPORT_NAME" 129 byte[] mechBytes = null; 130 DerOutputStream dout = new DerOutputStream(); 131 Oid mech = cStub.getMech(); 132 try { 133 dout.putOID(new ObjectIdentifier(mech.toString())); 134 } catch (IOException e) { 135 throw new GSSExceptionImpl(GSSException.FAILURE, e); 136 } 137 mechBytes = dout.toByteArray(); 138 name = new byte[2 + 2 + mechBytes.length + 4 + nameBytes.length]; 139 int pos = 0; 140 name[pos++] = 0x04; 141 name[pos++] = 0x01; 142 name[pos++] = (byte) (mechBytes.length>>>8); 143 name[pos++] = (byte) mechBytes.length; 144 System.arraycopy(mechBytes, 0, name, pos, mechBytes.length); 145 pos += mechBytes.length; 146 name[pos++] = (byte) (nameBytes.length>>>24); 147 name[pos++] = (byte) (nameBytes.length>>>16); 148 name[pos++] = (byte) (nameBytes.length>>>8); 149 name[pos++] = (byte) nameBytes.length; 150 System.arraycopy(nameBytes, 0, name, pos, nameBytes.length); 151 } 152 } 153 pName = cStub.importName(name, nameType); 154 setPrintables(); 155 156 SecurityManager sm = System.getSecurityManager(); 157 if (sm != null && !Realm.AUTODEDUCEREALM) { 158 String krbName = getKrbName(); 159 int atPos = krbName.lastIndexOf('@'); 160 if (atPos != -1) { 161 String atRealm = krbName.substring(atPos); 162 // getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null 163 if ((nameType == null 164 || nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL)) 165 && new String(nameBytes).endsWith(atRealm)) { 166 // Created from Kerberos name with realm, no need to check 167 } else { 168 try { 169 sm.checkPermission(new ServicePermission(atRealm, "-")); 170 } catch (SecurityException se) { 171 // Do not chain the actual exception to hide info 172 throw new GSSException(GSSException.FAILURE); 173 } 174 } 175 } 176 } 177 178 SunNativeProvider.debug("Imported " + printableName + " w/ type " + 179 printableType); 180 } 181 setPrintables()182 private void setPrintables() throws GSSException { 183 Object[] printables = null; 184 printables = cStub.displayName(pName); 185 assert((printables != null) && (printables.length == 2)); 186 printableName = (String) printables[0]; 187 assert(printableName != null); 188 printableType = (Oid) printables[1]; 189 if (printableType == null) { 190 printableType = GSSName.NT_USER_NAME; 191 } 192 } 193 194 // Need to be public for GSSUtil.getSubject() getKrbName()195 public String getKrbName() throws GSSException { 196 long mName = 0; 197 GSSLibStub stub = cStub; 198 if (!GSSUtil.isKerberosMech(cStub.getMech())) { 199 stub = GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID); 200 } 201 mName = stub.canonicalizeName(pName); 202 Object[] printables2 = stub.displayName(mName); 203 stub.releaseName(mName); 204 SunNativeProvider.debug("Got kerberized name: " + printables2[0]); 205 return (String) printables2[0]; 206 } 207 getProvider()208 public Provider getProvider() { 209 return SunNativeProvider.INSTANCE; 210 } 211 equals(GSSNameSpi other)212 public boolean equals(GSSNameSpi other) throws GSSException { 213 if (!(other instanceof GSSNameElement)) { 214 return false; 215 } 216 return cStub.compareName(pName, ((GSSNameElement)other).pName); 217 } 218 equals(Object other)219 public boolean equals(Object other) { 220 if (!(other instanceof GSSNameElement)) { 221 return false; 222 } 223 try { 224 return equals((GSSNameElement) other); 225 } catch (GSSException ex) { 226 return false; 227 } 228 } 229 hashCode()230 public int hashCode() { 231 return new Long(pName).hashCode(); 232 } 233 export()234 public byte[] export() throws GSSException { 235 byte[] nameVal = cStub.exportName(pName); 236 237 // Need to strip off the mech Oid portion of the exported 238 // bytes since GSSNameImpl class will subsequently add it. 239 int pos = 0; 240 if ((nameVal[pos++] != 0x04) || 241 (nameVal[pos++] != 0x01)) 242 throw new GSSException(GSSException.BAD_NAME); 243 244 int mechOidLen = (((0xFF & nameVal[pos++]) << 8) | 245 (0xFF & nameVal[pos++])); 246 ObjectIdentifier temp = null; 247 try { 248 DerInputStream din = new DerInputStream(nameVal, pos, 249 mechOidLen); 250 temp = new ObjectIdentifier(din); 251 } catch (IOException e) { 252 throw new GSSExceptionImpl(GSSException.BAD_NAME, e); 253 } 254 Oid mech2 = new Oid(temp.toString()); 255 assert(mech2.equals(getMechanism())); 256 pos += mechOidLen; 257 int mechPortionLen = (((0xFF & nameVal[pos++]) << 24) | 258 ((0xFF & nameVal[pos++]) << 16) | 259 ((0xFF & nameVal[pos++]) << 8) | 260 (0xFF & nameVal[pos++])); 261 if (mechPortionLen < 0) { 262 throw new GSSException(GSSException.BAD_NAME); 263 } 264 byte[] mechPortion = new byte[mechPortionLen]; 265 System.arraycopy(nameVal, pos, mechPortion, 0, mechPortionLen); 266 return mechPortion; 267 } 268 getMechanism()269 public Oid getMechanism() { 270 return cStub.getMech(); 271 } 272 toString()273 public String toString() { 274 return printableName; 275 } 276 getStringNameType()277 public Oid getStringNameType() { 278 return printableType; 279 } 280 isAnonymousName()281 public boolean isAnonymousName() { 282 return (GSSName.NT_ANONYMOUS.equals(printableType)); 283 } 284 dispose()285 public void dispose() { 286 if (pName != 0) { 287 cStub.releaseName(pName); 288 pName = 0; 289 } 290 } 291 finalize()292 protected void finalize() throws Throwable { 293 dispose(); 294 } 295 } 296