Path: blob/master/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_sessmgmt.c
41149 views
/*1* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.2*/34/* Copyright (c) 2002 Graz University of Technology. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions are met:8*9* 1. Redistributions of source code must retain the above copyright notice,10* this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright notice,13* this list of conditions and the following disclaimer in the documentation14* and/or other materials provided with the distribution.15*16* 3. The end-user documentation included with the redistribution, if any, must17* include the following acknowledgment:18*19* "This product includes software developed by IAIK of Graz University of20* Technology."21*22* Alternately, this acknowledgment may appear in the software itself, if23* and wherever such third-party acknowledgments normally appear.24*25* 4. The names "Graz University of Technology" and "IAIK of Graz University of26* Technology" must not be used to endorse or promote products derived from27* this software without prior written permission.28*29* 5. Products derived from this software may not be called30* "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior31* written permission of Graz University of Technology.32*33* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED34* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED35* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR36* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE37* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,38* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,39* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,40* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON41* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,42* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY43* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE44* POSSIBILITY OF SUCH DAMAGE.45*/4647#include "pkcs11wrapper.h"4849#include <stdio.h>50#include <stdlib.h>51#include <string.h>52#include <assert.h>5354#include "sun_security_pkcs11_wrapper_PKCS11.h"5556/* The list of notify callback handles that are currently active and waiting57* for callbacks from their sessions.58*/59#ifndef NO_CALLBACKS60NotifyListNode *notifyListHead = NULL;61jobject notifyListLock = NULL;62#endif /* NO_CALLBACKS */6364#ifdef P11_ENABLE_C_OPENSESSION65/*66* Class: sun_security_pkcs11_wrapper_PKCS1167* Method: C_OpenSession68* Signature: (JJLjava/lang/Object;Lsun/security/pkcs11/wrapper/CK_NOTIFY;)J69* Parametermapping: *PKCS11*70* @param jlong jSlotID CK_SLOT_ID slotID71* @param jlong jFlags CK_FLAGS flags72* @param jobject jApplication CK_VOID_PTR pApplication73* @param jobject jNotify CK_NOTIFY Notify74* @return jlong jSessionHandle CK_SESSION_HANDLE_PTR phSession75*/76JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1OpenSession77(JNIEnv *env, jobject obj, jlong jSlotID, jlong jFlags, jobject jApplication, jobject jNotify)78{79CK_SESSION_HANDLE ckSessionHandle;80CK_SLOT_ID ckSlotID;81CK_FLAGS ckFlags;82CK_VOID_PTR ckpApplication;83CK_NOTIFY ckNotify;84jlong jSessionHandle;85CK_RV rv;86#ifndef NO_CALLBACKS87NotifyEncapsulation *notifyEncapsulation = NULL;88#endif /* NO_CALLBACKS */8990CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);91if (ckpFunctions == NULL) { return 0L; }9293ckSlotID = jLongToCKULong(jSlotID);94ckFlags = jLongToCKULong(jFlags);9596#ifndef NO_CALLBACKS97if (jNotify != NULL) {98notifyEncapsulation = (NotifyEncapsulation *) malloc(sizeof(NotifyEncapsulation));99if (notifyEncapsulation == NULL) {100throwOutOfMemoryError(env, 0);101return 0L;102}103notifyEncapsulation->jApplicationData = (jApplication != NULL)104? (*env)->NewGlobalRef(env, jApplication)105: NULL;106notifyEncapsulation->jNotifyObject = (*env)->NewGlobalRef(env, jNotify);107ckpApplication = notifyEncapsulation;108ckNotify = (CK_NOTIFY) ¬ifyCallback;109} else {110ckpApplication = NULL_PTR;111ckNotify = NULL_PTR;112}113#else114ckpApplication = NULL_PTR;115ckNotify = NULL_PTR;116#endif /* NO_CALLBACKS */117118TRACE0("DEBUG: C_OpenSession");119TRACE1(", slotID=%lu", ckSlotID);120TRACE1(", flags=%lu", (unsigned long) ckFlags);121TRACE0(" ... ");122123rv = (*ckpFunctions->C_OpenSession)(ckSlotID, ckFlags, ckpApplication, ckNotify, &ckSessionHandle);124if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) {125#ifndef NO_CALLBACKS126if (notifyEncapsulation != NULL) {127if (notifyEncapsulation->jApplicationData != NULL) {128(*env)->DeleteGlobalRef(env, jApplication);129}130(*env)->DeleteGlobalRef(env, jNotify);131free(notifyEncapsulation);132}133#endif /* NO_CALLBACKS */134return 0L;135}136137TRACE0("got session");138TRACE1(", SessionHandle=%lu", (unsigned long) ckSessionHandle);139TRACE0(" ... ");140141jSessionHandle = ckULongToJLong(ckSessionHandle);142143#ifndef NO_CALLBACKS144if (notifyEncapsulation != NULL) {145/* store the notifyEncapsulation to enable later cleanup */146putNotifyEntry(env, ckSessionHandle, notifyEncapsulation);147}148#endif /* NO_CALLBACKS */149150TRACE0("FINISHED\n");151152return jSessionHandle ;153}154#endif155156#ifdef P11_ENABLE_C_CLOSESESSION157/*158* Class: sun_security_pkcs11_wrapper_PKCS11159* Method: C_CloseSession160* Signature: (J)V161* Parametermapping: *PKCS11*162* @param jlong jSessionHandle CK_SESSION_HANDLE hSession163*/164JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseSession165(JNIEnv *env, jobject obj, jlong jSessionHandle)166{167CK_SESSION_HANDLE ckSessionHandle;168CK_RV rv;169#ifndef NO_CALLBACKS170NotifyEncapsulation *notifyEncapsulation;171jobject jApplicationData;172#endif /* NO_CALLBACKS */173174CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);175if (ckpFunctions == NULL) { return; }176177ckSessionHandle = jLongToCKULong(jSessionHandle);178179rv = (*ckpFunctions->C_CloseSession)(ckSessionHandle);180if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }181182#ifndef NO_CALLBACKS183notifyEncapsulation = removeNotifyEntry(env, ckSessionHandle);184185if (notifyEncapsulation != NULL) {186/* there was a notify object used with this session, now dump the187* encapsulation object188*/189(*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);190jApplicationData = notifyEncapsulation->jApplicationData;191if (jApplicationData != NULL) {192(*env)->DeleteGlobalRef(env, jApplicationData);193}194free(notifyEncapsulation);195}196#endif /* NO_CALLBACKS */197198}199#endif200201#ifdef P11_ENABLE_C_CLOSEALLSESSIONS202/*203* Class: sun_security_pkcs11_wrapper_PKCS11204* Method: C_CloseAllSessions205* Signature: (J)V206* Parametermapping: *PKCS11*207* @param jlong jSlotID CK_SLOT_ID slotID208*/209JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1CloseAllSessions210(JNIEnv *env, jobject obj, jlong jSlotID)211{212CK_SLOT_ID ckSlotID;213CK_RV rv;214#ifndef NO_CALLBACKS215NotifyEncapsulation *notifyEncapsulation;216jobject jApplicationData;217#endif /* NO_CALLBACKS */218219CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);220if (ckpFunctions == NULL) { return; }221222ckSlotID = jLongToCKULong(jSlotID);223224rv = (*ckpFunctions->C_CloseAllSessions)(ckSlotID);225if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }226227#ifndef NO_CALLBACKS228/* Remove all notify callback helper objects. */229while ((notifyEncapsulation = removeFirstNotifyEntry(env)) != NULL) {230/* there was a notify object used with this session, now dump the231* encapsulation object232*/233(*env)->DeleteGlobalRef(env, notifyEncapsulation->jNotifyObject);234jApplicationData = notifyEncapsulation->jApplicationData;235if (jApplicationData != NULL) {236(*env)->DeleteGlobalRef(env, jApplicationData);237}238free(notifyEncapsulation);239}240#endif /* NO_CALLBACKS */241}242#endif243244#ifdef P11_ENABLE_C_GETSESSIONINFO245/*246* Class: sun_security_pkcs11_wrapper_PKCS11247* Method: C_GetSessionInfo248* Signature: (J)Lsun/security/pkcs11/wrapper/CK_SESSION_INFO;249* Parametermapping: *PKCS11*250* @param jlong jSessionHandle CK_SESSION_HANDLE hSession251* @return jobject jSessionInfo CK_SESSION_INFO_PTR pInfo252*/253JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetSessionInfo254(JNIEnv *env, jobject obj, jlong jSessionHandle)255{256CK_SESSION_HANDLE ckSessionHandle;257CK_SESSION_INFO ckSessionInfo;258jobject jSessionInfo=NULL;259CK_RV rv;260261CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);262if (ckpFunctions == NULL) { return NULL; }263264ckSessionHandle = jLongToCKULong(jSessionHandle);265266rv = (*ckpFunctions->C_GetSessionInfo)(ckSessionHandle, &ckSessionInfo);267if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {268jSessionInfo = ckSessionInfoPtrToJSessionInfo(env, &ckSessionInfo);269}270return jSessionInfo ;271}272#endif273274#ifdef P11_ENABLE_C_GETOPERATIONSTATE275/*276* Class: sun_security_pkcs11_wrapper_PKCS11277* Method: C_GetOperationState278* Signature: (J)[B279* Parametermapping: *PKCS11*280* @param jlong jSessionHandle CK_SESSION_HANDLE hSession281* @return jbyteArray jState CK_BYTE_PTR pOperationState282* CK_ULONG_PTR pulOperationStateLen283*/284JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1GetOperationState285(JNIEnv *env, jobject obj, jlong jSessionHandle)286{287CK_SESSION_HANDLE ckSessionHandle;288CK_BYTE_PTR ckpState;289CK_ULONG ckStateLength;290jbyteArray jState = NULL;291CK_RV rv;292293CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);294if (ckpFunctions == NULL) { return NULL; }295296ckSessionHandle = jLongToCKULong(jSessionHandle);297298rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, NULL_PTR, &ckStateLength);299if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return NULL ; }300301ckpState = (CK_BYTE_PTR) malloc(ckStateLength);302if (ckpState == NULL) {303throwOutOfMemoryError(env, 0);304return NULL;305}306307rv = (*ckpFunctions->C_GetOperationState)(ckSessionHandle, ckpState, &ckStateLength);308if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {309jState = ckByteArrayToJByteArray(env, ckpState, ckStateLength);310}311free(ckpState);312313return jState ;314}315#endif316317#ifdef P11_ENABLE_C_SETOPERATIONSTATE318/*319* Class: sun_security_pkcs11_wrapper_PKCS11320* Method: C_SetOperationState321* Signature: (J[BJJ)V322* Parametermapping: *PKCS11*323* @param jlong jSessionHandle CK_SESSION_HANDLE hSession324* @param jbyteArray jOperationState CK_BYTE_PTR pOperationState325* CK_ULONG ulOperationStateLen326* @param jlong jEncryptionKeyHandle CK_OBJECT_HANDLE hEncryptionKey327* @param jlong jAuthenticationKeyHandle CK_OBJECT_HANDLE hAuthenticationKey328*/329JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1SetOperationState330(JNIEnv *env, jobject obj, jlong jSessionHandle, jbyteArray jOperationState, jlong jEncryptionKeyHandle, jlong jAuthenticationKeyHandle)331{332CK_SESSION_HANDLE ckSessionHandle;333CK_BYTE_PTR ckpState = NULL_PTR;334CK_ULONG ckStateLength;335CK_OBJECT_HANDLE ckEncryptionKeyHandle;336CK_OBJECT_HANDLE ckAuthenticationKeyHandle;337CK_RV rv;338339CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);340if (ckpFunctions == NULL) { return; }341342ckSessionHandle = jLongToCKULong(jSessionHandle);343jByteArrayToCKByteArray(env, jOperationState, &ckpState, &ckStateLength);344if ((*env)->ExceptionCheck(env)) { return; }345346ckEncryptionKeyHandle = jLongToCKULong(jEncryptionKeyHandle);347ckAuthenticationKeyHandle = jLongToCKULong(jAuthenticationKeyHandle);348349rv = (*ckpFunctions->C_SetOperationState)(ckSessionHandle, ckpState, ckStateLength, ckEncryptionKeyHandle, ckAuthenticationKeyHandle);350351free(ckpState);352353if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }354}355#endif356357#ifdef P11_ENABLE_C_LOGIN358/*359* Class: sun_security_pkcs11_wrapper_PKCS11360* Method: C_Login361* Signature: (JJ[C)V362* Parametermapping: *PKCS11*363* @param jlong jSessionHandle CK_SESSION_HANDLE hSession364* @param jlong jUserType CK_USER_TYPE userType365* @param jcharArray jPin CK_CHAR_PTR pPin366* CK_ULONG ulPinLen367*/368JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Login369(JNIEnv *env, jobject obj, jlong jSessionHandle, jlong jUserType, jcharArray jPin)370{371CK_SESSION_HANDLE ckSessionHandle;372CK_USER_TYPE ckUserType;373CK_CHAR_PTR ckpPinArray = NULL_PTR;374CK_ULONG ckPinLength;375CK_RV rv;376377CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);378if (ckpFunctions == NULL) { return; }379380ckSessionHandle = jLongToCKULong(jSessionHandle);381ckUserType = jLongToCKULong(jUserType);382jCharArrayToCKCharArray(env, jPin, &ckpPinArray, &ckPinLength);383if ((*env)->ExceptionCheck(env)) { return; }384385rv = (*ckpFunctions->C_Login)(ckSessionHandle, ckUserType, ckpPinArray, ckPinLength);386387free(ckpPinArray);388389if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }390}391#endif392393#ifdef P11_ENABLE_C_LOGOUT394/*395* Class: sun_security_pkcs11_wrapper_PKCS11396* Method: C_Logout397* Signature: (J)V398* Parametermapping: *PKCS11*399* @param jlong jSessionHandle CK_SESSION_HANDLE hSession400*/401JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Logout402(JNIEnv *env, jobject obj, jlong jSessionHandle)403{404CK_SESSION_HANDLE ckSessionHandle;405CK_RV rv;406407CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);408if (ckpFunctions == NULL) { return; }409410ckSessionHandle = jLongToCKULong(jSessionHandle);411412rv = (*ckpFunctions->C_Logout)(ckSessionHandle);413if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }414}415#endif416417/* ************************************************************************** */418/* Functions for keeping track of notify callbacks */419/* ************************************************************************** */420421#ifndef NO_CALLBACKS422423/*424* Add the given notify encapsulation object to the list of active notify425* objects.426* If notifyEncapsulation is NULL, this function does nothing.427*/428void putNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession, NotifyEncapsulation *notifyEncapsulation) {429NotifyListNode *currentNode, *newNode;430431if (notifyEncapsulation == NULL) {432return;433}434435newNode = (NotifyListNode *) malloc(sizeof(NotifyListNode));436if (newNode == NULL) {437throwOutOfMemoryError(env, 0);438return;439}440newNode->hSession = hSession;441newNode->notifyEncapsulation = notifyEncapsulation;442newNode->next = NULL;443444(*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */445446if (notifyListHead == NULL) {447/* this is the first entry */448notifyListHead = newNode;449} else {450/* go to the last entry; i.e. the first node which's 'next' is NULL.451*/452currentNode = notifyListHead;453while (currentNode->next != NULL) {454currentNode = currentNode->next;455}456currentNode->next = newNode;457}458459(*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */460}461462/*463* Removes the active notifyEncapsulation object used with the given session and464* returns it. If there is no notifyEncapsulation active for this session, this465* function returns NULL.466*/467NotifyEncapsulation * removeNotifyEntry(JNIEnv *env, CK_SESSION_HANDLE hSession) {468NotifyEncapsulation *notifyEncapsulation;469NotifyListNode *currentNode, *previousNode;470471(*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */472473if (notifyListHead == NULL) {474/* this is the first entry */475notifyEncapsulation = NULL;476} else {477/* Find the node with the wanted session handle. Also stop, when we reach478* the last entry; i.e. the first node which's 'next' is NULL.479*/480currentNode = notifyListHead;481previousNode = NULL;482483while ((currentNode->hSession != hSession) && (currentNode->next != NULL)) {484previousNode = currentNode;485currentNode = currentNode->next;486}487488if (currentNode->hSession == hSession) {489/* We found a entry for the wanted session, now remove it. */490if (previousNode == NULL) {491/* it's the first node */492notifyListHead = currentNode->next;493} else {494previousNode->next = currentNode->next;495}496notifyEncapsulation = currentNode->notifyEncapsulation;497free(currentNode);498} else {499/* We did not find a entry for this session */500notifyEncapsulation = NULL;501}502}503504(*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */505506return notifyEncapsulation ;507}508509/*510511* Removes the first notifyEncapsulation object. If there is no notifyEncapsulation,512* this function returns NULL.513*/514NotifyEncapsulation * removeFirstNotifyEntry(JNIEnv *env) {515NotifyEncapsulation *notifyEncapsulation;516NotifyListNode *currentNode;517518(*env)->MonitorEnter(env, notifyListLock); /* synchronize access to list */519520if (notifyListHead == NULL) {521/* this is the first entry */522notifyEncapsulation = NULL;523} else {524/* Remove the first entry. */525currentNode = notifyListHead;526notifyListHead = notifyListHead->next;527notifyEncapsulation = currentNode->notifyEncapsulation;528free(currentNode);529}530531(*env)->MonitorExit(env, notifyListLock); /* synchronize access to list */532533return notifyEncapsulation ;534}535536#endif /* NO_CALLBACKS */537538#ifndef NO_CALLBACKS539540/*541* The function handling notify callbacks. It casts the pApplication parameter542* back to a NotifyEncapsulation structure and retrieves the Notify object and543* the application data from it.544*545* @param hSession The session, this callback is comming from.546* @param event The type of event that occurred.547* @param pApplication The application data as passed in upon OpenSession. In548this wrapper we always pass in a NotifyEncapsulation549object, which holds necessary information for delegating550the callback to the Java VM.551* @return552*/553CK_RV notifyCallback(554CK_SESSION_HANDLE hSession, /* the session's handle */555CK_NOTIFICATION event,556CK_VOID_PTR pApplication /* passed to C_OpenSession */557)558{559NotifyEncapsulation *notifyEncapsulation;560extern JavaVM *jvm;561JNIEnv *env;562jint returnValue;563jlong jSessionHandle;564jlong jEvent;565jclass ckNotifyClass;566jmethodID jmethod;567jthrowable pkcs11Exception;568jclass pkcs11ExceptionClass;569jlong errorCode;570CK_RV rv = CKR_OK;571int wasAttached = 1;572573if (pApplication == NULL) { return rv ; } /* This should not occur in this wrapper. */574575notifyEncapsulation = (NotifyEncapsulation *) pApplication;576577/* Get the currently running Java VM */578if (jvm == NULL) { return rv ; } /* there is no VM running */579580/* Determine, if current thread is already attached */581returnValue = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_2);582if (returnValue == JNI_EDETACHED) {583/* thread detached, so attach it */584wasAttached = 0;585returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);586} else if (returnValue == JNI_EVERSION) {587/* this version of JNI is not supported, so just try to attach */588/* we assume it was attached to ensure that this thread is not detached589* afterwards even though it should not590*/591wasAttached = 1;592returnValue = (*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);593} else {594/* attached */595wasAttached = 1;596}597598jSessionHandle = ckULongToJLong(hSession);599jEvent = ckULongToJLong(event);600601ckNotifyClass = (*env)->FindClass(env, CLASS_NOTIFY);602if (ckNotifyClass == NULL) { return rv; }603jmethod = (*env)->GetMethodID(env, ckNotifyClass, "CK_NOTIFY", "(JJLjava/lang/Object;)V");604if (jmethod == NULL) { return rv; }605606(*env)->CallVoidMethod(env, notifyEncapsulation->jNotifyObject, jmethod,607jSessionHandle, jEvent, notifyEncapsulation->jApplicationData);608609/* check, if callback threw an exception */610pkcs11Exception = (*env)->ExceptionOccurred(env);611612if (pkcs11Exception != NULL) {613/* TBD: clear the pending exception with ExceptionClear? */614/* The was an exception thrown, now we get the error-code from it */615pkcs11ExceptionClass = (*env)->FindClass(env, CLASS_PKCS11EXCEPTION);616if (pkcs11ExceptionClass == NULL) { return rv; }617618jmethod = (*env)->GetMethodID(env, pkcs11ExceptionClass, "getErrorCode", "()J");619if (jmethod == NULL) { return rv; }620621errorCode = (*env)->CallLongMethod(env, pkcs11Exception, jmethod);622rv = jLongToCKULong(errorCode);623}624625/* if we attached this thread to the VM just for callback, we detach it now */626if (wasAttached) {627returnValue = (*jvm)->DetachCurrentThread(jvm);628}629630return rv ;631}632633#endif /* NO_CALLBACKS */634635636