| /* |
| * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #include "NativeUtil.h" |
| #include "NativeFunc.h" |
| #include "jlong.h" |
| #include <jni.h> |
| #include "jni_util.h" |
| |
| const int JAVA_DUPLICATE_TOKEN_CODE = 19; /* DUPLICATE_TOKEN */ |
| const int JAVA_OLD_TOKEN_CODE = 20; /* OLD_TOKEN */ |
| const int JAVA_UNSEQ_TOKEN_CODE = 21; /* UNSEQ_TOKEN */ |
| const int JAVA_GAP_TOKEN_CODE = 22; /* GAP_TOKEN */ |
| const int JAVA_ERROR_CODE[] = { |
| 2, /* BAD_MECH */ |
| 3, /* BAD_NAME */ |
| 4, /* BAD_NAMETYPE */ |
| 1, /* BAD_BINDINGS */ |
| 5, /* BAD_STATUS */ |
| 6, /* BAD_MIC */ |
| 13, /* NO_CRED */ |
| 12, /* NO_CONTEXT */ |
| 10, /* DEFECTIVE_TOKEN */ |
| 9, /* DEFECTIVE_CREDENTIAL */ |
| 8, /* CREDENTIAL_EXPIRED */ |
| 7, /* CONTEXT_EXPIRED */ |
| 11, /* FAILURE */ |
| 14, /* BAD_QOP */ |
| 15, /* UNAUTHORIZED */ |
| 16, /* UNAVAILABLE */ |
| 17, /* DUPLICATE_ELEMENT */ |
| 18, /* NAME_NOT_MN */ |
| }; |
| const char SPNEGO_BYTES[] = { |
| 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 |
| }; |
| |
| jclass CLS_Object; |
| jclass CLS_String; |
| jclass CLS_Oid; |
| jclass CLS_GSSException; |
| jclass CLS_GSSNameElement; |
| jclass CLS_GSSCredElement; |
| jclass CLS_NativeGSSContext; |
| jclass CLS_SunNativeProvider; |
| jmethodID MID_String_ctor; |
| jmethodID MID_Oid_ctor1; |
| jmethodID MID_Oid_getDER; |
| jmethodID MID_MessageProp_getPrivacy; |
| jmethodID MID_MessageProp_getQOP; |
| jmethodID MID_MessageProp_setPrivacy; |
| jmethodID MID_MessageProp_setQOP; |
| jmethodID MID_MessageProp_setSupplementaryStates; |
| jmethodID MID_GSSException_ctor3; |
| jmethodID MID_ChannelBinding_getInitiatorAddr; |
| jmethodID MID_ChannelBinding_getAcceptorAddr; |
| jmethodID MID_ChannelBinding_getAppData; |
| jmethodID MID_InetAddress_getAddr; |
| jmethodID MID_GSSNameElement_ctor; |
| jmethodID MID_GSSCredElement_ctor; |
| jmethodID MID_NativeGSSContext_ctor; |
| jfieldID FID_GSSLibStub_pMech; |
| jfieldID FID_NativeGSSContext_pContext; |
| jfieldID FID_NativeGSSContext_srcName; |
| jfieldID FID_NativeGSSContext_targetName; |
| jfieldID FID_NativeGSSContext_isInitiator; |
| jfieldID FID_NativeGSSContext_isEstablished; |
| jfieldID FID_NativeGSSContext_delegatedCred; |
| jfieldID FID_NativeGSSContext_flags; |
| jfieldID FID_NativeGSSContext_lifetime; |
| jfieldID FID_NativeGSSContext_actualMech; |
| |
| int JGSS_DEBUG; |
| |
| JNIEXPORT jint JNICALL |
| DEF_JNI_OnLoad(JavaVM *jvm, void *reserved) { |
| JNIEnv *env; |
| jclass cls; |
| |
| if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) { |
| return JNI_EVERSION; /* JNI version not supported */ |
| } |
| /* Retrieve and store the classes in global ref */ |
| cls = (*env)->FindClass(env, "java/lang/Object"); |
| if (cls == NULL) { |
| printf("Couldn't find Object class\n"); |
| return JNI_ERR; |
| } |
| CLS_Object = (*env)->NewGlobalRef(env, cls); |
| if (CLS_Object == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "java/lang/String"); |
| if (cls == NULL) { |
| printf("Couldn't find String class\n"); |
| return JNI_ERR; |
| } |
| CLS_String = (*env)->NewGlobalRef(env, cls); |
| if (CLS_String == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "org/ietf/jgss/Oid"); |
| if (cls == NULL) { |
| printf("Couldn't find org.ietf.jgss.Oid class\n"); |
| return JNI_ERR; |
| } |
| CLS_Oid = (*env)->NewGlobalRef(env, cls); |
| if (CLS_Oid == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "org/ietf/jgss/GSSException"); |
| if (cls == NULL) { |
| printf("Couldn't find org.ietf.jgss.GSSException class\n"); |
| return JNI_ERR; |
| } |
| CLS_GSSException = (*env)->NewGlobalRef(env, cls); |
| if (CLS_GSSException == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSNameElement"); |
| if (cls == NULL) { |
| printf("Couldn't find sun.security.jgss.wrapper.GSSNameElement class\n"); |
| return JNI_ERR; |
| } |
| CLS_GSSNameElement = (*env)->NewGlobalRef(env, cls); |
| if (CLS_GSSException == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSCredElement"); |
| if (cls == NULL) { |
| printf("Couldn't find sun.security.jgss.wrapper.GSSCredElement class\n"); |
| return JNI_ERR; |
| } |
| CLS_GSSCredElement = (*env)->NewGlobalRef(env, cls); |
| if (CLS_GSSCredElement == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/NativeGSSContext"); |
| if (cls == NULL) { |
| printf("Couldn't find sun.security.jgss.wrapper.NativeGSSContext class\n"); |
| return JNI_ERR; |
| } |
| CLS_NativeGSSContext = (*env)->NewGlobalRef(env, cls); |
| if (CLS_NativeGSSContext == NULL) { |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/SunNativeProvider"); |
| if (cls == NULL) { |
| printf("Couldn't find sun.security.jgss.wrapper.SunNativeProvider class\n"); |
| return JNI_ERR; |
| } |
| CLS_SunNativeProvider = (*env)->NewGlobalRef(env, cls); |
| if (CLS_SunNativeProvider == NULL) { |
| return JNI_ERR; |
| } |
| /* Compute and cache the method ID */ |
| MID_String_ctor = (*env)->GetMethodID(env, CLS_String, |
| "<init>", "([B)V"); |
| if (MID_String_ctor == NULL) { |
| printf("Couldn't find String(byte[]) constructor\n"); |
| return JNI_ERR; |
| } |
| MID_Oid_ctor1 = |
| (*env)->GetMethodID(env, CLS_Oid, "<init>", "([B)V"); |
| if (MID_Oid_ctor1 == NULL) { |
| printf("Couldn't find Oid(byte[]) constructor\n"); |
| return JNI_ERR; |
| } |
| MID_Oid_getDER = (*env)->GetMethodID(env, CLS_Oid, "getDER", "()[B"); |
| if (MID_Oid_getDER == NULL) { |
| printf("Couldn't find Oid.getDER() method\n"); |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "org/ietf/jgss/MessageProp"); |
| if (cls == NULL) { |
| printf("Couldn't find org.ietf.jgss.MessageProp class\n"); |
| return JNI_ERR; |
| } |
| MID_MessageProp_getPrivacy = |
| (*env)->GetMethodID(env, cls, "getPrivacy", "()Z"); |
| if (MID_MessageProp_getPrivacy == NULL) { |
| printf("Couldn't find MessageProp.getPrivacy() method\n"); |
| return JNI_ERR; |
| } |
| MID_MessageProp_getQOP = (*env)->GetMethodID(env, cls, "getQOP", "()I"); |
| if (MID_MessageProp_getQOP == NULL) { |
| printf("Couldn't find MessageProp.getQOP() method\n"); |
| return JNI_ERR; |
| } |
| MID_MessageProp_setPrivacy = |
| (*env)->GetMethodID(env, cls, "setPrivacy", "(Z)V"); |
| if (MID_MessageProp_setPrivacy == NULL) { |
| printf("Couldn't find MessageProp.setPrivacy(boolean) method\n"); |
| return JNI_ERR; |
| } |
| MID_MessageProp_setQOP = (*env)->GetMethodID(env, cls, "setQOP", "(I)V"); |
| if (MID_MessageProp_setQOP == NULL) { |
| printf("Couldn't find MessageProp.setQOP(int) method\n"); |
| return JNI_ERR; |
| } |
| MID_MessageProp_setSupplementaryStates = |
| (*env)->GetMethodID(env, cls, "setSupplementaryStates", |
| "(ZZZZILjava/lang/String;)V"); |
| if (MID_MessageProp_setSupplementaryStates == NULL) { |
| printf("Couldn't find MessageProp.setSupplementaryStates(...) method\n"); |
| return JNI_ERR; |
| } |
| MID_GSSException_ctor3 = (*env)->GetMethodID |
| (env, CLS_GSSException, "<init>", "(IILjava/lang/String;)V"); |
| if (MID_GSSException_ctor3 == NULL) { |
| printf("Couldn't find GSSException(int, int, String) constructor\n"); |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "org/ietf/jgss/ChannelBinding"); |
| if (cls == NULL) { |
| printf("Couldn't find org.ietf.jgss.ChannelBinding class\n"); |
| return JNI_ERR; |
| } |
| MID_ChannelBinding_getInitiatorAddr = |
| (*env)->GetMethodID(env, cls, "getInitiatorAddress", |
| "()Ljava/net/InetAddress;"); |
| if (MID_ChannelBinding_getInitiatorAddr == NULL) { |
| printf("Couldn't find ChannelBinding.getInitiatorAddress() method\n"); |
| return JNI_ERR; |
| } |
| MID_ChannelBinding_getAcceptorAddr = |
| (*env)->GetMethodID(env, cls, "getAcceptorAddress", |
| "()Ljava/net/InetAddress;"); |
| if (MID_ChannelBinding_getAcceptorAddr == NULL) { |
| printf("Couldn't find ChannelBinding.getAcceptorAddress() method\n"); |
| return JNI_ERR; |
| } |
| MID_ChannelBinding_getAppData = |
| (*env)->GetMethodID(env, cls, "getApplicationData", "()[B"); |
| if (MID_ChannelBinding_getAppData == NULL) { |
| printf("Couldn't find ChannelBinding.getApplicationData() method\n"); |
| return JNI_ERR; |
| } |
| cls = (*env)->FindClass(env, "java/net/InetAddress"); |
| if (cls == NULL) { |
| printf("Couldn't find java.net.InetAddress class\n"); |
| return JNI_ERR; |
| } |
| MID_InetAddress_getAddr = (*env)->GetMethodID(env, cls, "getAddress", |
| "()[B"); |
| if (MID_InetAddress_getAddr == NULL) { |
| printf("Couldn't find InetAddress.getAddress() method\n"); |
| return JNI_ERR; |
| } |
| MID_GSSNameElement_ctor = |
| (*env)->GetMethodID(env, CLS_GSSNameElement, |
| "<init>", "(JLsun/security/jgss/wrapper/GSSLibStub;)V"); |
| if (MID_GSSNameElement_ctor == NULL) { |
| printf("Couldn't find GSSNameElement(long, GSSLibStub) constructor\n"); |
| return JNI_ERR; |
| } |
| MID_GSSCredElement_ctor = |
| (*env)->GetMethodID(env, CLS_GSSCredElement, "<init>", |
| "(JLsun/security/jgss/wrapper/GSSNameElement;Lorg/ietf/jgss/Oid;)V"); |
| if (MID_GSSCredElement_ctor == NULL) { |
| printf("Couldn't find GSSCredElement(long, GSSLibStub) constructor\n"); |
| return JNI_ERR; |
| } |
| MID_NativeGSSContext_ctor = |
| (*env)->GetMethodID(env, CLS_NativeGSSContext, "<init>", |
| "(JLsun/security/jgss/wrapper/GSSLibStub;)V"); |
| if (MID_NativeGSSContext_ctor == NULL) { |
| printf("Couldn't find NativeGSSContext(long, GSSLibStub) constructor\n"); |
| return JNI_ERR; |
| } |
| /* Compute and cache the field ID */ |
| cls = (*env)->FindClass(env, "sun/security/jgss/wrapper/GSSLibStub"); |
| if (cls == NULL) { |
| printf("Couldn't find sun.security.jgss.wrapper.GSSLibStub class\n"); |
| return JNI_ERR; |
| } |
| FID_GSSLibStub_pMech = |
| (*env)->GetFieldID(env, cls, "pMech", "J"); |
| if (FID_GSSLibStub_pMech == NULL) { |
| printf("Couldn't find GSSLibStub.pMech field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_pContext = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "pContext", "J"); |
| if (FID_NativeGSSContext_pContext == NULL) { |
| printf("Couldn't find NativeGSSContext.pContext field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_srcName = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "srcName", |
| "Lsun/security/jgss/wrapper/GSSNameElement;"); |
| if (FID_NativeGSSContext_srcName == NULL) { |
| printf("Couldn't find NativeGSSContext.srcName field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_targetName = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "targetName", |
| "Lsun/security/jgss/wrapper/GSSNameElement;"); |
| if (FID_NativeGSSContext_targetName == NULL) { |
| printf("Couldn't find NativeGSSContext.targetName field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_isInitiator = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "isInitiator", "Z"); |
| if (FID_NativeGSSContext_isInitiator == NULL) { |
| printf("Couldn't find NativeGSSContext.isInitiator field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_isEstablished = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "isEstablished", "Z"); |
| if (FID_NativeGSSContext_isEstablished == NULL) { |
| printf("Couldn't find NativeGSSContext.isEstablished field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_delegatedCred = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "delegatedCred", |
| "Lsun/security/jgss/wrapper/GSSCredElement;"); |
| if (FID_NativeGSSContext_delegatedCred == NULL) { |
| printf("Couldn't find NativeGSSContext.delegatedCred field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_flags = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "flags", "I"); |
| if (FID_NativeGSSContext_flags == NULL) { |
| printf("Couldn't find NativeGSSContext.flags field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_lifetime = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "lifetime", "I"); |
| if (FID_NativeGSSContext_lifetime == NULL) { |
| printf("Couldn't find NativeGSSContext.lifetime field\n"); |
| return JNI_ERR; |
| } |
| FID_NativeGSSContext_actualMech = |
| (*env)->GetFieldID(env, CLS_NativeGSSContext, "actualMech", |
| "Lorg/ietf/jgss/Oid;"); |
| if (FID_NativeGSSContext_actualMech == NULL) { |
| printf("Couldn't find NativeGSSContext.actualMech field\n"); |
| return JNI_ERR; |
| } |
| return JNI_VERSION_1_2; |
| } |
| |
| JNIEXPORT void JNICALL |
| DEF_JNI_OnUnload(JavaVM *jvm, void *reserved) { |
| JNIEnv *env; |
| |
| if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) { |
| return; |
| } |
| /* Delete the global refs */ |
| (*env)->DeleteGlobalRef(env, CLS_Object); |
| (*env)->DeleteGlobalRef(env, CLS_String); |
| (*env)->DeleteGlobalRef(env, CLS_Oid); |
| (*env)->DeleteGlobalRef(env, CLS_GSSException); |
| (*env)->DeleteGlobalRef(env, CLS_GSSNameElement); |
| (*env)->DeleteGlobalRef(env, CLS_GSSCredElement); |
| (*env)->DeleteGlobalRef(env, CLS_SunNativeProvider); |
| return; |
| } |
| |
| const OM_uint32 JAVA_MAX = GSS_C_INDEFINITE/2; |
| |
| /* |
| * Utility routine for converting the C unsigned integer time |
| * to Java signed integer time. |
| */ |
| jint getJavaTime(OM_uint32 ctime) { |
| jint result; |
| |
| /* special handle values equals or more than JAVA_MAX */ |
| if (ctime == GSS_C_INDEFINITE) { |
| result = JAVA_MAX; |
| } else if (ctime >= JAVA_MAX) { |
| result = JAVA_MAX-1; |
| } else { |
| result = ctime; |
| } |
| return result; |
| } |
| /* |
| * Utility routine for converting the Java signed integer time |
| * to C unsigned integer time. |
| */ |
| OM_uint32 getGSSTime(jint jtime) { |
| OM_uint32 result; |
| |
| /* special handle values equal to JAVA_MAX */ |
| if (jtime == (jint)JAVA_MAX) { |
| result = GSS_C_INDEFINITE; |
| } else { |
| result = jtime; |
| } |
| return result; |
| } |
| /* |
| * Utility routine for mapping the C error code to the |
| * Java one. The routine errors really should have |
| * shared the same values but unfortunately don't. |
| */ |
| jint getJavaErrorCode(int cNonCallingErr) { |
| int cRoutineErr, cSuppStatus; |
| /* map the routine errors */ |
| cRoutineErr = GSS_ROUTINE_ERROR(cNonCallingErr) >> 16; |
| if (cRoutineErr != GSS_S_COMPLETE) { |
| return JAVA_ERROR_CODE[cRoutineErr-1]; |
| } |
| /* map the supplementary infos */ |
| cSuppStatus = GSS_SUPPLEMENTARY_INFO(cNonCallingErr); |
| if (cSuppStatus & GSS_S_DUPLICATE_TOKEN) { |
| return JAVA_DUPLICATE_TOKEN_CODE; |
| } else if (cSuppStatus & GSS_S_OLD_TOKEN) { |
| return JAVA_OLD_TOKEN_CODE; |
| } else if (cSuppStatus & GSS_S_UNSEQ_TOKEN) { |
| return JAVA_UNSEQ_TOKEN_CODE; |
| } else if (cSuppStatus & GSS_S_GAP_TOKEN) { |
| return JAVA_GAP_TOKEN_CODE; |
| } |
| return GSS_S_COMPLETE; |
| } |
| |
| |
| /* Throws a Java Exception by name */ |
| void throwByName(JNIEnv *env, const char *name, const char *msg) { |
| jclass cls = (*env)->FindClass(env, name); |
| |
| if (cls != NULL) { |
| (*env)->ThrowNew(env, cls, msg); |
| } |
| } |
| |
| void throwOutOfMemoryError(JNIEnv *env, const char *message) { |
| throwByName(env, "java/lang/OutOfMemoryError", message); |
| } |
| |
| /* |
| * Utility routine for creating a java.lang.String object |
| * using the specified gss_buffer_t structure. The specified |
| * gss_buffer_t structure is always released. |
| */ |
| jstring getJavaString(JNIEnv *env, gss_buffer_t bytes) { |
| jstring result = NULL; |
| OM_uint32 minor; |
| int len; |
| jbyteArray jbytes; |
| |
| if (bytes != NULL) { |
| /* constructs the String object with new String(byte[]) |
| NOTE: do NOT include the trailing NULL */ |
| len = bytes->length; |
| jbytes = (*env)->NewByteArray(env, len); |
| if (jbytes == NULL) { |
| goto finish; |
| } |
| |
| (*env)->SetByteArrayRegion(env, jbytes, 0, len, (jbyte *) bytes->value); |
| if ((*env)->ExceptionCheck(env)) { |
| goto finish; |
| } |
| |
| result = (*env)->NewObject(env, CLS_String, MID_String_ctor, |
| jbytes); |
| finish: |
| (*env)->DeleteLocalRef(env, jbytes); |
| (*ftab->releaseBuffer)(&minor, bytes); |
| return result; |
| } /* else fall through */ |
| return NULL; |
| } |
| /* |
| * Utility routine for generate message for the specified minor |
| * status code. |
| */ |
| jstring getMinorMessage(JNIEnv *env, jobject jstub, OM_uint32 statusValue) { |
| OM_uint32 messageContext, minor, major; |
| gss_buffer_desc statusString; |
| gss_OID mech; |
| jstring msg; |
| |
| messageContext = 0; |
| if (jstub != NULL) { |
| mech = (gss_OID) jlong_to_ptr((*env)->GetLongField(env, jstub, FID_GSSLibStub_pMech)); |
| } else { |
| mech = GSS_C_NO_OID; |
| } |
| |
| /* gss_display_status(...) => GSS_S_BAD_MECH, GSS_S_BAD_STATUS */ |
| // TBD: check messageContext value and repeat the call if necessary |
| major = (*ftab->displayStatus)(&minor, statusValue, GSS_C_MECH_CODE, mech, |
| &messageContext, &statusString); |
| |
| return getJavaString(env, &statusString); |
| } |
| |
| /* |
| * Utility routine checking the specified major and minor |
| * status codes. GSSExceptions will be thrown if they are |
| * not GSS_S_COMPLETE (i.e. 0). |
| */ |
| void checkStatus(JNIEnv *env, jobject jstub, OM_uint32 major, |
| OM_uint32 minor, char* methodName) { |
| int callingErr, routineErr, supplementaryInfo; |
| jint jmajor, jminor; |
| char* msg; |
| jstring jmsg; |
| jthrowable gssEx; |
| |
| if (major == GSS_S_COMPLETE) return; |
| |
| callingErr = GSS_CALLING_ERROR(major); |
| routineErr = GSS_ROUTINE_ERROR(major); |
| supplementaryInfo = GSS_SUPPLEMENTARY_INFO(major); |
| |
| TRACE3("%s Status major/minor = %x/%d", methodName, major, minor); |
| TRACE3("c/r/s = %d/%d/%d ", callingErr>>24, routineErr>>16, |
| supplementaryInfo); |
| |
| jmajor = getJavaErrorCode(routineErr | supplementaryInfo); |
| jminor = minor; |
| if (jmajor != GSS_S_COMPLETE) { |
| jmsg = NULL; |
| if (minor != 0) { |
| jmsg = getMinorMessage(env, jstub, minor); |
| if ((*env)->ExceptionCheck(env)) { |
| return; |
| } |
| } |
| |
| gssEx = (*env)->NewObject(env, CLS_GSSException, |
| MID_GSSException_ctor3, |
| jmajor, jminor, jmsg); |
| if (gssEx != NULL) { |
| (*env)->Throw(env, gssEx); |
| } |
| } else { |
| /* Error in calling the GSS api */ |
| if (callingErr == GSS_S_CALL_INACCESSIBLE_READ) { |
| msg = "A required input parameter cannot be read"; |
| } else if (callingErr == GSS_S_CALL_INACCESSIBLE_WRITE) { |
| msg = "A required output parameter cannot be write"; |
| } else { |
| msg = "A parameter was malformed"; |
| } |
| jmajor = 13; /* use GSSException.FAILURE for now */ |
| jmsg = (*env)->NewStringUTF(env, msg); |
| if (jmsg == NULL) { |
| return; |
| } |
| gssEx = (*env)->NewObject(env, CLS_GSSException, |
| MID_GSSException_ctor3, |
| jmajor, jminor, jmsg); |
| if (gssEx != NULL) { |
| (*env)->Throw(env, gssEx); |
| } |
| } |
| } |
| |
| /* |
| * Utility routine for initializing gss_buffer_t structure |
| * with the byte[] in the specified jbyteArray object. |
| * NOTE: must call resetGSSBuffer() to free up the resources |
| * inside the gss_buffer_t structure. |
| */ |
| void initGSSBuffer(JNIEnv *env, jbyteArray jbytes, |
| gss_buffer_t cbytes) { |
| |
| int len; |
| void* value; |
| |
| if (jbytes != NULL) { |
| len = (*env)->GetArrayLength(env, jbytes); |
| value = malloc(len); |
| if (value == NULL) { |
| throwOutOfMemoryError(env, NULL); |
| return; |
| } else { |
| (*env)->GetByteArrayRegion(env, jbytes, 0, len, value); |
| if ((*env)->ExceptionCheck(env)) { |
| free(value); |
| return; |
| } else { |
| cbytes->length = len; |
| cbytes->value = value; |
| } |
| } |
| } else { |
| cbytes->length = 0; |
| cbytes->value = NULL; |
| } |
| } |
| |
| /* |
| * Utility routine for freeing the bytes malloc'ed |
| * in initGSSBuffer() method. |
| * NOTE: used in conjunction with initGSSBuffer(...). |
| */ |
| void resetGSSBuffer(gss_buffer_t cbytes) { |
| if ((cbytes != NULL) && (cbytes != GSS_C_NO_BUFFER)) { |
| free(cbytes->value); |
| cbytes->length = 0; |
| cbytes->value = NULL; |
| } |
| } |
| |
| /* |
| * Utility routine for creating a jbyteArray object using |
| * the byte[] value in specified gss_buffer_t structure. |
| * NOTE: the specified gss_buffer_t structure is always |
| * released. |
| */ |
| jbyteArray getJavaBuffer(JNIEnv *env, gss_buffer_t cbytes) { |
| jbyteArray result = NULL; |
| OM_uint32 minor; // don't care, just so it compiles |
| |
| if (cbytes != NULL) { |
| if ((cbytes != GSS_C_NO_BUFFER) && (cbytes->length != 0)) { |
| result = (*env)->NewByteArray(env, cbytes->length); |
| if (result == NULL) { |
| goto finish; |
| } |
| (*env)->SetByteArrayRegion(env, result, 0, cbytes->length, |
| cbytes->value); |
| if ((*env)->ExceptionCheck(env)) { |
| result = NULL; |
| } |
| } |
| finish: |
| (*ftab->releaseBuffer)(&minor, cbytes); |
| return result; |
| } |
| return NULL; |
| } |
| |
| /* |
| * Utility routine for creating a non-mech gss_OID using |
| * the specified org.ietf.jgss.Oid object. |
| * NOTE: must call deleteGSSOID(...) to free up the gss_OID. |
| */ |
| gss_OID newGSSOID(JNIEnv *env, jobject jOid) { |
| jbyteArray jbytes; |
| gss_OID cOid; |
| jthrowable gssEx; |
| if (jOid != NULL) { |
| jbytes = (*env)->CallObjectMethod(env, jOid, MID_Oid_getDER); |
| if ((*env)->ExceptionCheck(env)) { |
| return GSS_C_NO_OID; |
| } |
| cOid = malloc(sizeof(struct gss_OID_desc_struct)); |
| if (cOid == NULL) { |
| throwOutOfMemoryError(env,NULL); |
| return GSS_C_NO_OID; |
| } |
| cOid->length = (*env)->GetArrayLength(env, jbytes) - 2; |
| cOid->elements = malloc(cOid->length); |
| if (cOid->elements == NULL) { |
| throwOutOfMemoryError(env,NULL); |
| goto cleanup; |
| } |
| (*env)->GetByteArrayRegion(env, jbytes, 2, cOid->length, |
| cOid->elements); |
| if ((*env)->ExceptionCheck(env)) { |
| goto cleanup; |
| } |
| return cOid; |
| } else { |
| return GSS_C_NO_OID; |
| } |
| cleanup: |
| (*env)->DeleteLocalRef(env, jbytes); |
| free(cOid->elements); |
| free(cOid); |
| return GSS_C_NO_OID; |
| } |
| |
| /* |
| * Utility routine for releasing the specified gss_OID |
| * structure. |
| * NOTE: used in conjunction with newGSSOID(...). |
| */ |
| void deleteGSSOID(gss_OID oid) { |
| if (oid != GSS_C_NO_OID) { |
| free(oid->elements); |
| free(oid); |
| } |
| } |
| |
| /* |
| * Utility routine for creating a org.ietf.jgss.Oid |
| * object using the specified gss_OID structure. |
| */ |
| jobject getJavaOID(JNIEnv *env, gss_OID cOid) { |
| int cLen; |
| char oidHdr[2]; |
| jbyteArray jbytes; |
| jobject result = NULL; |
| |
| if ((cOid == NULL) || (cOid == GSS_C_NO_OID)) { |
| return NULL; |
| } |
| cLen = cOid->length; |
| oidHdr[0] = 6; |
| oidHdr[1] = cLen; |
| jbytes = (*env)->NewByteArray(env, cLen+2); |
| if (jbytes == NULL) { |
| return NULL; |
| } |
| (*env)->SetByteArrayRegion(env, jbytes, 0, 2, (jbyte *) oidHdr); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| (*env)->SetByteArrayRegion(env, jbytes, 2, cLen, (jbyte *) cOid->elements); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| result = (*env)->NewObject(env, CLS_Oid, MID_Oid_ctor1, jbytes); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| (*env)->DeleteLocalRef(env, jbytes); |
| return result; |
| } |
| /* |
| * Utility routine for creating a gss_OID_set structure |
| * using the specified gss_OID. |
| * NOTE: need to call deleteGSSOIDSet(...) afterwards |
| * to release the created gss_OID_set structure. |
| */ |
| gss_OID_set newGSSOIDSet(gss_OID oid) { |
| gss_OID_set oidSet; |
| OM_uint32 minor; // don't care; just so it compiles |
| |
| if (oid->length != 6 || |
| memcmp(oid->elements, SPNEGO_BYTES, 6) != 0) { |
| (*ftab->createEmptyOidSet)(&minor, &oidSet); |
| (*ftab->addOidSetMember)(&minor, oid, &oidSet); |
| return oidSet; |
| } else { |
| // Use all mechs for SPNEGO in order to work with |
| // various native GSS impls |
| return (ftab->mechs); |
| } |
| } |
| /* |
| * Utility routine for releasing a gss_OID_set structure. |
| * NOTE: used in conjunction with newGSSOIDSet(...). |
| */ |
| void deleteGSSOIDSet(gss_OID_set oidSet) { |
| OM_uint32 minor; /* don't care; just so it compiles */ |
| |
| if ((oidSet != ftab->mechs) && |
| (oidSet != NULL) && (oidSet != GSS_C_NO_OID_SET)) { |
| (*ftab->releaseOidSet)(&minor, &oidSet); |
| } |
| } |
| /* |
| * Utility routine for creating a org.ietf.jgss.Oid[] |
| * using the specified gss_OID_set structure. |
| */ |
| jobjectArray getJavaOIDArray(JNIEnv *env, gss_OID_set cOidSet) { |
| int numOfOids = 0; |
| jobjectArray jOidSet; |
| jobject jOid; |
| int i; |
| jthrowable gssEx; |
| |
| if (cOidSet != NULL && cOidSet != GSS_C_NO_OID_SET) { |
| numOfOids = cOidSet->count; |
| jOidSet = (*env)->NewObjectArray(env, numOfOids, CLS_Oid, NULL); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| for (i = 0; i < numOfOids; i++) { |
| jOid = getJavaOID(env, &(cOidSet->elements[i])); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| (*env)->SetObjectArrayElement(env, jOidSet, i, jOid); |
| if ((*env)->ExceptionCheck(env)) { |
| return NULL; |
| } |
| (*env)->DeleteLocalRef(env, jOid); |
| } |
| return jOidSet; |
| } |
| return NULL; |
| } |
| |
| int sameMech(gss_OID mech, gss_OID mech2) { |
| int result = JNI_FALSE; // default to not equal |
| |
| if (mech->length == mech2->length) { |
| result = (memcmp(mech->elements, mech2->elements, mech->length) == 0); |
| } |
| return result; |
| } |