1/*
2 * Copyright (c) 2005, 2015, 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
32const int JAVA_DUPLICATE_TOKEN_CODE = 19; /* DUPLICATE_TOKEN */
33const int JAVA_OLD_TOKEN_CODE = 20; /* OLD_TOKEN */
34const int JAVA_UNSEQ_TOKEN_CODE = 21; /* UNSEQ_TOKEN */
35const int JAVA_GAP_TOKEN_CODE = 22; /* GAP_TOKEN */
36const 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};
56const char SPNEGO_BYTES[] = {
57 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
58};
59
60jclass CLS_Object;
61jclass CLS_String;
62jclass CLS_Oid;
63jclass CLS_GSSException;
64jclass CLS_GSSNameElement;
65jclass CLS_GSSCredElement;
66jclass CLS_NativeGSSContext;
67jclass CLS_SunNativeProvider;
68jmethodID MID_String_ctor;
69jmethodID MID_Oid_ctor1;
70jmethodID MID_Oid_getDER;
71jmethodID MID_MessageProp_getPrivacy;
72jmethodID MID_MessageProp_getQOP;
73jmethodID MID_MessageProp_setPrivacy;
74jmethodID MID_MessageProp_setQOP;
75jmethodID MID_MessageProp_setSupplementaryStates;
76jmethodID MID_GSSException_ctor3;
77jmethodID MID_ChannelBinding_getInitiatorAddr;
78jmethodID MID_ChannelBinding_getAcceptorAddr;
79jmethodID MID_ChannelBinding_getAppData;
80jmethodID MID_InetAddress_getAddr;
81jmethodID MID_GSSNameElement_ctor;
82jmethodID MID_GSSCredElement_ctor;
83jmethodID MID_NativeGSSContext_ctor;
84jfieldID FID_GSSLibStub_pMech;
85jfieldID FID_NativeGSSContext_pContext;
86jfieldID FID_NativeGSSContext_srcName;
87jfieldID FID_NativeGSSContext_targetName;
88jfieldID FID_NativeGSSContext_isInitiator;
89jfieldID FID_NativeGSSContext_isEstablished;
90jfieldID FID_NativeGSSContext_delegatedCred;
91jfieldID FID_NativeGSSContext_flags;
92jfieldID FID_NativeGSSContext_lifetime;
93jfieldID FID_NativeGSSContext_actualMech;
94
95int JGSS_DEBUG;
96
97JNIEXPORT jint JNICALL
98DEF_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
366JNIEXPORT void JNICALL
367DEF_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
384const 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 */
390jint 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 */
407OM_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 */
423jint 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 */
446void 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
454void 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 */
463jstring 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 = 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 */
496jstring getMinorMessage(JNIEnv *env, jobject jstub, OM_uint32 statusValue) {
497  OM_uint32 messageContext, minor, major;
498  gss_buffer_desc statusString;
499  gss_OID mech;
500  jstring msg;
501
502  messageContext = 0;
503  if (jstub != NULL) {
504    mech = (gss_OID) jlong_to_ptr((*env)->GetLongField(env, jstub, FID_GSSLibStub_pMech));
505  } else {
506    mech = GSS_C_NO_OID;
507  }
508
509  /* gss_display_status(...) => GSS_S_BAD_MECH, GSS_S_BAD_STATUS */
510  // TBD: check messageContext value and repeat the call if necessary
511  major = (*ftab->displayStatus)(&minor, statusValue, GSS_C_MECH_CODE, mech,
512                                 &messageContext, &statusString);
513
514  return getJavaString(env, &statusString);
515}
516
517/*
518 * Utility routine checking the specified major and minor
519 * status codes. GSSExceptions will be thrown if they are
520 * not GSS_S_COMPLETE (i.e. 0).
521 */
522void checkStatus(JNIEnv *env, jobject jstub, OM_uint32 major,
523                 OM_uint32 minor, char* methodName) {
524  int callingErr, routineErr, supplementaryInfo;
525  jint jmajor, jminor;
526  char* msg;
527  jstring jmsg;
528  jthrowable gssEx;
529
530  if (major == GSS_S_COMPLETE) return;
531
532  callingErr = GSS_CALLING_ERROR(major);
533  routineErr = GSS_ROUTINE_ERROR(major);
534  supplementaryInfo = GSS_SUPPLEMENTARY_INFO(major);
535
536  TRACE3("%s Status major/minor = %x/%d", methodName, major, minor);
537  TRACE3("c/r/s = %d/%d/%d ", callingErr>>24, routineErr>>16,
538          supplementaryInfo);
539
540  jmajor = getJavaErrorCode(routineErr | supplementaryInfo);
541  jminor = minor;
542  if (jmajor != GSS_S_COMPLETE) {
543    jmsg = NULL;
544    if (minor != 0) {
545      jmsg = getMinorMessage(env, jstub, minor);
546      if ((*env)->ExceptionCheck(env)) {
547        return;
548      }
549    }
550
551    gssEx = (*env)->NewObject(env, CLS_GSSException,
552                              MID_GSSException_ctor3,
553                              jmajor, jminor, jmsg);
554    if (gssEx != NULL) {
555      (*env)->Throw(env, gssEx);
556    }
557  } else {
558    /* Error in calling the GSS api */
559    if (callingErr == GSS_S_CALL_INACCESSIBLE_READ) {
560      msg = "A required input parameter cannot be read";
561    } else if (callingErr == GSS_S_CALL_INACCESSIBLE_WRITE) {
562      msg = "A required output parameter cannot be write";
563    } else {
564      msg = "A parameter was malformed";
565    }
566    jmajor = 13; /* use GSSException.FAILURE for now */
567    jmsg = (*env)->NewStringUTF(env, msg);
568    if (jmsg == NULL) {
569      return;
570    }
571    gssEx = (*env)->NewObject(env, CLS_GSSException,
572                              MID_GSSException_ctor3,
573                              jmajor, jminor, jmsg);
574    if (gssEx != NULL) {
575      (*env)->Throw(env, gssEx);
576    }
577  }
578}
579
580/*
581 * Utility routine for initializing gss_buffer_t structure
582 * with the byte[] in the specified jbyteArray object.
583 * NOTE: must call resetGSSBuffer() to free up the resources
584 * inside the gss_buffer_t structure.
585 */
586void initGSSBuffer(JNIEnv *env, jbyteArray jbytes,
587                     gss_buffer_t cbytes) {
588
589  int len;
590  void* value;
591
592  if (jbytes != NULL) {
593    len = (*env)->GetArrayLength(env, jbytes);
594    value = malloc(len);
595    if (value == NULL) {
596      throwOutOfMemoryError(env, NULL);
597      return;
598    } else {
599      (*env)->GetByteArrayRegion(env, jbytes, 0, len, value);
600      if ((*env)->ExceptionCheck(env)) {
601        free(value);
602        return;
603      } else {
604        cbytes->length = len;
605        cbytes->value = value;
606      }
607    }
608  } else {
609    cbytes->length = 0;
610    cbytes->value = NULL;
611  }
612}
613
614/*
615 * Utility routine for freeing the bytes malloc'ed
616 * in initGSSBuffer() method.
617 * NOTE: used in conjunction with initGSSBuffer(...).
618 */
619void resetGSSBuffer(gss_buffer_t cbytes) {
620  if ((cbytes != NULL) && (cbytes != GSS_C_NO_BUFFER)) {
621    free(cbytes->value);
622    cbytes->length = 0;
623    cbytes->value = NULL;
624  }
625}
626
627/*
628 * Utility routine for creating a jbyteArray object using
629 * the byte[] value in specified gss_buffer_t structure.
630 * NOTE: the specified gss_buffer_t structure is always
631 * released.
632 */
633jbyteArray getJavaBuffer(JNIEnv *env, gss_buffer_t cbytes) {
634  jbyteArray result = NULL;
635  OM_uint32 minor; // don't care, just so it compiles
636
637  if (cbytes != NULL) {
638    if ((cbytes != GSS_C_NO_BUFFER) && (cbytes->length != 0)) {
639      result = (*env)->NewByteArray(env, cbytes->length);
640      if (result == NULL) {
641        goto finish;
642      }
643      (*env)->SetByteArrayRegion(env, result, 0, cbytes->length,
644                                 cbytes->value);
645      if ((*env)->ExceptionCheck(env)) {
646        result = NULL;
647      }
648    }
649  finish:
650    (*ftab->releaseBuffer)(&minor, cbytes);
651    return result;
652  }
653  return NULL;
654}
655
656/*
657 * Utility routine for creating a non-mech gss_OID using
658 * the specified org.ietf.jgss.Oid object.
659 * NOTE: must call deleteGSSOID(...) to free up the gss_OID.
660 */
661gss_OID newGSSOID(JNIEnv *env, jobject jOid) {
662  jbyteArray jbytes;
663  gss_OID cOid;
664  jthrowable gssEx;
665  if (jOid != NULL) {
666    jbytes = (*env)->CallObjectMethod(env, jOid, MID_Oid_getDER);
667    if ((*env)->ExceptionCheck(env)) {
668      return GSS_C_NO_OID;
669    }
670    cOid = malloc(sizeof(struct gss_OID_desc_struct));
671    if (cOid == NULL) {
672      throwOutOfMemoryError(env,NULL);
673      return GSS_C_NO_OID;
674    }
675    cOid->length = (*env)->GetArrayLength(env, jbytes) - 2;
676    cOid->elements = malloc(cOid->length);
677    if (cOid->elements == NULL) {
678      throwOutOfMemoryError(env,NULL);
679      goto cleanup;
680    }
681    (*env)->GetByteArrayRegion(env, jbytes, 2, cOid->length,
682                               cOid->elements);
683    if ((*env)->ExceptionCheck(env)) {
684      goto cleanup;
685    }
686    return cOid;
687  } else {
688    return GSS_C_NO_OID;
689  }
690  cleanup:
691    (*env)->DeleteLocalRef(env, jbytes);
692    free(cOid->elements);
693    free(cOid);
694    return GSS_C_NO_OID;
695}
696
697/*
698 * Utility routine for releasing the specified gss_OID
699 * structure.
700 * NOTE: used in conjunction with newGSSOID(...).
701 */
702void deleteGSSOID(gss_OID oid) {
703  if (oid != GSS_C_NO_OID) {
704    free(oid->elements);
705    free(oid);
706  }
707}
708
709/*
710 * Utility routine for creating a org.ietf.jgss.Oid
711 * object using the specified gss_OID structure.
712 */
713jobject getJavaOID(JNIEnv *env, gss_OID cOid) {
714  int cLen;
715  char oidHdr[2];
716  jbyteArray jbytes;
717  jobject result = NULL;
718
719  if ((cOid == NULL) || (cOid == GSS_C_NO_OID)) {
720    return NULL;
721  }
722  cLen = cOid->length;
723  oidHdr[0] = 6;
724  oidHdr[1] = cLen;
725  jbytes = (*env)->NewByteArray(env, cLen+2);
726  if (jbytes == NULL) {
727    return NULL;
728  }
729  (*env)->SetByteArrayRegion(env, jbytes, 0, 2, (jbyte *) oidHdr);
730  if ((*env)->ExceptionCheck(env)) {
731    return NULL;
732  }
733  (*env)->SetByteArrayRegion(env, jbytes, 2, cLen, (jbyte *) cOid->elements);
734  if ((*env)->ExceptionCheck(env)) {
735    return NULL;
736  }
737  result = (*env)->NewObject(env, CLS_Oid, MID_Oid_ctor1, jbytes);
738  if ((*env)->ExceptionCheck(env)) {
739    return NULL;
740  }
741  (*env)->DeleteLocalRef(env, jbytes);
742  return result;
743}
744/*
745 * Utility routine for creating a gss_OID_set structure
746 * using the specified gss_OID.
747 * NOTE: need to call deleteGSSOIDSet(...) afterwards
748 * to release the created gss_OID_set structure.
749 */
750gss_OID_set newGSSOIDSet(gss_OID oid) {
751  gss_OID_set oidSet;
752  OM_uint32 minor; // don't care; just so it compiles
753
754  if (oid->length != 6 ||
755      memcmp(oid->elements, SPNEGO_BYTES, 6) != 0) {
756      (*ftab->createEmptyOidSet)(&minor, &oidSet);
757      (*ftab->addOidSetMember)(&minor, oid, &oidSet);
758      return oidSet;
759  } else {
760      // Use all mechs for SPNEGO in order to work with
761      // various native GSS impls
762      return (ftab->mechs);
763  }
764}
765/*
766 * Utility routine for releasing a gss_OID_set structure.
767 * NOTE: used in conjunction with newGSSOIDSet(...).
768 */
769void deleteGSSOIDSet(gss_OID_set oidSet) {
770  OM_uint32 minor; /* don't care; just so it compiles */
771
772  if ((oidSet != ftab->mechs) &&
773      (oidSet != NULL) && (oidSet != GSS_C_NO_OID_SET)) {
774    (*ftab->releaseOidSet)(&minor, &oidSet);
775  }
776}
777/*
778 * Utility routine for creating a org.ietf.jgss.Oid[]
779 * using the specified gss_OID_set structure.
780 */
781jobjectArray getJavaOIDArray(JNIEnv *env, gss_OID_set cOidSet) {
782  int numOfOids = 0;
783  jobjectArray jOidSet;
784  jobject jOid;
785  int i;
786  jthrowable gssEx;
787
788  if (cOidSet != NULL && cOidSet != GSS_C_NO_OID_SET) {
789    numOfOids = cOidSet->count;
790    jOidSet = (*env)->NewObjectArray(env, numOfOids, CLS_Oid, NULL);
791    if ((*env)->ExceptionCheck(env)) {
792      return NULL;
793    }
794    for (i = 0; i < numOfOids; i++) {
795      jOid = getJavaOID(env, &(cOidSet->elements[i]));
796      if ((*env)->ExceptionCheck(env)) {
797        return NULL;
798      }
799      (*env)->SetObjectArrayElement(env, jOidSet, i, jOid);
800      if ((*env)->ExceptionCheck(env)) {
801        return NULL;
802      }
803      (*env)->DeleteLocalRef(env, jOid);
804    }
805    return jOidSet;
806  }
807  return NULL;
808}
809
810int sameMech(gss_OID mech, gss_OID mech2) {
811  int result = JNI_FALSE; // default to not equal
812
813  if (mech->length == mech2->length) {
814    result = (memcmp(mech->elements, mech2->elements, mech->length) == 0);
815  }
816  return result;
817}
818