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 }