1 /*
   2  * Copyright (c) 2003, 2012, 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 
  99     /* Set the mutex functions that will call the Java mutex functions, but
 100      * only set it, if the field is not null.
 101      */
 102     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 103     if (jInitArgsClass == NULL) {
 104         free(ckpInitArgs);
 105         return NULL;
 106     }
 107 
 108 #ifdef NO_CALLBACKS
 109     ckpInitArgs->CreateMutex = NULL_PTR;
 110     ckpInitArgs->DestroyMutex = NULL_PTR;
 111     ckpInitArgs->LockMutex = NULL_PTR;
 112     ckpInitArgs->UnlockMutex = NULL_PTR;
 113 #else
 114     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;");
 115     if (fieldID == NULL) {
 116         free(ckpInitArgs);
 117         return NULL;
 118     }
 119     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 120     ckpInitArgs->CreateMutex = (jMutexHandler != NULL) ? &callJCreateMutex : NULL_PTR;
 121 
 122     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;");
 123     if (fieldID == NULL) {
 124         free(ckpInitArgs);
 125         return NULL;
 126     }
 127     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 128     ckpInitArgs->DestroyMutex = (jMutexHandler != NULL) ? &callJDestroyMutex : NULL_PTR;
 129 
 130     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;");
 131     if (fieldID == NULL) {
 132         free(ckpInitArgs);
 133         return NULL;
 134     }
 135     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 136     ckpInitArgs->LockMutex = (jMutexHandler != NULL) ? &callJLockMutex : NULL_PTR;
 137 
 138     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;");
 139     if (fieldID == NULL) {
 140         free(ckpInitArgs);
 141         return NULL;
 142     }
 143     jMutexHandler = (*env)->GetObjectField(env, jInitArgs, fieldID);
 144     ckpInitArgs->UnlockMutex = (jMutexHandler != NULL) ? &callJUnlockMutex : NULL_PTR;
 145 
 146     if ((ckpInitArgs->CreateMutex != NULL_PTR)
 147             || (ckpInitArgs->DestroyMutex != NULL_PTR)
 148             || (ckpInitArgs->LockMutex != NULL_PTR)
 149             || (ckpInitArgs->UnlockMutex != NULL_PTR)) {
 150         /* we only need to keep a global copy, if we need callbacks */
 151         /* set the global object jInitArgs so that the right Java mutex functions will be called */
 152         jInitArgsObject = (*env)->NewGlobalRef(env, jInitArgs);
 153         ckpGlobalInitArgs = (CK_C_INITIALIZE_ARGS_PTR) malloc(sizeof(CK_C_INITIALIZE_ARGS));
 154         if (ckpGlobalInitArgs == NULL) {
 155             free(ckpInitArgs);
 156             throwOutOfMemoryError(env, 0);
 157             return NULL_PTR;
 158         }
 159 
 160         memcpy(ckpGlobalInitArgs, ckpInitArgs, sizeof(CK_C_INITIALIZE_ARGS));
 161     }
 162 #endif /* NO_CALLBACKS */
 163 
 164     /* convert and set the flags field */
 165     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "flags", "J");
 166     if (fieldID == NULL) {
 167         free(ckpInitArgs);
 168         return NULL;
 169     }
 170     jFlags = (*env)->GetLongField(env, jInitArgs, fieldID);
 171     ckpInitArgs->flags = jLongToCKULong(jFlags);
 172 
 173     /* pReserved should be NULL_PTR in this version */
 174     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "pReserved", "Ljava/lang/Object;");
 175     if (fieldID == NULL) {
 176         free(ckpInitArgs);
 177         return NULL;
 178     }
 179     jReserved = (*env)->GetObjectField(env, jInitArgs, fieldID);
 180 
 181     /* we try to convert the reserved parameter also */
 182     jObjectToPrimitiveCKObjectPtrPtr(env, jReserved, &(ckpInitArgs->pReserved), &ckReservedLength);
 183 
 184     return ckpInitArgs ;
 185 }
 186 
 187 #ifndef NO_CALLBACKS
 188 
 189 /*
 190  * is the function that gets called by PKCS#11 to create a mutex and calls the Java
 191  * CreateMutex function
 192  *
 193  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 194  * @param ppMutex - the new created mutex
 195  * @return - should return CKR_OK if the mutex creation was ok
 196  */
 197 CK_RV callJCreateMutex(CK_VOID_PTR_PTR ppMutex)
 198 {
 199     extern JavaVM *jvm;
 200     JNIEnv *env;
 201     jint returnValue;
 202     jthrowable pkcs11Exception;
 203     jclass pkcs11ExceptionClass;
 204     jlong errorCode;
 205     CK_RV rv = CKR_OK;
 206     int wasAttached = 1;
 207     jclass jCreateMutexClass;
 208     jclass jInitArgsClass;
 209     jmethodID methodID;
 210     jfieldID fieldID;
 211     jobject jCreateMutex;
 212     jobject jMutex;
 213 
 214 
 215     /* Get the currently running Java VM */
 216     if (jvm == NULL) { return rv ;} /* there is no VM running */
 217 
 218     /* Determine, if current thread is already attached */
 219     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 220     if (returnValue == JNI_EDETACHED) {
 221         /* thread detached, so attach it */
 222         wasAttached = 0;
 223         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 224     } else if (returnValue == JNI_EVERSION) {
 225         /* this version of JNI is not supported, so just try to attach */
 226         /* we assume it was attached to ensure that this thread is not detached
 227          * afterwards even though it should not
 228          */
 229         wasAttached = 1;
 230         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 231     } else {
 232         /* attached */
 233         wasAttached = 1;
 234     }
 235 
 236     jCreateMutexClass = (*env)->FindClass(env, CLASS_CREATEMUTEX);
 237     if (jCreateMutexClass == NULL) { return rv; }
 238     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 239     if (jInitArgsClass == NULL) { return rv; }
 240 
 241     /* get the CreateMutex object out of the jInitArgs object */
 242     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "CreateMutex", "Lsun/security/pkcs11/wrapper/CK_CREATEMUTEX;");
 243     if (fieldID == NULL) { return rv; }
 244     jCreateMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 245     assert(jCreateMutex != 0);
 246 
 247     /* call the CK_CREATEMUTEX function of the CreateMutex object */
 248     /* and get the new Java mutex object */
 249     methodID = (*env)->GetMethodID(env, jCreateMutexClass, "CK_CREATEMUTEX", "()Ljava/lang/Object;");
 250     if (methodID == NULL) { return rv; }
 251     jMutex = (*env)->CallObjectMethod(env, jCreateMutex, methodID);
 252 
 253     /* set a global reference on the Java mutex */
 254     jMutex = (*env)->NewGlobalRef(env, jMutex);
 255     /* convert the Java mutex to a CK mutex */
 256     *ppMutex = jObjectToCKVoidPtr(jMutex);
 257 
 258 
 259     /* check, if callback threw an exception */
 260     pkcs11Exception = (*env)->ExceptionOccurred(env);
 261 
 262     if (pkcs11Exception != NULL) {
 263         /* TBD: clear the pending exception with ExceptionClear? */
 264         /* The was an exception thrown, now we get the error-code from it */
 265         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 266         if (pkcs11ExceptionClass == NULL) { return rv; }
 267         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 268         if (methodID == NULL) { return rv; }
 269 
 270         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 271         rv = jLongToCKULong(errorCode);
 272     }
 273 
 274     /* if we attached this thread to the VM just for callback, we detach it now */
 275     if (wasAttached) {
 276         returnValue = (*jvm)->DetachCurrentThread(jvm);
 277     }
 278 
 279     return rv ;
 280 }
 281 
 282 /*
 283  * is the function that gets called by PKCS#11 to destroy a mutex and calls the Java
 284  * DestroyMutex function
 285  *
 286  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 287  * @param pMutex - the mutex to destroy
 288  * @return - should return CKR_OK if the mutex was destroyed
 289  */
 290 CK_RV callJDestroyMutex(CK_VOID_PTR pMutex)
 291 {
 292     extern JavaVM *jvm;
 293     JNIEnv *env;
 294     jint returnValue;
 295     jthrowable pkcs11Exception;
 296     jclass pkcs11ExceptionClass;
 297     jlong errorCode;
 298     CK_RV rv = CKR_OK;
 299     int wasAttached = 1;
 300     jclass jDestroyMutexClass;
 301     jclass jInitArgsClass;
 302     jmethodID methodID;
 303     jfieldID fieldID;
 304     jobject jDestroyMutex;
 305     jobject jMutex;
 306 
 307 
 308     /* Get the currently running Java VM */
 309     if (jvm == NULL) { return rv ; } /* there is no VM running */
 310 
 311     /* Determine, if current thread is already attached */
 312     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 313     if (returnValue == JNI_EDETACHED) {
 314         /* thread detached, so attach it */
 315         wasAttached = 0;
 316         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 317     } else if (returnValue == JNI_EVERSION) {
 318         /* this version of JNI is not supported, so just try to attach */
 319         /* we assume it was attached to ensure that this thread is not detached
 320          * afterwards even though it should not
 321          */
 322         wasAttached = 1;
 323         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 324     } else {
 325         /* attached */
 326         wasAttached = 1;
 327     }
 328 
 329     jDestroyMutexClass = (*env)->FindClass(env, CLASS_DESTROYMUTEX);
 330     if (jDestroyMutexClass == NULL) { return rv; }
 331     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 332     if (jInitArgsClass == NULL) { return rv; }
 333 
 334     /* convert the CK mutex to a Java mutex */
 335     jMutex = ckVoidPtrToJObject(pMutex);
 336 
 337     /* get the DestroyMutex object out of the jInitArgs object */
 338     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "DestroyMutex", "Lsun/security/pkcs11/wrapper/CK_DESTROYMUTEX;");
 339     if (fieldID == NULL) { return rv; }
 340     jDestroyMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 341     assert(jDestroyMutex != 0);
 342 
 343     /* call the CK_DESTROYMUTEX method of the DestroyMutex object */
 344     methodID = (*env)->GetMethodID(env, jDestroyMutexClass, "CK_DESTROYMUTEX", "(Ljava/lang/Object;)V");
 345     if (methodID == NULL) { return rv; }
 346     (*env)->CallVoidMethod(env, jDestroyMutex, methodID, jMutex);
 347 
 348     /* delete the global reference on the Java mutex */
 349     (*env)->DeleteGlobalRef(env, jMutex);
 350 
 351 
 352     /* check, if callback threw an exception */
 353     pkcs11Exception = (*env)->ExceptionOccurred(env);
 354 
 355     if (pkcs11Exception != NULL) {
 356         /* TBD: clear the pending exception with ExceptionClear? */
 357         /* The was an exception thrown, now we get the error-code from it */
 358         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 359         if (pkcs11ExceptionClass == NULL) { return rv; }
 360         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 361         if (methodID == NULL) { return rv; }
 362         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 363         rv = jLongToCKULong(errorCode);
 364     }
 365 
 366     /* if we attached this thread to the VM just for callback, we detach it now */
 367     if (wasAttached) {
 368         returnValue = (*jvm)->DetachCurrentThread(jvm);
 369     }
 370 
 371     return rv ;
 372 }
 373 
 374 /*
 375  * is the function that gets called by PKCS#11 to lock a mutex and calls the Java
 376  * LockMutex function
 377  *
 378  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 379  * @param pMutex - the mutex to lock
 380  * @return - should return CKR_OK if the mutex was not locked already
 381  */
 382 CK_RV callJLockMutex(CK_VOID_PTR pMutex)
 383 {
 384     extern JavaVM *jvm;
 385     JNIEnv *env;
 386     jint returnValue;
 387     jthrowable pkcs11Exception;
 388     jclass pkcs11ExceptionClass;
 389     jlong errorCode;
 390     CK_RV rv = CKR_OK;
 391     int wasAttached = 1;
 392     jclass jLockMutexClass;
 393     jclass jInitArgsClass;
 394     jmethodID methodID;
 395     jfieldID fieldID;
 396     jobject jLockMutex;
 397     jobject jMutex;
 398 
 399 
 400     /* Get the currently running Java VM */
 401     if (jvm == NULL) { return rv ; } /* there is no VM running */
 402 
 403     /* Determine, if current thread is already attached */
 404     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 405     if (returnValue == JNI_EDETACHED) {
 406         /* thread detached, so attach it */
 407         wasAttached = 0;
 408         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 409     } else if (returnValue == JNI_EVERSION) {
 410         /* this version of JNI is not supported, so just try to attach */
 411         /* we assume it was attached to ensure that this thread is not detached
 412          * afterwards even though it should not
 413          */
 414         wasAttached = 1;
 415         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 416     } else {
 417         /* attached */
 418         wasAttached = 1;
 419     }
 420 
 421     jLockMutexClass = (*env)->FindClass(env, CLASS_LOCKMUTEX);
 422     if (jLockMutexClass == NULL) { return rv; }
 423     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 424     if (jInitArgsClass == NULL) { return rv; }
 425 
 426     /* convert the CK mutex to a Java mutex */
 427     jMutex = ckVoidPtrToJObject(pMutex);
 428 
 429     /* get the LockMutex object out of the jInitArgs object */
 430     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "LockMutex", "Lsun/security/pkcs11/wrapper/CK_LOCKMUTEX;");
 431     if (fieldID == NULL) { return rv; }
 432     jLockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 433     assert(jLockMutex != 0);
 434 
 435     /* call the CK_LOCKMUTEX method of the LockMutex object */
 436     methodID = (*env)->GetMethodID(env, jLockMutexClass, "CK_LOCKMUTEX", "(Ljava/lang/Object;)V");
 437     if (methodID == NULL) { return rv; }
 438     (*env)->CallVoidMethod(env, jLockMutex, methodID, jMutex);
 439 
 440     /* check, if callback threw an exception */
 441     pkcs11Exception = (*env)->ExceptionOccurred(env);
 442 
 443     if (pkcs11Exception != NULL) {
 444         /* TBD: clear the pending exception with ExceptionClear? */
 445         /* The was an exception thrown, now we get the error-code from it */
 446         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 447         if (pkcs11ExceptionClass == NULL) { return rv; }
 448         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 449         if (methodID == NULL) { return rv; }
 450         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 451         rv = jLongToCKULong(errorCode);
 452     }
 453 
 454     /* if we attached this thread to the VM just for callback, we detach it now */
 455     if (wasAttached) {
 456         returnValue = (*jvm)->DetachCurrentThread(jvm);
 457     }
 458 
 459     return rv ;
 460 }
 461 
 462 /*
 463  * is the function that gets called by PKCS#11 to unlock a mutex and calls the Java
 464  * UnlockMutex function
 465  *
 466  * @param env - used to call JNI funktions to get the Java classes, objects, methods and fields
 467  * @param pMutex - the mutex to unlock
 468  * @return - should return CKR_OK if the mutex was not unlocked already
 469  */
 470 CK_RV callJUnlockMutex(CK_VOID_PTR pMutex)
 471 {
 472     extern JavaVM *jvm;
 473     JNIEnv *env;
 474     jint returnValue;
 475     jthrowable pkcs11Exception;
 476     jclass pkcs11ExceptionClass;
 477     jlong errorCode;
 478     CK_RV rv = CKR_OK;
 479     int wasAttached = 1;
 480     jclass jUnlockMutexClass;
 481     jclass jInitArgsClass;
 482     jmethodID methodID;
 483     jfieldID fieldID;
 484     jobject jUnlockMutex;
 485     jobject jMutex;
 486 
 487 
 488     /* Get the currently running Java VM */
 489     if (jvm == NULL) { return rv ; } /* there is no VM running */
 490 
 491     /* Determine, if current thread is already attached */
 492     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 493     if (returnValue == JNI_EDETACHED) {
 494         /* thread detached, so attach it */
 495         wasAttached = 0;
 496         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 497     } else if (returnValue == JNI_EVERSION) {
 498         /* this version of JNI is not supported, so just try to attach */
 499         /* we assume it was attached to ensure that this thread is not detached
 500          * afterwards even though it should not
 501          */
 502         wasAttached = 1;
 503         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 504     } else {
 505         /* attached */
 506         wasAttached = 1;
 507     }
 508 
 509     jUnlockMutexClass = (*env)->FindClass(env, CLASS_UNLOCKMUTEX);
 510     if (jUnlockMutexClass == NULL) { return rv; }
 511     jInitArgsClass = (*env)->FindClass(env, CLASS_C_INITIALIZE_ARGS);
 512     if (jInitArgsClass == NULL) { return rv; }
 513 
 514     /* convert the CK-type mutex to a Java mutex */
 515     jMutex = ckVoidPtrToJObject(pMutex);
 516 
 517     /* get the UnlockMutex object out of the jInitArgs object */
 518     fieldID = (*env)->GetFieldID(env, jInitArgsClass, "UnlockMutex", "Lsun/security/pkcs11/wrapper/CK_UNLOCKMUTEX;");
 519     if (fieldID == NULL) { return rv; }
 520     jUnlockMutex = (*env)->GetObjectField(env, jInitArgsObject, fieldID);
 521     assert(jUnlockMutex != 0);
 522 
 523     /* call the CK_UNLOCKMUTEX method of the UnLockMutex object */
 524     methodID = (*env)->GetMethodID(env, jUnlockMutexClass, "CK_UNLOCKMUTEX", "(Ljava/lang/Object;)V");
 525     if (methodID == NULL) { return rv; }
 526     (*env)->CallVoidMethod(env, jUnlockMutex, methodID, jMutex);
 527 
 528     /* check, if callback threw an exception */
 529     pkcs11Exception = (*env)->ExceptionOccurred(env);
 530 
 531     if (pkcs11Exception != NULL) {
 532         /* TBD: clear the pending exception with ExceptionClear? */
 533         /* The was an exception thrown, now we get the error-code from it */
 534         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 535         if (pkcs11ExceptionClass == NULL) { return rv; }
 536         methodID = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 537         if (methodID == NULL) { return rv; }
 538         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, methodID);
 539         rv = jLongToCKULong(errorCode);
 540     }
 541 
 542     /* if we attached this thread to the VM just for callback, we detach it now */
 543     if (wasAttached) {
 544         returnValue = (*jvm)->DetachCurrentThread(jvm);
 545     }
 546 
 547     return rv ;
 548 }
 549 
 550 #endif /* NO_CALLBACKS */