1 /*
2  * Copyright (c) 2005, 2020, 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 sun.security.krb5.Realm;
33 import sun.security.jgss.GSSUtil;
34 import sun.security.util.ObjectIdentifier;
35 import sun.security.util.DerInputStream;
36 import sun.security.util.DerOutputStream;
37 import sun.security.jgss.GSSUtil;
38 import sun.security.jgss.GSSExceptionImpl;
39 import sun.security.jgss.spi.GSSNameSpi;
40 
41 import javax.security.auth.kerberos.ServicePermission;
42 
43 /**
44  * This class is essentially a wrapper class for the gss_name_t
45  * structure of the native GSS library.
46  * @author Valerie Peng
47  * @since 1.6
48  */
49 
50 public class GSSNameElement implements GSSNameSpi {
51 
52     long pName = 0; // Pointer to the gss_name_t structure
53     private String printableName;
54     private Oid printableType;
55     private GSSLibStub cStub;
56 
57     static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement();
58 
getNativeNameType(Oid nameType, GSSLibStub stub)59     private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) {
60         if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) {
61             Oid[] supportedNTs = null;
62             try {
63                 supportedNTs = stub.inquireNamesForMech();
64             } catch (GSSException ge) {
65                 if (ge.getMajor() == GSSException.BAD_MECH &&
66                     GSSUtil.isSpNegoMech(stub.getMech())) {
67                     // Workaround known Heimdal issue and retry with KRB5
68                     try {
69                         stub = GSSLibStub.getInstance
70                             (GSSUtil.GSS_KRB5_MECH_OID);
71                         supportedNTs = stub.inquireNamesForMech();
72                     } catch (GSSException ge2) {
73                         // Should never happen
74                         SunNativeProvider.debug("Name type list unavailable: " +
75                             ge2.getMajorString());
76                     }
77                 } else {
78                     SunNativeProvider.debug("Name type list unavailable: " +
79                         ge.getMajorString());
80                 }
81             }
82             if (supportedNTs != null) {
83                 for (int i = 0; i < supportedNTs.length; i++) {
84                     if (supportedNTs[i].equals(nameType)) return nameType;
85                 }
86                 // Special handling the specified name type
87                 SunNativeProvider.debug("Override " + nameType +
88                     " with mechanism default(null)");
89                 return null; // Use mechanism specific default
90             }
91         }
92         return nameType;
93     }
94 
GSSNameElement()95     private GSSNameElement() {
96         printableName = "<DEFAULT ACCEPTOR>";
97     }
98 
99     // Warning: called by NativeUtil.c
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(ObjectIdentifier.of(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 Long.hashCode(pName);
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 
292     @SuppressWarnings("deprecation")
finalize()293     protected void finalize() throws Throwable {
294         dispose();
295     }
296 }
297