1 /*
   2  * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
   6  *
   7  * Redistribution and use in  source and binary forms, with or without
   8  * modification, are permitted  provided that the following conditions are met:
   9  *
  10  * 1. Redistributions of  source code must retain the above copyright notice,
  11  *    this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in  binary form must reproduce the above copyright notice,
  14  *    this list of conditions and the following disclaimer in the documentation
  15  *    and/or other materials provided with the distribution.
  16  *
  17  * 3. The end-user documentation included with the redistribution, if any, must
  18  *    include the following acknowledgment:
  19  *
  20  *    "This product includes software developed by IAIK of Graz University of
  21  *     Technology."
  22  *
  23  *    Alternately, this acknowledgment may appear in the software itself, if
  24  *    and wherever such third-party acknowledgments normally appear.
  25  *
  26  * 4. The names "Graz University of Technology" and "IAIK of Graz University of
  27  *    Technology" must not be used to endorse or promote products derived from
  28  *    this software without prior written permission.
  29  *
  30  * 5. Products derived from this software may not be called
  31  *    "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
  32  *    written permission of Graz University of Technology.
  33  *
  34  *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  35  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  36  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
  38  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  39  *  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  41  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  42  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  43  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  44  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  45  *  POSSIBILITY  OF SUCH DAMAGE.
  46  */
  47 
  48 #include "pkcs11wrapper.h"
  49 
  50 #include <stdio.h>
  51 #include <stdlib.h>
  52 #include <string.h>
  53 #include <assert.h>
  54 
  55 #include "sun_security_pkcs11_wrapper_PKCS11.h"
  56 
  57 /* The initArgs that enable the application to do custom mutex-handling */
  58 #ifndef NO_CALLBACKS
  59 jobject jInitArgsObject;
  60 CK_C_INITIALIZE_ARGS_PTR ckpGlobalInitArgs;
  61 #endif /* NO_CALLBACKS */
  62 
  63 /* ************************************************************************** */
  64 /* Now come the functions for mutex handling and notification callbacks       */
  65 /* ************************************************************************** */
  66 
  67 /*
  68  * converts the InitArgs object to a CK_C_INITIALIZE_ARGS structure and sets the functions
  69  * that will call the right Java mutex functions
  70  *
  71  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
  72  * @param pInitArgs - the InitArgs object with the Java mutex functions to call
  73  * @return - the pointer to the CK_C_INITIALIZE_ARGS structure with the functions that will call
  74  *           the corresponding Java functions
  75  */
  76 CK_C_INITIALIZE_ARGS_PTR makeCKInitArgsAdapter(JNIEnv *env, jobject jInitArgs)
  77 {
  78     CK_C_INITIALIZE_ARGS_PTR ckpInitArgs;
  79     jclass jInitArgsClass;
  80     jfieldID fieldID;
  81     jlong jFlags;
  82     jobject jReserved;
  83     CK_ULONG ckReservedLength;
  84 #ifndef NO_CALLBACKS
  85     jobject jMutexHandler;
  86 #endif /* NO_CALLBACKS */
  87 
  88     if(jInitArgs == NULL) {
  89         return NULL_PTR;
  90     }
  91 
  92     /* convert the Java InitArgs object to a pointer to a CK_C_INITIALIZE_ARGS structure */
  93     ckpInitArgs = (CK_C_INITIALIZE_ARGS_PTR) malloc(sizeof(CK_C_INITIALIZE_ARGS));
  94     if (ckpInitArgs == NULL) {
  95         throwOutOfMemoryError(env, 0);
  96         return NULL_PTR;
  97     }
  98     ckpInitArgs->flags = (CK_FLAGS)0;
  99     ckpInitArgs->pReserved = (CK_VOID_PTR)NULL;
 100 
 101     /* Set the mutex functions that will call the Java mutex functions, but
 102      * only set it, if the field is not null.
 103      */
 104     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 105     if (jInitArgsClass == NULL) {
 106         free(ckpInitArgs);
 107         return NULL;
 108     }
 109 
 110 #ifdef NO_CALLBACKS
 111     ckpInitArgs->CreateMutex = NULL_PTR;
 112     ckpInitArgs->DestroyMutex = NULL_PTR;
 113     ckpInitArgs->LockMutex = NULL_PTR;
 114     ckpInitArgs->UnlockMutex = NULL_PTR;
 115 #else
 116     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;");
 117     if (fieldID == NULL) {
 118         free(ckpInitArgs);
 119         return NULL;
 120     }
 121     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 122     ckpInitArgs->CreateMutex = (jMutexHandler != NULL) ? &callJCreateMutex : NULL_PTR;
 123 
 124     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;");
 125     if (fieldID == NULL) {
 126         free(ckpInitArgs);
 127         return NULL;
 128     }
 129     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 130     ckpInitArgs->DestroyMutex = (jMutexHandler != NULL) ? &callJDestroyMutex : NULL_PTR;
 131 
 132     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;");
 133     if (fieldID == NULL) {
 134         free(ckpInitArgs);
 135         return NULL;
 136     }
 137     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 138     ckpInitArgs->LockMutex = (jMutexHandler != NULL) ? &callJLockMutex : NULL_PTR;
 139 
 140     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;");
 141     if (fieldID == NULL) {
 142         free(ckpInitArgs);
 143         return NULL;
 144     }
 145     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 146     ckpInitArgs->UnlockMutex = (jMutexHandler != NULL) ? &callJUnlockMutex : NULL_PTR;
 147 
 148     if ((ckpInitArgs->CreateMutex != NULL_PTR)
 149             || (ckpInitArgs->DestroyMutex != NULL_PTR)
 150             || (ckpInitArgs->LockMutex != NULL_PTR)
 151             || (ckpInitArgs->UnlockMutex != NULL_PTR)) {
 152         /* we only need to keep a global copy, if we need callbacks */
 153         /* set the global object jInitArgs so that the right Java mutex functions will be called */
 154         jInitArgsObject = (*env)->NewGlobalRef(env, jInitArgs);
 155         ckpGlobalInitArgs = (CK_C_INITIALIZE_ARGS_PTR) malloc(sizeof(CK_C_INITIALIZE_ARGS));
 156         if (ckpGlobalInitArgs == NULL) {
 157             free(ckpInitArgs);
 158             throwOutOfMemoryError(env, 0);
 159             return NULL_PTR;
 160         }
 161 
 162         memcpy(ckpGlobalInitArgs, ckpInitArgs, sizeof(CK_C_INITIALIZE_ARGS));
 163     }
 164 #endif /* NO_CALLBACKS */
 165 
 166     /* convert and set the flags field */
 167     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "flags", "J");
 168     if (fieldID == NULL) {
 169         free(ckpInitArgs);
 170         return NULL;
 171     }
 172     jFlags = (*env)->GetLongField(env, jInitArgs, fieldID);
 173     ckpInitArgs->flags = jLongToCKULong(jFlags);
 174 
 175     /* pReserved should be NULL_PTR in this version */
 176     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "pReserved", "Ljava/lang/Object;");
 177     if (fieldID == NULL) {
 178         free(ckpInitArgs);
 179         return NULL;
 180     }
 181     jReserved = (*env)->GetObjectField(env, jInitArgs, fieldID);
 182 
 183     /* we try to convert the reserved parameter also */
 184     jObjectToPrimitiveCKObjectPtrPtr(env, jReserved, &(ckpInitArgs->pReserved), &ckReservedLength);
 185 
 186     return ckpInitArgs ;
 187 }
 188 
 189 #ifndef NO_CALLBACKS
 190 
 191 /*
 192  * is the function that gets called by PKCS#11 to create a mutex and calls the Java
 193  * CreateMutex function
 194  *
 195  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 196  * @param ppMutex - the new created mutex
 197  * @return - should return CKR_OK if the mutex creation was ok
 198  */
 199 CK_RV callJCreateMutex(CK_VOID_PTR_PTR ppMutex)
 200 {
 201     extern JavaVM *jvm;
 202     JNIEnv *env;
 203     jint returnValue;
 204     jthrowable pkcs11Exception;
 205     jclass pkcs11ExceptionClass;
 206     jlong errorCode;
 207     CK_RV rv = CKR_OK;
 208     int wasAttached = 1;
 209     jclass jCreateMutexClass;
 210     jclass jInitArgsClass;
 211     jmethodID methodID;
 212     jfieldID fieldID;
 213     jobject jCreateMutex;
 214     jobject jMutex;
 215 
 216 
 217     /* Get the currently running Java VM */
 218     if (jvm == NULL) { return rv ;} /* there is no VM running */
 219 
 220     /* Determine, if current thread is already attached */
 221     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 222     if (returnValue == JNI_EDETACHED) {
 223         /* thread detached, so attach it */
 224         wasAttached = 0;
 225         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 226     } else if (returnValue == JNI_EVERSION) {
 227         /* this version of JNI is not supported, so just try to attach */
 228         /* we assume it was attached to ensure that this thread is not detached
 229          * afterwards even though it should not
 230          */
 231         wasAttached = 1;
 232         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 233     } else {
 234         /* attached */
 235         wasAttached = 1;
 236     }
 237 
 238     jCreateMutexClass = (*env)->FindClass(env, CLASS_CREATEMUTEX);
 239     if (jCreateMutexClass == NULL) { return rv; }
 240     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 241     if (jInitArgsClass == NULL) { return rv; }
 242 
 243     /* get the CreateMutex object out of the jInitArgs object */
 244     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;");
 245     if (fieldID == NULL) { return rv; }
 246     jCreateMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 247     assert(jCreateMutex != 0);
 248 
 249     /* call the CK_CREATEMUTEX function of the CreateMutex object */
 250     /* and get the new Java mutex object */
 251     methodID = (*env)->GetMethodID(env, jCreateMutexClass, "CK_CREATEMUTEX", "()Ljava/lang/Object;");
 252     if (methodID == NULL) { return rv; }
 253     jMutex = (*env)->CallObjectMethod(env, jCreateMutex, methodID);
 254 
 255     /* set a global reference on the Java mutex */
 256     jMutex = (*env)->NewGlobalRef(env, jMutex);
 257     /* convert the Java mutex to a CK mutex */
 258     *ppMutex = jObjectToCKVoidPtr(jMutex);
 259 
 260 
 261     /* check, if callback threw an exception */
 262     pkcs11Exception = (*env)->ExceptionOccurred(env);
 263 
 264     if (pkcs11Exception != NULL) {
 265         /* TBD: clear the pending exception with ExceptionClear? */
 266         /* The was an exception thrown, now we get the error-code from it */
 267         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 268         if (pkcs11ExceptionClass == NULL) { return rv; }
 269         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 270         if (methodID == NULL) { return rv; }
 271 
 272         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 273         rv = jLongToCKULong(errorCode);
 274     }
 275 
 276     /* if we attached this thread to the VM just for callback, we detach it now */
 277     if (wasAttached) {
 278         returnValue = (*jvm)->DetachCurrentThread(jvm);
 279     }
 280 
 281     return rv ;
 282 }
 283 
 284 /*
 285  * is the function that gets called by PKCS#11 to destroy a mutex and calls the Java
 286  * DestroyMutex function
 287  *
 288  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 289  * @param pMutex - the mutex to destroy
 290  * @return - should return CKR_OK if the mutex was destroyed
 291  */
 292 CK_RV callJDestroyMutex(CK_VOID_PTR pMutex)
 293 {
 294     extern JavaVM *jvm;
 295     JNIEnv *env;
 296     jint returnValue;
 297     jthrowable pkcs11Exception;
 298     jclass pkcs11ExceptionClass;
 299     jlong errorCode;
 300     CK_RV rv = CKR_OK;
 301     int wasAttached = 1;
 302     jclass jDestroyMutexClass;
 303     jclass jInitArgsClass;
 304     jmethodID methodID;
 305     jfieldID fieldID;
 306     jobject jDestroyMutex;
 307     jobject jMutex;
 308 
 309 
 310     /* Get the currently running Java VM */
 311     if (jvm == NULL) { return rv ; } /* there is no VM running */
 312 
 313     /* Determine, if current thread is already attached */
 314     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 315     if (returnValue == JNI_EDETACHED) {
 316         /* thread detached, so attach it */
 317         wasAttached = 0;
 318         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 319     } else if (returnValue == JNI_EVERSION) {
 320         /* this version of JNI is not supported, so just try to attach */
 321         /* we assume it was attached to ensure that this thread is not detached
 322          * afterwards even though it should not
 323          */
 324         wasAttached = 1;
 325         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 326     } else {
 327         /* attached */
 328         wasAttached = 1;
 329     }
 330 
 331     jDestroyMutexClass = (*env)->FindClass(env, CLASS_DESTROYMUTEX);
 332     if (jDestroyMutexClass == NULL) { return rv; }
 333     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 334     if (jInitArgsClass == NULL) { return rv; }
 335 
 336     /* convert the CK mutex to a Java mutex */
 337     jMutex = ckVoidPtrToJObject(pMutex);
 338 
 339     /* get the DestroyMutex object out of the jInitArgs object */
 340     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;");
 341     if (fieldID == NULL) { return rv; }
 342     jDestroyMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 343     assert(jDestroyMutex != 0);
 344 
 345     /* call the CK_DESTROYMUTEX method of the DestroyMutex object */
 346     methodID = (*env)->GetMethodID(env, jDestroyMutexClass, "CK_DESTROYMUTEX", "(Ljava/lang/Object;)V");
 347     if (methodID == NULL) { return rv; }
 348     (*env)->CallVoidMethod(env, jDestroyMutex, methodID, jMutex);
 349 
 350     /* delete the global reference on the Java mutex */
 351     (*env)->DeleteGlobalRef(env, jMutex);
 352 
 353 
 354     /* check, if callback threw an exception */
 355     pkcs11Exception = (*env)->ExceptionOccurred(env);
 356 
 357     if (pkcs11Exception != NULL) {
 358         /* TBD: clear the pending exception with ExceptionClear? */
 359         /* The was an exception thrown, now we get the error-code from it */
 360         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 361         if (pkcs11ExceptionClass == NULL) { return rv; }
 362         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 363         if (methodID == NULL) { return rv; }
 364         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 365         rv = jLongToCKULong(errorCode);
 366     }
 367 
 368     /* if we attached this thread to the VM just for callback, we detach it now */
 369     if (wasAttached) {
 370         returnValue = (*jvm)->DetachCurrentThread(jvm);
 371     }
 372 
 373     return rv ;
 374 }
 375 
 376 /*
 377  * is the function that gets called by PKCS#11 to lock a mutex and calls the Java
 378  * LockMutex function
 379  *
 380  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 381  * @param pMutex - the mutex to lock
 382  * @return - should return CKR_OK if the mutex was not locked already
 383  */
 384 CK_RV callJLockMutex(CK_VOID_PTR pMutex)
 385 {
 386     extern JavaVM *jvm;
 387     JNIEnv *env;
 388     jint returnValue;
 389     jthrowable pkcs11Exception;
 390     jclass pkcs11ExceptionClass;
 391     jlong errorCode;
 392     CK_RV rv = CKR_OK;
 393     int wasAttached = 1;
 394     jclass jLockMutexClass;
 395     jclass jInitArgsClass;
 396     jmethodID methodID;
 397     jfieldID fieldID;
 398     jobject jLockMutex;
 399     jobject jMutex;
 400 
 401 
 402     /* Get the currently running Java VM */
 403     if (jvm == NULL) { return rv ; } /* there is no VM running */
 404 
 405     /* Determine, if current thread is already attached */
 406     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 407     if (returnValue == JNI_EDETACHED) {
 408         /* thread detached, so attach it */
 409         wasAttached = 0;
 410         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 411     } else if (returnValue == JNI_EVERSION) {
 412         /* this version of JNI is not supported, so just try to attach */
 413         /* we assume it was attached to ensure that this thread is not detached
 414          * afterwards even though it should not
 415          */
 416         wasAttached = 1;
 417         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 418     } else {
 419         /* attached */
 420         wasAttached = 1;
 421     }
 422 
 423     jLockMutexClass = (*env)->FindClass(env, CLASS_LOCKMUTEX);
 424     if (jLockMutexClass == NULL) { return rv; }
 425     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 426     if (jInitArgsClass == NULL) { return rv; }
 427 
 428     /* convert the CK mutex to a Java mutex */
 429     jMutex = ckVoidPtrToJObject(pMutex);
 430 
 431     /* get the LockMutex object out of the jInitArgs object */
 432     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;");
 433     if (fieldID == NULL) { return rv; }
 434     jLockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 435     assert(jLockMutex != 0);
 436 
 437     /* call the CK_LOCKMUTEX method of the LockMutex object */
 438     methodID = (*env)->GetMethodID(env, jLockMutexClass, "CK_LOCKMUTEX", "(Ljava/lang/Object;)V");
 439     if (methodID == NULL) { return rv; }
 440     (*env)->CallVoidMethod(env, jLockMutex, methodID, jMutex);
 441 
 442     /* check, if callback threw an exception */
 443     pkcs11Exception = (*env)->ExceptionOccurred(env);
 444 
 445     if (pkcs11Exception != NULL) {
 446         /* TBD: clear the pending exception with ExceptionClear? */
 447         /* The was an exception thrown, now we get the error-code from it */
 448         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 449         if (pkcs11ExceptionClass == NULL) { return rv; }
 450         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 451         if (methodID == NULL) { return rv; }
 452         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 453         rv = jLongToCKULong(errorCode);
 454     }
 455 
 456     /* if we attached this thread to the VM just for callback, we detach it now */
 457     if (wasAttached) {
 458         returnValue = (*jvm)->DetachCurrentThread(jvm);
 459     }
 460 
 461     return rv ;
 462 }
 463 
 464 /*
 465  * is the function that gets called by PKCS#11 to unlock a mutex and calls the Java
 466  * UnlockMutex function
 467  *
 468  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 469  * @param pMutex - the mutex to unlock
 470  * @return - should return CKR_OK if the mutex was not unlocked already
 471  */
 472 CK_RV callJUnlockMutex(CK_VOID_PTR pMutex)
 473 {
 474     extern JavaVM *jvm;
 475     JNIEnv *env;
 476     jint returnValue;
 477     jthrowable pkcs11Exception;
 478     jclass pkcs11ExceptionClass;
 479     jlong errorCode;
 480     CK_RV rv = CKR_OK;
 481     int wasAttached = 1;
 482     jclass jUnlockMutexClass;
 483     jclass jInitArgsClass;
 484     jmethodID methodID;
 485     jfieldID fieldID;
 486     jobject jUnlockMutex;
 487     jobject jMutex;
 488 
 489 
 490     /* Get the currently running Java VM */
 491     if (jvm == NULL) { return rv ; } /* there is no VM running */
 492 
 493     /* Determine, if current thread is already attached */
 494     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 495     if (returnValue == JNI_EDETACHED) {
 496         /* thread detached, so attach it */
 497         wasAttached = 0;
 498         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 499     } else if (returnValue == JNI_EVERSION) {
 500         /* this version of JNI is not supported, so just try to attach */
 501         /* we assume it was attached to ensure that this thread is not detached
 502          * afterwards even though it should not
 503          */
 504         wasAttached = 1;
 505         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 506     } else {
 507         /* attached */
 508         wasAttached = 1;
 509     }
 510 
 511     jUnlockMutexClass = (*env)->FindClass(env, CLASS_UNLOCKMUTEX);
 512     if (jUnlockMutexClass == NULL) { return rv; }
 513     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 514     if (jInitArgsClass == NULL) { return rv; }
 515 
 516     /* convert the CK-type mutex to a Java mutex */
 517     jMutex = ckVoidPtrToJObject(pMutex);
 518 
 519     /* get the UnlockMutex object out of the jInitArgs object */
 520     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;");
 521     if (fieldID == NULL) { return rv; }
 522     jUnlockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 523     assert(jUnlockMutex != 0);
 524 
 525     /* call the CK_UNLOCKMUTEX method of the UnLockMutex object */
 526     methodID = (*env)->GetMethodID(env, jUnlockMutexClass, "CK_UNLOCKMUTEX", "(Ljava/lang/Object;)V");
 527     if (methodID == NULL) { return rv; }
 528     (*env)->CallVoidMethod(env, jUnlockMutex, methodID, jMutex);
 529 
 530     /* check, if callback threw an exception */
 531     pkcs11Exception = (*env)->ExceptionOccurred(env);
 532 
 533     if (pkcs11Exception != NULL) {
 534         /* TBD: clear the pending exception with ExceptionClear? */
 535         /* The was an exception thrown, now we get the error-code from it */
 536         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 537         if (pkcs11ExceptionClass == NULL) { return rv; }
 538         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 539         if (methodID == NULL) { return rv; }
 540         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 541         rv = jLongToCKULong(errorCode);
 542     }
 543 
 544     /* if we attached this thread to the VM just for callback, we detach it now */
 545     if (wasAttached) {
 546         returnValue = (*jvm)->DetachCurrentThread(jvm);
 547     }
 548 
 549     return rv ;
 550 }
 551 
 552 #endif /* NO_CALLBACKS */