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 
  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
  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
 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  */
 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  */
 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  */
 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 */
 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 
 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  */
 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 = 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  */
 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   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  */
 522 void 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  */
 586 void 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  */
 619 void 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  */
 633 jbyteArray 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  */
 661 gss_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  */
 702 void 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  */
 713 jobject 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  */
 750 gss_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  */
 769 void 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  */
 781 jobjectArray 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 
 810 int 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 }