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