1 /*
   2  * Copyright (c) 2003, 2013, 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 list of notify callback handles that are currently active and waiting
  58  * for callbacks from their sessions.
  59  */
  60 #ifndef NO_CALLBACKS
  61 NotifyListNode *notifyListHead = NULL;
  62 jobject notifyListLock = NULL;
  63 #endif /* NO_CALLBACKS */
  64 
  65 #ifdef P11_ENABLE_C_OPENSESSION
  66 /*
  67  * Class:     sun_security_pkcs11_wrapper_PKCS11
  68  * Method:    C_OpenSession
  69  * Signature: (JJLjava/lang/Object;Lsun/security/pkcs11/wrapper/CK_NOTIFY;)J
  70  * Parametermapping:                    *PKCS11*
  71  * @param   jlong jSlotID               CK_SLOT_ID slotID
  72  * @param   jlong jFlags                CK_FLAGS flags
  73  * @param   jobject jApplication        CK_VOID_PTR pApplication
  74  * @param   jobject jNotify             CK_NOTIFY Notify
  75  * @return  jlong jSessionHandle        CK_SESSION_HANDLE_PTR phSession
  76  */
  77 JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession
  78     (JNIEnv *env, jobject obj, jlong jSlotID, jlong jFlags, jobject jApplication, jobject jNotify)
  79 {
  80     CK_SESSION_HANDLE ckSessionHandle;
  81     CK_SLOT_ID ckSlotID;
  82     CK_FLAGS ckFlags;
  83     CK_VOID_PTR ckpApplication;
  84     CK_NOTIFY ckNotify;
  85     jlong jSessionHandle;
  86     CK_RV rv;
  87 #ifndef NO_CALLBACKS
  88     NotifyEncapsulation *notifyEncapsulation = NULL;
  89 #endif /* NO_CALLBACKS */
  90 
  91     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
  92     if (ckpFunctions == NULL) { return 0L; }
  93 
  94     ckSlotID = jLongToCKULong(jSlotID);
  95     ckFlags = jLongToCKULong(jFlags);
  96 
  97 #ifndef NO_CALLBACKS
  98     if (jNotify != NULL) {
  99         notifyEncapsulation = (NotifyEncapsulation *) malloc(sizeof(NotifyEncapsulation));
 100         if (notifyEncapsulation == NULL) {
 101             throwOutOfMemoryError(env, 0);
 102             return 0L;
 103         }
 104         notifyEncapsulation->jApplicationData = (jApplication != NULL)
 105                 ? (*env)->NewGlobalRef(env, jApplication)
 106                 : NULL;
 107         notifyEncapsulation->jNotifyObject = (*env)->NewGlobalRef(env, jNotify);
 108         ckpApplication = notifyEncapsulation;
 109         ckNotify = (CK_NOTIFY) &notifyCallback;
 110     } else {
 111         ckpApplication = NULL_PTR;
 112         ckNotify = NULL_PTR;
 113     }
 114 #else
 115         ckpApplication = NULL_PTR;
 116         ckNotify = NULL_PTR;
 117 #endif /* NO_CALLBACKS */
 118 
 119     TRACE0("DEBUG: C_OpenSession");
 120     TRACE1(", slotID=%u", ckSlotID);
 121     TRACE1(", flags=%x", ckFlags);
 122     TRACE0(" ... ");
 123 
 124     rv = (*ckpFunctions->C_OpenSession)(ckSlotID, ckFlags, ckpApplication, ckNotify, &ckSessionHandle);
 125     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) {
 126 #ifndef NO_CALLBACKS
 127         if (notifyEncapsulation != NULL) {
 128             if (notifyEncapsulation->jApplicationData != NULL) {
 129                 (*env)->DeleteGlobalRef(env, jApplication);
 130             }
 131             (*env)->DeleteGlobalRef(env, jNotify);
 132             free(notifyEncapsulation);
 133         }
 134 #endif /* NO_CALLBACKS */
 135         return 0L;
 136     }
 137 
 138     TRACE0("got session");
 139     TRACE1(", SessionHandle=%u", ckSessionHandle);
 140     TRACE0(" ... ");
 141 
 142     jSessionHandle = ckULongToJLong(ckSessionHandle);
 143 
 144 #ifndef NO_CALLBACKS
 145     if (notifyEncapsulation != NULL) {
 146         /* store the notifyEncapsulation to enable later cleanup */
 147         putNotifyEntry(env, ckSessionHandle, notifyEncapsulation);
 148     }
 149 #endif /* NO_CALLBACKS */
 150 
 151     TRACE0("FINISHED\n");
 152 
 153     return jSessionHandle ;
 154 }
 155 #endif
 156 
 157 #ifdef P11_ENABLE_C_CLOSESESSION
 158 /*
 159  * Class:     sun_security_pkcs11_wrapper_PKCS11
 160  * Method:    C_CloseSession
 161  * Signature: (J)V
 162  * Parametermapping:                    *PKCS11*
 163  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
 164  */
 165 JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseSession
 166     (JNIEnv *env, jobject obj, jlong jSessionHandle)
 167 {
 168     CK_SESSION_HANDLE ckSessionHandle;
 169     CK_RV rv;
 170 #ifndef NO_CALLBACKS
 171     NotifyEncapsulation *notifyEncapsulation;
 172     jobject jApplicationData;
 173 #endif /* NO_CALLBACKS */
 174 
 175     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 176     if (ckpFunctions == NULL) { return; }
 177 
 178     ckSessionHandle = jLongToCKULong(jSessionHandle);
 179 
 180     rv = (*ckpFunctions->C_CloseSession)(ckSessionHandle);
 181     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 182 
 183 #ifndef NO_CALLBACKS
 184     notifyEncapsulation = removeNotifyEntry(env, ckSessionHandle);
 185 
 186     if (notifyEncapsulation != NULL) {
 187         /* there was a notify object used with this session, now dump the
 188          * encapsulation object
 189          */
 190         (*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);
 191         jApplicationData = notifyEncapsulation->jApplicationData;
 192         if (jApplicationData != NULL) {
 193             (*env)->DeleteGlobalRef(env, jApplicationData);
 194         }
 195         free(notifyEncapsulation);
 196     }
 197 #endif /* NO_CALLBACKS */
 198 
 199 }
 200 #endif
 201 
 202 #ifdef P11_ENABLE_C_CLOSEALLSESSIONS
 203 /*
 204  * Class:     sun_security_pkcs11_wrapper_PKCS11
 205  * Method:    C_CloseAllSessions
 206  * Signature: (J)V
 207  * Parametermapping:                    *PKCS11*
 208  * @param   jlong jSlotID               CK_SLOT_ID slotID
 209  */
 210 JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseAllSessions
 211     (JNIEnv *env, jobject obj, jlong jSlotID)
 212 {
 213     CK_SLOT_ID ckSlotID;
 214     CK_RV rv;
 215 #ifndef NO_CALLBACKS
 216     NotifyEncapsulation *notifyEncapsulation;
 217     jobject jApplicationData;
 218 #endif /* NO_CALLBACKS */
 219 
 220     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 221     if (ckpFunctions == NULL) { return; }
 222 
 223     ckSlotID = jLongToCKULong(jSlotID);
 224 
 225     rv = (*ckpFunctions->C_CloseAllSessions)(ckSlotID);
 226     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 227 
 228 #ifndef NO_CALLBACKS
 229     /* Remove all notify callback helper objects. */
 230     while ((notifyEncapsulation = removeFirstNotifyEntry(env)) != NULL) {
 231         /* there was a notify object used with this session, now dump the
 232          * encapsulation object
 233          */
 234         (*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);
 235         jApplicationData = notifyEncapsulation->jApplicationData;
 236         if (jApplicationData != NULL) {
 237             (*env)->DeleteGlobalRef(env, jApplicationData);
 238         }
 239         free(notifyEncapsulation);
 240     }
 241 #endif /* NO_CALLBACKS */
 242 }
 243 #endif
 244 
 245 #ifdef P11_ENABLE_C_GETSESSIONINFO
 246 /*
 247  * Class:     sun_security_pkcs11_wrapper_PKCS11
 248  * Method:    C_GetSessionInfo
 249  * Signature: (J)Lsun/security/pkcs11/wrapper/CK_SESSION_INFO;
 250  * Parametermapping:                    *PKCS11*
 251  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
 252  * @return  jobject jSessionInfo        CK_SESSION_INFO_PTR pInfo
 253  */
 254 JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSessionInfo
 255     (JNIEnv *env, jobject obj, jlong jSessionHandle)
 256 {
 257     CK_SESSION_HANDLE ckSessionHandle;
 258     CK_SESSION_INFO ckSessionInfo;
 259     jobject jSessionInfo=NULL;
 260     CK_RV rv;
 261 
 262     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 263     if (ckpFunctions == NULL) { return NULL; }
 264 
 265     ckSessionHandle = jLongToCKULong(jSessionHandle);
 266 
 267     rv = (*ckpFunctions->C_GetSessionInfo)(ckSessionHandle, &ckSessionInfo);
 268     if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
 269         jSessionInfo = ckSessionInfoPtrToJSessionInfo(env, &ckSessionInfo);
 270     }
 271     return jSessionInfo ;
 272 }
 273 #endif
 274 
 275 #ifdef P11_ENABLE_C_GETOPERATIONSTATE
 276 /*
 277  * Class:     sun_security_pkcs11_wrapper_PKCS11
 278  * Method:    C_GetOperationState
 279  * Signature: (J)[B
 280  * Parametermapping:                    *PKCS11*
 281  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
 282  * @return  jbyteArray jState           CK_BYTE_PTR pOperationState
 283  *                                      CK_ULONG_PTR pulOperationStateLen
 284  */
 285 JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOperationState
 286     (JNIEnv *env, jobject obj, jlong jSessionHandle)
 287 {
 288     CK_SESSION_HANDLE ckSessionHandle;
 289     CK_BYTE_PTR ckpState;
 290     CK_ULONG ckStateLength;
 291     jbyteArray jState = NULL;
 292     CK_RV rv;
 293 
 294     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 295     if (ckpFunctions == NULL) { return NULL; }
 296 
 297     ckSessionHandle = jLongToCKULong(jSessionHandle);
 298 
 299     rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, NULL_PTR, &ckStateLength);
 300     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; }
 301 
 302     ckpState = (CK_BYTE_PTR) malloc(ckStateLength);
 303     if (ckpState == NULL) {
 304         throwOutOfMemoryError(env, 0);
 305         return NULL;
 306     }
 307 
 308     rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, ckpState, &ckStateLength);
 309     if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
 310         jState = ckByteArrayToJByteArray(env, ckpState, ckStateLength);
 311     }
 312     free(ckpState);
 313 
 314     return jState ;
 315 }
 316 #endif
 317 
 318 #ifdef P11_ENABLE_C_SETOPERATIONSTATE
 319 /*
 320  * Class:     sun_security_pkcs11_wrapper_PKCS11
 321  * Method:    C_SetOperationState
 322  * Signature: (J[BJJ)V
 323  * Parametermapping:                        *PKCS11*
 324  * @param   jlong jSessionHandle            CK_SESSION_HANDLE hSession
 325  * @param   jbyteArray jOperationState      CK_BYTE_PTR pOperationState
 326  *                                          CK_ULONG ulOperationStateLen
 327  * @param   jlong jEncryptionKeyHandle      CK_OBJECT_HANDLE hEncryptionKey
 328  * @param   jlong jAuthenticationKeyHandle  CK_OBJECT_HANDLE hAuthenticationKey
 329  */
 330 JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationState
 331     (JNIEnv *env, jobject obj, jlong jSessionHandle, jbyteArray jOperationState, jlong jEncryptionKeyHandle, jlong jAuthenticationKeyHandle)
 332 {
 333     CK_SESSION_HANDLE ckSessionHandle;
 334     CK_BYTE_PTR ckpState = NULL_PTR;
 335     CK_ULONG ckStateLength;
 336     CK_OBJECT_HANDLE ckEncryptionKeyHandle;
 337     CK_OBJECT_HANDLE ckAuthenticationKeyHandle;
 338     CK_RV rv;
 339 
 340     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 341     if (ckpFunctions == NULL) { return; }
 342 
 343     ckSessionHandle = jLongToCKULong(jSessionHandle);
 344     jByteArrayToCKByteArray(env, jOperationState, &ckpState, &ckStateLength);
 345     if ((*env)->ExceptionCheck(env)) { return; }
 346 
 347     ckEncryptionKeyHandle = jLongToCKULong(jEncryptionKeyHandle);
 348     ckAuthenticationKeyHandle = jLongToCKULong(jAuthenticationKeyHandle);
 349 
 350     rv = (*ckpFunctions->C_SetOperationState)(ckSessionHandle, ckpState, ckStateLength, ckEncryptionKeyHandle, ckAuthenticationKeyHandle);
 351 
 352     free(ckpState);
 353 
 354     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 355 }
 356 #endif
 357 
 358 #ifdef P11_ENABLE_C_LOGIN
 359 /*
 360  * Class:     sun_security_pkcs11_wrapper_PKCS11
 361  * Method:    C_Login
 362  * Signature: (JJ[C)V
 363  * Parametermapping:                    *PKCS11*
 364  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
 365  * @param   jlong jUserType             CK_USER_TYPE userType
 366  * @param   jcharArray jPin             CK_CHAR_PTR pPin
 367  *                                      CK_ULONG ulPinLen
 368  */
 369 JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Login
 370     (JNIEnv *env, jobject obj, jlong jSessionHandle, jlong jUserType, jcharArray jPin)
 371 {
 372     CK_SESSION_HANDLE ckSessionHandle;
 373     CK_USER_TYPE ckUserType;
 374     CK_CHAR_PTR ckpPinArray = NULL_PTR;
 375     CK_ULONG ckPinLength;
 376     CK_RV rv;
 377 
 378     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 379     if (ckpFunctions == NULL) { return; }
 380 
 381     ckSessionHandle = jLongToCKULong(jSessionHandle);
 382     ckUserType = jLongToCKULong(jUserType);
 383     jCharArrayToCKCharArray(env, jPin, &ckpPinArray, &ckPinLength);
 384     if ((*env)->ExceptionCheck(env)) { return; }
 385 
 386     rv = (*ckpFunctions->C_Login)(ckSessionHandle, ckUserType, ckpPinArray, ckPinLength);
 387 
 388     free(ckpPinArray);
 389 
 390     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 391 }
 392 #endif
 393 
 394 #ifdef P11_ENABLE_C_LOGOUT
 395 /*
 396  * Class:     sun_security_pkcs11_wrapper_PKCS11
 397  * Method:    C_Logout
 398  * Signature: (J)V
 399  * Parametermapping:                    *PKCS11*
 400  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
 401  */
 402 JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Logout
 403     (JNIEnv *env, jobject obj, jlong jSessionHandle)
 404 {
 405     CK_SESSION_HANDLE ckSessionHandle;
 406     CK_RV rv;
 407 
 408     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
 409     if (ckpFunctions == NULL) { return; }
 410 
 411     ckSessionHandle = jLongToCKULong(jSessionHandle);
 412 
 413     rv = (*ckpFunctions->C_Logout)(ckSessionHandle);
 414     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 415 }
 416 #endif
 417 
 418 /* ************************************************************************** */
 419 /* Functions for keeping track of notify callbacks                            */
 420 /* ************************************************************************** */
 421 
 422 #ifndef NO_CALLBACKS
 423 
 424 /*
 425  * Add the given notify encapsulation object to the list of active notify
 426  * objects.
 427  * If notifyEncapsulation is NULL, this function does nothing.
 428  */
 429 void putNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession, NotifyEncapsulation *notifyEncapsulation) {
 430     NotifyListNode *currentNode, *newNode;
 431 
 432     if (notifyEncapsulation == NULL) {
 433         return;
 434     }
 435 
 436     newNode = (NotifyListNode *) malloc(sizeof(NotifyListNode));
 437     if (newNode == NULL) {
 438         throwOutOfMemoryError(env, 0);
 439         return;
 440     }
 441     newNode->hSession = hSession;
 442     newNode->notifyEncapsulation = notifyEncapsulation;
 443     newNode->next = NULL;
 444 
 445     (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
 446 
 447     if (notifyListHead == NULL) {
 448         /* this is the first entry */
 449         notifyListHead = newNode;
 450     } else {
 451         /* go to the last entry; i.e. the first node which's 'next' is NULL.
 452          */
 453         currentNode = notifyListHead;
 454         while (currentNode->next != NULL) {
 455             currentNode = currentNode->next;
 456         }
 457         currentNode->next = newNode;
 458     }
 459 
 460     (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
 461 }
 462 
 463 /*
 464  * Removes the active notifyEncapsulation object used with the given session and
 465  * returns it. If there is no notifyEncapsulation active for this session, this
 466  * function returns NULL.
 467  */
 468 NotifyEncapsulation * removeNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession) {
 469     NotifyEncapsulation *notifyEncapsulation;
 470     NotifyListNode *currentNode, *previousNode;
 471 
 472     (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
 473 
 474     if (notifyListHead == NULL) {
 475         /* this is the first entry */
 476         notifyEncapsulation = NULL;
 477     } else {
 478         /* Find the node with the wanted session handle. Also stop, when we reach
 479          * the last entry; i.e. the first node which's 'next' is NULL.
 480          */
 481         currentNode = notifyListHead;
 482         previousNode = NULL;
 483 
 484         while ((currentNode->hSession != hSession) && (currentNode->next != NULL)) {
 485             previousNode = currentNode;
 486             currentNode = currentNode->next;
 487         }
 488 
 489         if (currentNode->hSession == hSession) {
 490             /* We found a entry for the wanted session, now remove it. */
 491             if (previousNode == NULL) {
 492                 /* it's the first node */
 493                 notifyListHead = currentNode->next;
 494             } else {
 495                 previousNode->next = currentNode->next;
 496             }
 497             notifyEncapsulation = currentNode->notifyEncapsulation;
 498             free(currentNode);
 499         } else {
 500             /* We did not find a entry for this session */
 501             notifyEncapsulation = NULL;
 502         }
 503     }
 504 
 505     (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
 506 
 507     return notifyEncapsulation ;
 508 }
 509 
 510 /*
 511 
 512  * Removes the first notifyEncapsulation object. If there is no notifyEncapsulation,
 513  * this function returns NULL.
 514  */
 515 NotifyEncapsulation * removeFirstNotifyEntry(JNIEnv *env) {
 516     NotifyEncapsulation *notifyEncapsulation;
 517     NotifyListNode *currentNode;
 518 
 519     (*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */
 520 
 521     if (notifyListHead == NULL) {
 522         /* this is the first entry */
 523         notifyEncapsulation = NULL;
 524     } else {
 525         /* Remove the first entry. */
 526         currentNode = notifyListHead;
 527         notifyListHead = notifyListHead->next;
 528         notifyEncapsulation = currentNode->notifyEncapsulation;
 529         free(currentNode);
 530     }
 531 
 532     (*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */
 533 
 534     return notifyEncapsulation ;
 535 }
 536 
 537 #endif /* NO_CALLBACKS */
 538 
 539 #ifndef NO_CALLBACKS
 540 
 541 /*
 542  * The function handling notify callbacks. It casts the pApplication parameter
 543  * back to a NotifyEncapsulation structure and retrieves the Notify object and
 544  * the application data from it.
 545  *
 546  * @param hSession The session, this callback is comming from.
 547  * @param event The type of event that occurred.
 548  * @param pApplication The application data as passed in upon OpenSession. In
 549                        this wrapper we always pass in a NotifyEncapsulation
 550                        object, which holds necessary information for delegating
 551                        the callback to the Java VM.
 552  * @return
 553  */
 554 CK_RV notifyCallback(
 555     CK_SESSION_HANDLE hSession,     /* the session's handle */
 556     CK_NOTIFICATION   event,
 557     CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
 558 )
 559 {
 560     NotifyEncapsulation *notifyEncapsulation;
 561     extern JavaVM *jvm;
 562     JNIEnv *env;
 563     jint returnValue;
 564     jlong jSessionHandle;
 565     jlong jEvent;
 566     jclass ckNotifyClass;
 567     jmethodID jmethod;
 568     jthrowable pkcs11Exception;
 569     jclass pkcs11ExceptionClass;
 570     jlong errorCode;
 571     CK_RV rv = CKR_OK;
 572     int wasAttached = 1;
 573 
 574     if (pApplication == NULL) { return rv ; } /* This should not occur in this wrapper. */
 575 
 576     notifyEncapsulation = (NotifyEncapsulation *) pApplication;
 577 
 578     /* Get the currently running Java VM */
 579     if (jvm == NULL) { return rv ; } /* there is no VM running */
 580 
 581     /* Determine, if current thread is already attached */
 582     returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);
 583     if (returnValue == JNI_EDETACHED) {
 584         /* thread detached, so attach it */
 585         wasAttached = 0;
 586         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 587     } else if (returnValue == JNI_EVERSION) {
 588         /* this version of JNI is not supported, so just try to attach */
 589         /* we assume it was attached to ensure that this thread is not detached
 590          * afterwards even though it should not
 591          */
 592         wasAttached = 1;
 593         returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
 594     } else {
 595         /* attached */
 596         wasAttached = 1;
 597     }
 598 
 599     jSessionHandle = ckULongToJLong(hSession);
 600     jEvent = ckULongToJLong(event);
 601 
 602     ckNotifyClass = (*env)->FindClass(env, CLASS_NOTIFY);
 603     if (ckNotifyClass == NULL) { return rv; }
 604     jmethod = (*env)->GetMethodID(env, ckNotifyClass, "CK_NOTIFY", "(JJLjava/lang/Object;)V");
 605     if (jmethod == NULL) { return rv; }
 606 
 607     (*env)->CallVoidMethod(env, notifyEncapsulation->jNotifyObject, jmethod,
 608                          jSessionHandle, jEvent, notifyEncapsulation->jApplicationData);
 609 
 610     /* check, if callback threw an exception */
 611     pkcs11Exception = (*env)->ExceptionOccurred(env);
 612 
 613     if (pkcs11Exception != NULL) {
 614         /* TBD: clear the pending exception with ExceptionClear? */
 615         /* The was an exception thrown, now we get the error-code from it */
 616         pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);
 617         if (pkcs11ExceptionClass == NULL) { return rv; }
 618 
 619         jmethod = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");
 620         if (jmethod == NULL) { return rv; }
 621 
 622         errorCode = (*env)->CallLongMethod(env, pkcs11Exception, jmethod);
 623         rv = jLongToCKULong(errorCode);
 624     }
 625 
 626     /* if we attached this thread to the VM just for callback, we detach it now */
 627     if (wasAttached) {
 628         returnValue = (*jvm)->DetachCurrentThread(jvm);
 629     }
 630 
 631     return rv ;
 632 }
 633 
 634 #endif /* NO_CALLBACKS */