1 /*
2  * Copyright (c) 2005, 2018, 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 #include "NativeUtil.h"
27 #include "NativeFunc.h"
28 #include "jlong.h"
29 #include <jni.h>
30 #include "jni_util.h"
31 
32 const int JAVA_DUPLICATE_TOKEN_CODE = 19; /* DUPLICATE_TOKEN */
33 const int JAVA_OLD_TOKEN_CODE = 20; /* OLD_TOKEN */
34 const int JAVA_UNSEQ_TOKEN_CODE = 21; /* UNSEQ_TOKEN */
35 const int JAVA_GAP_TOKEN_CODE = 22; /* GAP_TOKEN */
36 const int JAVA_ERROR_CODE[] = {
37   2,  /* BAD_MECH */
38   3,  /* BAD_NAME */
39   4,  /* BAD_NAMETYPE */
40   1,  /* BAD_BINDINGS */
41   5,  /* BAD_STATUS */
42   6,  /* BAD_MIC */
43   13, /* NO_CRED */
44   12, /* NO_CONTEXT */
45   10, /* DEFECTIVE_TOKEN */
46   9,  /* DEFECTIVE_CREDENTIAL */
47   8,  /* CREDENTIAL_EXPIRED */
48   7,  /* CONTEXT_EXPIRED */
49   11, /* FAILURE */
50   14, /* BAD_QOP */
51   15, /* UNAUTHORIZED */
52   16, /* UNAVAILABLE */
53   17, /* DUPLICATE_ELEMENT */
54   18, /* NAME_NOT_MN */
55 };
56 const char SPNEGO_BYTES[] = {
57  0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
58 };
59 
60 jclass CLS_Object;
61 jclass CLS_String;
62 jclass CLS_Oid;
63 jclass CLS_GSSException;
64 jclass CLS_GSSNameElement;
65 jclass CLS_GSSCredElement;
66 jclass CLS_NativeGSSContext;
67 jclass CLS_SunNativeProvider;
68 jmethodID MID_String_ctor;
69 jmethodID MID_Oid_ctor1;
70 jmethodID MID_Oid_getDER;
71 jmethodID MID_MessageProp_getPrivacy;
72 jmethodID MID_MessageProp_getQOP;
73 jmethodID MID_MessageProp_setPrivacy;
74 jmethodID MID_MessageProp_setQOP;
75 jmethodID MID_MessageProp_setSupplementaryStates;
76 jmethodID MID_GSSException_ctor3;
77 jmethodID MID_ChannelBinding_getInitiatorAddr;
78 jmethodID MID_ChannelBinding_getAcceptorAddr;
79 jmethodID MID_ChannelBinding_getAppData;
80 jmethodID MID_InetAddress_getAddr;
81 jmethodID MID_GSSNameElement_ctor;
82 jmethodID MID_GSSCredElement_ctor;
83 jmethodID MID_NativeGSSContext_ctor;
84 jfieldID FID_GSSLibStub_pMech;
85 jfieldID FID_NativeGSSContext_pContext;
86 jfieldID FID_NativeGSSContext_srcName;
87 jfieldID FID_NativeGSSContext_targetName;
88 jfieldID FID_NativeGSSContext_isInitiator;
89 jfieldID FID_NativeGSSContext_isEstablished;
90 jfieldID FID_NativeGSSContext_delegatedCred;
91 jfieldID FID_NativeGSSContext_flags;
92 jfieldID FID_NativeGSSContext_lifetime;
93 jfieldID FID_NativeGSSContext_actualMech;
94 
95 int JGSS_DEBUG;
96 
97 JNIEXPORT jint JNICALL
DEF_JNI_OnLoad(JavaVM * jvm,void * reserved)98 DEF_JNI_OnLoad(JavaVM *jvm, void *reserved) {
99   JNIEnv *env;
100   jclass cls;
101 
102   if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
103     return JNI_EVERSION; /* JNI version not supported */
104   }
105   /* Retrieve and store the classes in global ref */
106   cls = (*env)->FindClass(env, "java/lang/Object");
107   if (cls == NULL) {
108     printf("Couldn't find Object class\n");
109     return JNI_ERR;
110   }
111   CLS_Object = (*env)->NewGlobalRef(env, cls);
112   if (CLS_Object == NULL) {
113     return JNI_ERR;
114   }
115   cls = (*env)->FindClass(env, "java/lang/String");
116   if (cls == NULL) {
117     printf("Couldn't find String class\n");
118     return JNI_ERR;
119   }
120   CLS_String = (*env)->NewGlobalRef(env, cls);
121   if (CLS_String == NULL) {
122     return JNI_ERR;
123   }
124   cls = (*env)->FindClass(env, "org/ietf/jgss/Oid");
125   if (cls == NULL) {
126     printf("Couldn't find org.ietf.jgss.Oid class\n");
127     return JNI_ERR;
128   }
129   CLS_Oid = (*env)->NewGlobalRef(env, cls);
130   if (CLS_Oid == NULL) {
131     return JNI_ERR;
132   }
133   cls = (*env)->FindClass(env, "org/ietf/jgss/GSSException");
134   if (cls == NULL) {
135     printf("Couldn't find org.ietf.jgss.GSSException class\n");
136     return JNI_ERR;
137   }
138   CLS_GSSException = (*env)->NewGlobalRef(env, cls);
139   if (CLS_GSSException == NULL) {
140     return JNI_ERR;
141   }
142   cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSNameElement");
143   if (cls == NULL) {
144     printf("Couldn't find sun.security.jgss.wrapper.GSSNameElement class\n");
145     return JNI_ERR;
146   }
147   CLS_GSSNameElement = (*env)->NewGlobalRef(env, cls);
148   if (CLS_GSSException == NULL) {
149     return JNI_ERR;
150   }
151   cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSCredElement");
152   if (cls == NULL) {
153     printf("Couldn't find sun.security.jgss.wrapper.GSSCredElement class\n");
154     return JNI_ERR;
155   }
156   CLS_GSSCredElement = (*env)->NewGlobalRef(env, cls);
157   if (CLS_GSSCredElement == NULL) {
158     return JNI_ERR;
159   }
160   cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/NativeGSSContext");
161   if (cls == NULL) {
162     printf("Couldn't find sun.security.jgss.wrapper.NativeGSSContext class\n");
163     return JNI_ERR;
164   }
165   CLS_NativeGSSContext = (*env)->NewGlobalRef(env, cls);
166   if (CLS_NativeGSSContext == NULL) {
167     return JNI_ERR;
168   }
169   cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/SunNativeProvider");
170   if (cls == NULL) {
171     printf("Couldn't find sun.security.jgss.wrapper.SunNativeProvider class\n");
172     return JNI_ERR;
173   }
174   CLS_SunNativeProvider = (*env)->NewGlobalRef(env, cls);
175   if (CLS_SunNativeProvider == NULL) {
176     return JNI_ERR;
177   }
178   /* Compute and cache the method ID */
179   MID_String_ctor = (*env)->GetMethodID(env, CLS_String,
180                                         "<init>", "([B)V");
181   if (MID_String_ctor == NULL) {
182     printf("Couldn't find String(byte[]) constructor\n");
183     return JNI_ERR;
184   }
185   MID_Oid_ctor1 =
186     (*env)->GetMethodID(env, CLS_Oid, "<init>", "([B)V");
187   if (MID_Oid_ctor1 == NULL) {
188     printf("Couldn't find Oid(byte[]) constructor\n");
189     return JNI_ERR;
190   }
191   MID_Oid_getDER = (*env)->GetMethodID(env, CLS_Oid, "getDER", "()[B");
192   if (MID_Oid_getDER == NULL) {
193     printf("Couldn't find Oid.getDER() method\n");
194     return JNI_ERR;
195   }
196   cls = (*env)->FindClass(env, "org/ietf/jgss/MessageProp");
197   if (cls == NULL) {
198     printf("Couldn't find org.ietf.jgss.MessageProp class\n");
199     return JNI_ERR;
200   }
201   MID_MessageProp_getPrivacy =
202     (*env)->GetMethodID(env, cls, "getPrivacy", "()Z");
203   if (MID_MessageProp_getPrivacy == NULL) {
204     printf("Couldn't find MessageProp.getPrivacy() method\n");
205     return JNI_ERR;
206   }
207   MID_MessageProp_getQOP = (*env)->GetMethodID(env, cls, "getQOP", "()I");
208   if (MID_MessageProp_getQOP == NULL) {
209     printf("Couldn't find MessageProp.getQOP() method\n");
210     return JNI_ERR;
211   }
212   MID_MessageProp_setPrivacy =
213     (*env)->GetMethodID(env, cls, "setPrivacy", "(Z)V");
214   if (MID_MessageProp_setPrivacy == NULL) {
215     printf("Couldn't find MessageProp.setPrivacy(boolean) method\n");
216     return JNI_ERR;
217   }
218   MID_MessageProp_setQOP = (*env)->GetMethodID(env, cls, "setQOP", "(I)V");
219   if (MID_MessageProp_setQOP == NULL) {
220     printf("Couldn't find MessageProp.setQOP(int) method\n");
221     return JNI_ERR;
222   }
223   MID_MessageProp_setSupplementaryStates =
224     (*env)->GetMethodID(env, cls, "setSupplementaryStates",
225                         "(ZZZZILjava/lang/String;)V");
226   if (MID_MessageProp_setSupplementaryStates == NULL) {
227     printf("Couldn't find MessageProp.setSupplementaryStates(...) method\n");
228     return JNI_ERR;
229   }
230   MID_GSSException_ctor3 = (*env)->GetMethodID
231     (env, CLS_GSSException, "<init>", "(IILjava/lang/String;)V");
232   if (MID_GSSException_ctor3 == NULL) {
233     printf("Couldn't find GSSException(int, int, String) constructor\n");
234     return JNI_ERR;
235   }
236   cls = (*env)->FindClass(env, "org/ietf/jgss/ChannelBinding");
237   if (cls == NULL) {
238     printf("Couldn't find org.ietf.jgss.ChannelBinding class\n");
239     return JNI_ERR;
240   }
241   MID_ChannelBinding_getInitiatorAddr =
242     (*env)->GetMethodID(env, cls, "getInitiatorAddress",
243                         "()Ljava/net/InetAddress;");
244   if (MID_ChannelBinding_getInitiatorAddr == NULL) {
245     printf("Couldn't find ChannelBinding.getInitiatorAddress() method\n");
246     return JNI_ERR;
247   }
248   MID_ChannelBinding_getAcceptorAddr =
249     (*env)->GetMethodID(env, cls, "getAcceptorAddress",
250                         "()Ljava/net/InetAddress;");
251   if (MID_ChannelBinding_getAcceptorAddr == NULL) {
252     printf("Couldn't find ChannelBinding.getAcceptorAddress() method\n");
253     return JNI_ERR;
254   }
255   MID_ChannelBinding_getAppData =
256     (*env)->GetMethodID(env, cls, "getApplicationData", "()[B");
257   if (MID_ChannelBinding_getAppData == NULL) {
258     printf("Couldn't find ChannelBinding.getApplicationData() method\n");
259     return JNI_ERR;
260   }
261   cls = (*env)->FindClass(env, "java/net/InetAddress");
262   if (cls == NULL) {
263     printf("Couldn't find java.net.InetAddress class\n");
264     return JNI_ERR;
265   }
266   MID_InetAddress_getAddr = (*env)->GetMethodID(env, cls, "getAddress",
267                                                 "()[B");
268   if (MID_InetAddress_getAddr == NULL) {
269     printf("Couldn't find InetAddress.getAddress() method\n");
270     return JNI_ERR;
271   }
272   MID_GSSNameElement_ctor =
273     (*env)->GetMethodID(env, CLS_GSSNameElement,
274                         "<init>", "(JLsun/security/jgss/wrapper/GSSLibStub;)V");
275   if (MID_GSSNameElement_ctor == NULL) {
276     printf("Couldn't find GSSNameElement(long, GSSLibStub) constructor\n");
277     return JNI_ERR;
278   }
279   MID_GSSCredElement_ctor =
280     (*env)->GetMethodID(env, CLS_GSSCredElement, "<init>",
281         "(JLsun/security/jgss/wrapper/GSSNameElement;Lorg/ietf/jgss/Oid;)V");
282   if (MID_GSSCredElement_ctor == NULL) {
283     printf("Couldn't find GSSCredElement(long, GSSLibStub) constructor\n");
284     return JNI_ERR;
285   }
286   MID_NativeGSSContext_ctor =
287     (*env)->GetMethodID(env, CLS_NativeGSSContext, "<init>",
288                         "(JLsun/security/jgss/wrapper/GSSLibStub;)V");
289   if (MID_NativeGSSContext_ctor == NULL) {
290     printf("Couldn't find NativeGSSContext(long, GSSLibStub) constructor\n");
291     return JNI_ERR;
292   }
293   /* Compute and cache the field ID */
294   cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSLibStub");
295   if (cls == NULL) {
296     printf("Couldn't find sun.security.jgss.wrapper.GSSLibStub class\n");
297     return JNI_ERR;
298   }
299   FID_GSSLibStub_pMech =
300     (*env)->GetFieldID(env, cls, "pMech", "J");
301   if (FID_GSSLibStub_pMech == NULL) {
302     printf("Couldn't find GSSLibStub.pMech field\n");
303     return JNI_ERR;
304   }
305   FID_NativeGSSContext_pContext =
306     (*env)->GetFieldID(env, CLS_NativeGSSContext, "pContext", "J");
307   if (FID_NativeGSSContext_pContext == NULL) {
308     printf("Couldn't find NativeGSSContext.pContext field\n");
309     return JNI_ERR;
310   }
311   FID_NativeGSSContext_srcName =
312     (*env)->GetFieldID(env, CLS_NativeGSSContext, "srcName",
313                        "Lsun/security/jgss/wrapper/GSSNameElement;");
314   if (FID_NativeGSSContext_srcName == NULL) {
315     printf("Couldn't find NativeGSSContext.srcName field\n");
316    return JNI_ERR;
317   }
318   FID_NativeGSSContext_targetName =
319     (*env)->GetFieldID(env, CLS_NativeGSSContext, "targetName",
320                        "Lsun/security/jgss/wrapper/GSSNameElement;");
321   if (FID_NativeGSSContext_targetName == NULL) {
322     printf("Couldn't find NativeGSSContext.targetName field\n");
323     return JNI_ERR;
324   }
325   FID_NativeGSSContext_isInitiator =
326     (*env)->GetFieldID(env, CLS_NativeGSSContext, "isInitiator", "Z");
327   if (FID_NativeGSSContext_isInitiator == NULL) {
328     printf("Couldn't find NativeGSSContext.isInitiator field\n");
329     return JNI_ERR;
330   }
331   FID_NativeGSSContext_isEstablished =
332     (*env)->GetFieldID(env, CLS_NativeGSSContext, "isEstablished", "Z");
333   if (FID_NativeGSSContext_isEstablished == NULL) {
334     printf("Couldn't find NativeGSSContext.isEstablished field\n");
335     return JNI_ERR;
336   }
337   FID_NativeGSSContext_delegatedCred =
338     (*env)->GetFieldID(env, CLS_NativeGSSContext, "delegatedCred",
339                        "Lsun/security/jgss/wrapper/GSSCredElement;");
340   if (FID_NativeGSSContext_delegatedCred == NULL) {
341     printf("Couldn't find NativeGSSContext.delegatedCred field\n");
342     return JNI_ERR;
343   }
344   FID_NativeGSSContext_flags =
345     (*env)->GetFieldID(env, CLS_NativeGSSContext, "flags", "I");
346   if (FID_NativeGSSContext_flags == NULL) {
347     printf("Couldn't find NativeGSSContext.flags field\n");
348     return JNI_ERR;
349   }
350   FID_NativeGSSContext_lifetime =
351     (*env)->GetFieldID(env, CLS_NativeGSSContext, "lifetime", "I");
352   if (FID_NativeGSSContext_lifetime == NULL) {
353     printf("Couldn't find NativeGSSContext.lifetime field\n");
354     return JNI_ERR;
355   }
356   FID_NativeGSSContext_actualMech =
357     (*env)->GetFieldID(env, CLS_NativeGSSContext, "actualMech",
358                        "Lorg/ietf/jgss/Oid;");
359   if (FID_NativeGSSContext_actualMech == NULL) {
360     printf("Couldn't find NativeGSSContext.actualMech field\n");
361     return JNI_ERR;
362   }
363   return JNI_VERSION_1_2;
364 }
365 
366 JNIEXPORT void JNICALL
DEF_JNI_OnUnload(JavaVM * jvm,void * reserved)367 DEF_JNI_OnUnload(JavaVM *jvm, void *reserved) {
368   JNIEnv *env;
369 
370   if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
371     return;
372   }
373   /* Delete the global refs */
374   (*env)->DeleteGlobalRef(env, CLS_Object);
375   (*env)->DeleteGlobalRef(env, CLS_String);
376   (*env)->DeleteGlobalRef(env, CLS_Oid);
377   (*env)->DeleteGlobalRef(env, CLS_GSSException);
378   (*env)->DeleteGlobalRef(env, CLS_GSSNameElement);
379   (*env)->DeleteGlobalRef(env, CLS_GSSCredElement);
380   (*env)->DeleteGlobalRef(env, CLS_SunNativeProvider);
381   return;
382 }
383 
384 const OM_uint32 JAVA_MAX = GSS_C_INDEFINITE/2;
385 
386 /*
387  * Utility routine for converting the C unsigned integer time
388  * to Java signed integer time.
389  */
getJavaTime(OM_uint32 ctime)390 jint getJavaTime(OM_uint32 ctime) {
391   jint result;
392 
393   /* special handle values equals or more than JAVA_MAX */
394   if (ctime == GSS_C_INDEFINITE) {
395     result = JAVA_MAX;
396   } else if (ctime >= JAVA_MAX) {
397     result = JAVA_MAX-1;
398   } else {
399     result = ctime;
400   }
401   return result;
402 }
403 /*
404  * Utility routine for converting the Java signed integer time
405  * to C unsigned integer time.
406  */
getGSSTime(jint jtime)407 OM_uint32 getGSSTime(jint jtime) {
408   OM_uint32 result;
409 
410   /* special handle values equal to JAVA_MAX */
411   if (jtime == (jint)JAVA_MAX) {
412     result = GSS_C_INDEFINITE;
413   } else {
414     result = jtime;
415   }
416   return result;
417 }
418 /*
419  * Utility routine for mapping the C error code to the
420  * Java one. The routine errors really should have
421  * shared the same values but unfortunately don't.
422  */
getJavaErrorCode(int cNonCallingErr)423 jint getJavaErrorCode(int cNonCallingErr) {
424   int cRoutineErr, cSuppStatus;
425   /* map the routine errors */
426   cRoutineErr = GSS_ROUTINE_ERROR(cNonCallingErr) >> 16;
427   if (cRoutineErr != GSS_S_COMPLETE) {
428     return JAVA_ERROR_CODE[cRoutineErr-1];
429   }
430   /* map the supplementary infos */
431   cSuppStatus = GSS_SUPPLEMENTARY_INFO(cNonCallingErr);
432   if (cSuppStatus & GSS_S_DUPLICATE_TOKEN) {
433     return JAVA_DUPLICATE_TOKEN_CODE;
434   } else if (cSuppStatus & GSS_S_OLD_TOKEN) {
435     return JAVA_OLD_TOKEN_CODE;
436   } else if (cSuppStatus & GSS_S_UNSEQ_TOKEN) {
437     return JAVA_UNSEQ_TOKEN_CODE;
438   } else if (cSuppStatus & GSS_S_GAP_TOKEN) {
439     return JAVA_GAP_TOKEN_CODE;
440   }
441   return GSS_S_COMPLETE;
442 }
443 
444 
445 /* Throws a Java Exception by name */
throwByName(JNIEnv * env,const char * name,const char * msg)446 void throwByName(JNIEnv *env, const char *name, const char *msg) {
447     jclass cls = (*env)->FindClass(env, name);
448 
449     if (cls != NULL) {
450         (*env)->ThrowNew(env, cls, msg);
451     }
452 }
453 
throwOutOfMemoryError(JNIEnv * env,const char * message)454 void throwOutOfMemoryError(JNIEnv *env, const char *message) {
455     throwByName(env, "java/lang/OutOfMemoryError", message);
456 }
457 
458 /*
459  * Utility routine for creating a java.lang.String object
460  * using the specified gss_buffer_t structure. The specified
461  * gss_buffer_t structure is always released.
462  */
getJavaString(JNIEnv * env,gss_buffer_t bytes)463 jstring getJavaString(JNIEnv *env, gss_buffer_t bytes) {
464   jstring result = NULL;
465   OM_uint32 minor;
466   int len;
467   jbyteArray jbytes;
468 
469   if (bytes != NULL) {
470     /* constructs the String object with new String(byte[])
471        NOTE: do NOT include the trailing NULL */
472     len = (int) bytes->length;
473     jbytes = (*env)->NewByteArray(env, len);
474     if (jbytes == NULL) {
475       goto finish;
476     }
477 
478     (*env)->SetByteArrayRegion(env, jbytes, 0, len, (jbyte *) bytes->value);
479     if ((*env)->ExceptionCheck(env)) {
480       goto finish;
481     }
482 
483     result = (*env)->NewObject(env, CLS_String, MID_String_ctor,
484                                jbytes);
485   finish:
486     (*env)->DeleteLocalRef(env, jbytes);
487     (*ftab->releaseBuffer)(&minor, bytes);
488     return result;
489   } /* else fall through */
490   return NULL;
491 }
492 /*
493  * Utility routine for generate message for the specified minor
494  * status code.
495  */
getMinorMessage(JNIEnv * env,jobject jstub,OM_uint32 statusValue)496 jstring getMinorMessage(JNIEnv *env, jobject jstub, OM_uint32 statusValue) {
497   OM_uint32 messageContext, minor, major;
498   gss_buffer_desc statusString;
499   gss_OID mech;
500 
501   messageContext = 0;
502   if (jstub != NULL) {
503     mech = (gss_OID) jlong_to_ptr((*env)->GetLongField(env, jstub, FID_GSSLibStub_pMech));
504   } else {
505     mech = GSS_C_NO_OID;
506   }
507 
508   /* gss_display_status(...) => GSS_S_BAD_MECH, GSS_S_BAD_STATUS */
509   // TBD: check messageContext value and repeat the call if necessary
510   major = (*ftab->displayStatus)(&minor, statusValue, GSS_C_MECH_CODE, mech,
511                                  &messageContext, &statusString);
512 
513   return getJavaString(env, &statusString);
514 }
515 
516 /*
517  * Utility routine checking the specified major and minor
518  * status codes. GSSExceptions will be thrown if they are
519  * not GSS_S_COMPLETE (i.e. 0).
520  */
checkStatus(JNIEnv * env,jobject jstub,OM_uint32 major,OM_uint32 minor,char * methodName)521 void checkStatus(JNIEnv *env, jobject jstub, OM_uint32 major,
522                  OM_uint32 minor, char* methodName) {
523   int callingErr, routineErr, supplementaryInfo;
524   jint jmajor, jminor;
525   char* msg;
526   jstring jmsg;
527   jthrowable gssEx;
528 
529   if (major == GSS_S_COMPLETE) return;
530 
531   callingErr = GSS_CALLING_ERROR(major);
532   routineErr = GSS_ROUTINE_ERROR(major);
533   supplementaryInfo = GSS_SUPPLEMENTARY_INFO(major);
534 
535   TRACE3("%s Status major/minor = %x/%d", methodName, major, minor);
536   TRACE3("c/r/s = %d/%d/%d ", callingErr>>24, routineErr>>16,
537           supplementaryInfo);
538 
539   jmajor = getJavaErrorCode(routineErr | supplementaryInfo);
540   jminor = minor;
541   if (jmajor != GSS_S_COMPLETE) {
542     jmsg = NULL;
543     if (minor != 0) {
544       jmsg = getMinorMessage(env, jstub, minor);
545       if ((*env)->ExceptionCheck(env)) {
546         return;
547       }
548     }
549 
550     gssEx = (*env)->NewObject(env, CLS_GSSException,
551                               MID_GSSException_ctor3,
552                               jmajor, jminor, jmsg);
553     if (gssEx != NULL) {
554       (*env)->Throw(env, gssEx);
555     }
556   } else {
557     /* Error in calling the GSS api */
558     if (callingErr == GSS_S_CALL_INACCESSIBLE_READ) {
559       msg = "A required input parameter cannot be read";
560     } else if (callingErr == GSS_S_CALL_INACCESSIBLE_WRITE) {
561       msg = "A required output parameter cannot be write";
562     } else {
563       msg = "A parameter was malformed";
564     }
565     jmajor = 13; /* use GSSException.FAILURE for now */
566     jmsg = (*env)->NewStringUTF(env, msg);
567     if (jmsg == NULL) {
568       return;
569     }
570     gssEx = (*env)->NewObject(env, CLS_GSSException,
571                               MID_GSSException_ctor3,
572                               jmajor, jminor, jmsg);
573     if (gssEx != NULL) {
574       (*env)->Throw(env, gssEx);
575     }
576   }
577 }
578 
579 /*
580  * Utility routine for initializing gss_buffer_t structure
581  * with the byte[] in the specified jbyteArray object.
582  * NOTE: must call resetGSSBuffer() to free up the resources
583  * inside the gss_buffer_t structure.
584  */
initGSSBuffer(JNIEnv * env,jbyteArray jbytes,gss_buffer_t cbytes)585 void initGSSBuffer(JNIEnv *env, jbyteArray jbytes,
586                      gss_buffer_t cbytes) {
587 
588   int len;
589   void* value;
590 
591   if (jbytes != NULL) {
592     len = (*env)->GetArrayLength(env, jbytes);
593     value = malloc(len);
594     if (value == NULL) {
595       throwOutOfMemoryError(env, NULL);
596       return;
597     } else {
598       (*env)->GetByteArrayRegion(env, jbytes, 0, len, value);
599       if ((*env)->ExceptionCheck(env)) {
600         free(value);
601         return;
602       } else {
603         cbytes->length = len;
604         cbytes->value = value;
605       }
606     }
607   } else {
608     cbytes->length = 0;
609     cbytes->value = NULL;
610   }
611 }
612 
613 /*
614  * Utility routine for freeing the bytes malloc'ed
615  * in initGSSBuffer() method.
616  * NOTE: used in conjunction with initGSSBuffer(...).
617  */
resetGSSBuffer(gss_buffer_t cbytes)618 void resetGSSBuffer(gss_buffer_t cbytes) {
619   if ((cbytes != NULL) && (cbytes != GSS_C_NO_BUFFER)) {
620     free(cbytes->value);
621     cbytes->length = 0;
622     cbytes->value = NULL;
623   }
624 }
625 
626 /*
627  * Utility routine for creating a jbyteArray object using
628  * the byte[] value in specified gss_buffer_t structure.
629  * NOTE: the specified gss_buffer_t structure is always
630  * released.
631  */
getJavaBuffer(JNIEnv * env,gss_buffer_t cbytes)632 jbyteArray getJavaBuffer(JNIEnv *env, gss_buffer_t cbytes) {
633   jbyteArray result = NULL;
634   OM_uint32 minor; // don't care, just so it compiles
635 
636   if (cbytes != NULL) {
637     if ((cbytes != GSS_C_NO_BUFFER) && (cbytes->length != 0)) {
638       result = (*env)->NewByteArray(env, (int) cbytes->length);
639       if (result == NULL) {
640         goto finish;
641       }
642       (*env)->SetByteArrayRegion(env, result, 0, (int) cbytes->length,
643                                  cbytes->value);
644       if ((*env)->ExceptionCheck(env)) {
645         result = NULL;
646       }
647     }
648   finish:
649     (*ftab->releaseBuffer)(&minor, cbytes);
650     return result;
651   }
652   return NULL;
653 }
654 
655 /*
656  * Utility routine for creating a non-mech gss_OID using
657  * the specified org.ietf.jgss.Oid object.
658  * NOTE: must call deleteGSSOID(...) to free up the gss_OID.
659  */
newGSSOID(JNIEnv * env,jobject jOid)660 gss_OID newGSSOID(JNIEnv *env, jobject jOid) {
661   jbyteArray jbytes;
662   gss_OID cOid;
663   if (jOid != NULL) {
664     jbytes = (*env)->CallObjectMethod(env, jOid, MID_Oid_getDER);
665     if ((*env)->ExceptionCheck(env)) {
666       return GSS_C_NO_OID;
667     }
668     cOid = malloc(sizeof(struct gss_OID_desc_struct));
669     if (cOid == NULL) {
670       throwOutOfMemoryError(env,NULL);
671       return GSS_C_NO_OID;
672     }
673     cOid->length = (*env)->GetArrayLength(env, jbytes) - 2;
674     cOid->elements = malloc(cOid->length);
675     if (cOid->elements == NULL) {
676       throwOutOfMemoryError(env,NULL);
677       goto cleanup;
678     }
679     (*env)->GetByteArrayRegion(env, jbytes, 2, cOid->length,
680                                cOid->elements);
681     if ((*env)->ExceptionCheck(env)) {
682       goto cleanup;
683     }
684     return cOid;
685   } else {
686     return GSS_C_NO_OID;
687   }
688   cleanup:
689     (*env)->DeleteLocalRef(env, jbytes);
690     free(cOid->elements);
691     free(cOid);
692     return GSS_C_NO_OID;
693 }
694 
695 /*
696  * Utility routine for releasing the specified gss_OID
697  * structure.
698  * NOTE: used in conjunction with newGSSOID(...).
699  */
deleteGSSOID(gss_OID oid)700 void deleteGSSOID(gss_OID oid) {
701   if (oid != GSS_C_NO_OID) {
702     free(oid->elements);
703     free(oid);
704   }
705 }
706 
707 /*
708  * Utility routine for creating a org.ietf.jgss.Oid
709  * object using the specified gss_OID structure.
710  */
getJavaOID(JNIEnv * env,gss_OID cOid)711 jobject getJavaOID(JNIEnv *env, gss_OID cOid) {
712   int cLen;
713   char oidHdr[2];
714   jbyteArray jbytes;
715   jobject result = NULL;
716 
717   if ((cOid == NULL) || (cOid == GSS_C_NO_OID)) {
718     return NULL;
719   }
720   cLen = cOid->length;
721   oidHdr[0] = 6;
722   oidHdr[1] = cLen;
723   jbytes = (*env)->NewByteArray(env, cLen+2);
724   if (jbytes == NULL) {
725     return NULL;
726   }
727   (*env)->SetByteArrayRegion(env, jbytes, 0, 2, (jbyte *) oidHdr);
728   if ((*env)->ExceptionCheck(env)) {
729     return NULL;
730   }
731   (*env)->SetByteArrayRegion(env, jbytes, 2, cLen, (jbyte *) cOid->elements);
732   if ((*env)->ExceptionCheck(env)) {
733     return NULL;
734   }
735   result = (*env)->NewObject(env, CLS_Oid, MID_Oid_ctor1, jbytes);
736   if ((*env)->ExceptionCheck(env)) {
737     return NULL;
738   }
739   (*env)->DeleteLocalRef(env, jbytes);
740   return result;
741 }
742 /*
743  * Utility routine for creating a gss_OID_set structure
744  * using the specified gss_OID.
745  * NOTE: need to call deleteGSSOIDSet(...) afterwards
746  * to release the created gss_OID_set structure.
747  */
newGSSOIDSet(gss_OID oid)748 gss_OID_set newGSSOIDSet(gss_OID oid) {
749   gss_OID_set oidSet;
750   OM_uint32 minor; // don't care; just so it compiles
751 
752   if (oid->length != 6 ||
753       memcmp(oid->elements, SPNEGO_BYTES, 6) != 0) {
754       (*ftab->createEmptyOidSet)(&minor, &oidSet);
755       (*ftab->addOidSetMember)(&minor, oid, &oidSet);
756       return oidSet;
757   } else {
758       // Use all mechs for SPNEGO in order to work with
759       // various native GSS impls
760       return (ftab->mechs);
761   }
762 }
763 /*
764  * Utility routine for releasing a gss_OID_set structure.
765  * NOTE: used in conjunction with newGSSOIDSet(...).
766  */
deleteGSSOIDSet(gss_OID_set oidSet)767 void deleteGSSOIDSet(gss_OID_set oidSet) {
768   OM_uint32 minor; /* don't care; just so it compiles */
769 
770   if ((oidSet != ftab->mechs) &&
771       (oidSet != NULL) && (oidSet != GSS_C_NO_OID_SET)) {
772     (*ftab->releaseOidSet)(&minor, &oidSet);
773   }
774 }
775 /*
776  * Utility routine for creating a org.ietf.jgss.Oid[]
777  * using the specified gss_OID_set structure.
778  */
getJavaOIDArray(JNIEnv * env,gss_OID_set cOidSet)779 jobjectArray getJavaOIDArray(JNIEnv *env, gss_OID_set cOidSet) {
780   int numOfOids = 0;
781   jobjectArray jOidSet;
782   jobject jOid;
783   int i;
784 
785   if (cOidSet != NULL && cOidSet != GSS_C_NO_OID_SET) {
786     numOfOids = (int) cOidSet->count;
787     jOidSet = (*env)->NewObjectArray(env, numOfOids, CLS_Oid, NULL);
788     if ((*env)->ExceptionCheck(env)) {
789       return NULL;
790     }
791     for (i = 0; i < numOfOids; i++) {
792       jOid = getJavaOID(env, &(cOidSet->elements[i]));
793       if ((*env)->ExceptionCheck(env)) {
794         return NULL;
795       }
796       (*env)->SetObjectArrayElement(env, jOidSet, i, jOid);
797       if ((*env)->ExceptionCheck(env)) {
798         return NULL;
799       }
800       (*env)->DeleteLocalRef(env, jOid);
801     }
802     return jOidSet;
803   }
804   return NULL;
805 }
806 
sameMech(gss_OID mech,gss_OID mech2)807 int sameMech(gss_OID mech, gss_OID mech2) {
808   int result = JNI_FALSE; // default to not equal
809 
810   if (mech->length == mech2->length) {
811     result = (memcmp(mech->elements, mech2->elements, mech->length) == 0);
812   }
813   return result;
814 }
815