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 }