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
59jobject jInitArgsObject;
60CK_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 */
76CK_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 */
199CK_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 */
292CK_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 */
384CK_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 */
472CK_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 */
553