void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, DWORD openHandle) { void* pUserData = NULL; void* pOpenHandle = (void*)(size_t) openHandle; pUserData = ListDictionary_GetItemValue(handles->open, pOpenHandle); return pUserData; }
static void terminate_pending_irp_threads(SERIAL_DEVICE* serial) { ULONG_PTR* ids; int i, nbIds; nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); WLog_Print(serial->log, WLOG_DEBUG, "Terminating %d IRP thread(s)", nbIds); for (i = 0; i < nbIds; i++) { HANDLE irpThread; ULONG_PTR id = ids[i]; irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); TerminateThread(irpThread, 0); if (WaitForSingleObject(irpThread, INFINITE) == WAIT_FAILED) { WLog_ERR(TAG, "WaitForSingleObject failed!"); continue; } CloseHandle(irpThread); WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*) id); } ListDictionary_Clear(serial->IrpThreads); }
HANDLE _GetCurrentThread(VOID) { HANDLE hdl = NULL; pthread_t tid = pthread_self(); if (!thread_list) { WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif } else if (!ListDictionary_Contains(thread_list, &tid)) { WLog_ERR(TAG, "function called, but no matching entry in thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif } else { hdl = ListDictionary_GetItemValue(thread_list, &tid); } return hdl; }
static BOOL rdg_handle_ntlm_challenge(rdpNtlm* ntlm, HttpResponse* response) { char* token64 = NULL; int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; if (response->StatusCode != HTTP_STATUS_DENIED) { WLog_DBG(TAG, "Unexpected NTLM challenge HTTP status: %d", response->StatusCode); return FALSE; } token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM"); if (!token64) return FALSE; crypto_base64_decode(token64, strlen(token64), &ntlmTokenData, &ntlmTokenLength); if (ntlmTokenData && ntlmTokenLength) { ntlm->inputBuffer[0].pvBuffer = ntlmTokenData; ntlm->inputBuffer[0].cbBuffer = ntlmTokenLength; } ntlm_authenticate(ntlm); return TRUE; }
void *get_callback_by_name(const char *name, void **context) { struct cb_value *rc; if (!cb_dict) { DEBUG_WARN("'%s' not found, function list does not exist.", name); return NULL; } if (!ListDictionary_Contains(cb_dict, (void *)name)) { DEBUG_WARN("'%s' not found", name); return NULL; } rc = ListDictionary_GetItemValue(cb_dict, (void *)name); DEBUG_DVC("'%s'=%p found", name, rc); if (context) *context = rc->context; return rc->fkt; }
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc, HttpResponse* response) { char* token64 = NULL; int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm; if (ListDictionary_Contains(response->Authenticates, "NTLM")) { token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM"); if (!token64) return -1; crypto_base64_decode(token64, strlen(token64), &ntlmTokenData, &ntlmTokenLength); } if (ntlmTokenData && ntlmTokenLength) { ntlm->inputBuffer[0].pvBuffer = ntlmTokenData; ntlm->inputBuffer[0].cbBuffer = ntlmTokenLength; } return 1; }
void* encomsp_get_open_handle_data(DWORD openHandle) { void* pUserData = NULL; void* pOpenHandle = (void*) (size_t) openHandle; pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle); return pUserData; }
static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id) { DRIVE_FILE* file = NULL; void* key = (void*)(size_t) id; file = (DRIVE_FILE*) ListDictionary_GetItemValue(drive->files, key); return file; }
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc) { char* token64; int ntlm_token_length = 0; BYTE* ntlm_token_data = NULL; HttpResponse* http_response; rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm; http_response = http_response_recv(rpc->TlsIn); if (!http_response) return -1; if (ListDictionary_Contains(http_response->Authenticates, "NTLM")) { token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM"); if (!token64) goto out; crypto_base64_decode(token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); } out: ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; http_response_free(http_response); return 0; }
BOOL rdg_process_out_channel_response(rdpRdg* rdg, HttpResponse* response) { int status; wStream* s; char* token64 = NULL; int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm = rdg->ntlm; if (response->StatusCode != HTTP_STATUS_DENIED) { WLog_DBG(TAG, "RDG not supported"); rdg->state = RDG_CLIENT_STATE_NOT_FOUND; return FALSE; } WLog_DBG(TAG, "Out Channel authorization required"); if (ListDictionary_Contains(response->Authenticates, "NTLM")) { token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM"); if (!token64) { return FALSE; } crypto_base64_decode(token64, strlen(token64), &ntlmTokenData, &ntlmTokenLength); } if (ntlmTokenData && ntlmTokenLength) { ntlm->inputBuffer[0].pvBuffer = ntlmTokenData; ntlm->inputBuffer[0].cbBuffer = ntlmTokenLength; } ntlm_authenticate(ntlm); s = rdg_build_http_request(rdg, "RDG_OUT_DATA"); if (!s) return FALSE; status = tls_write_all(rdg->tlsOut, Stream_Buffer(s), Stream_Length(s)); Stream_Free(s, TRUE); ntlm_free(rdg->ntlm); rdg->ntlm = NULL; if (status < 0) { return FALSE; } rdg->state = RDG_CLIENT_STATE_OUT_CHANNEL_AUTHORIZE; return TRUE; }
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id) { DEVICE* device = NULL; void* key = (void*) (size_t) id; device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key); return device; }
const char* http_response_get_auth_token(HttpResponse* respone, const char* method) { if (!respone || !method) return NULL; if (!ListDictionary_Contains(respone->Authenticates, method)) return NULL; return ListDictionary_GetItemValue(respone->Authenticates, method); }
void freerds_update_frame_acknowledge(rdpContext* context, UINT32 frameId) { SURFACE_FRAME* frame; rdsConnection* connection = (rdsConnection*) context; frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(connection->FrameList, (void*) (size_t) frameId); if (frame) { ListDictionary_Remove(connection->FrameList, (void*) (size_t) frameId); free(frame); } }
BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) { BYTE* pPlainText = NULL; size_t cbOut, cbFinal; WINPR_CIPHER_CTX* dec = NULL; WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = NULL; if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS) return FALSE; if (!g_ProtectedMemoryBlocks) return FALSE; pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData); if (!pMemBlock) goto out; cbOut = pMemBlock->cbData + 16 - 1; pPlainText = (BYTE*) malloc(cbOut); if (!pPlainText) goto out; if ((dec = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, pMemBlock->key, pMemBlock->iv)) == NULL) goto out; if (!winpr_Cipher_Update(dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut)) goto out; if (!winpr_Cipher_Final(dec, pPlainText + cbOut, &cbFinal)) goto out; winpr_Cipher_Free(dec); CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData); SecureZeroMemory(pPlainText, pMemBlock->cbData); free(pPlainText); ListDictionary_Remove(g_ProtectedMemoryBlocks, pData); free(pMemBlock); return TRUE; out: free(pPlainText); free(pMemBlock); winpr_Cipher_Free(dec); return FALSE; }
VOID ExitThread(DWORD dwExitCode) { DWORD rc; pthread_t tid = pthread_self(); if (!thread_list) { WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif pthread_exit(0); } else if (!ListDictionary_Contains(thread_list, &tid)) { WLog_ERR(TAG, "function called, but no matching entry in thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif pthread_exit(0); } else { WINPR_THREAD* thread; ListDictionary_Lock(thread_list); thread = ListDictionary_GetItemValue(thread_list, &tid); assert(thread); thread->exited = TRUE; thread->dwExitCode = dwExitCode; #if defined(WITH_DEBUG_THREADS) thread->exit_stack = winpr_backtrace(20); #endif ListDictionary_Unlock(thread_list); set_event(thread); rc = thread->dwExitCode; if (thread->detached || !thread->started) cleanup_handle(thread); pthread_exit((void*) (size_t) rc); } }
BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) { BYTE* pPlainText; int cbOut, cbFinal; WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock; if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS) return FALSE; if (!g_ProtectedMemoryBlocks) return FALSE; pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData); if (!pMemBlock) return FALSE; /* AES Decryption */ cbOut = pMemBlock->cbData + AES_BLOCK_SIZE - 1; pPlainText = (BYTE*) malloc(cbOut); EVP_DecryptInit_ex(&(pMemBlock->dec), NULL, NULL, NULL, NULL); EVP_DecryptUpdate(&(pMemBlock->dec), pPlainText, &cbOut, pMemBlock->pData, pMemBlock->cbData); EVP_DecryptFinal_ex(&(pMemBlock->dec), pPlainText + cbOut, &cbFinal); CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData); SecureZeroMemory(pPlainText, pMemBlock->cbData); free(pPlainText); ListDictionary_Remove(g_ProtectedMemoryBlocks, pData); /* AES Cleanup */ EVP_CIPHER_CTX_cleanup(&(pMemBlock->enc)); EVP_CIPHER_CTX_cleanup(&(pMemBlock->dec)); free(pMemBlock); return TRUE; }
static int pbrpc_process_response(rdsServer* server, FDSAPI_MSG_PACKET* msg) { pbRPCContext* context = server->rpc; pbRPCTransaction* ta = ListDictionary_GetItemValue(context->transactions, (void*)((UINT_PTR)msg->callId)); if (!ta) { fprintf(stderr,"unsoliciated response - ignoring (tag %d)\n", msg->callId); return 1; } ListDictionary_Remove(context->transactions, (void*)((UINT_PTR)msg->callId)); if (ta->responseCallback) ta->responseCallback(msg->status, msg, ta->callbackArg); if (ta->freeAfterResponse) free(ta); return 0; }
int TestListDictionary(int argc, char* argv[]) { int count; char* value; wListDictionary* list; list = ListDictionary_New(FALSE); ListDictionary_Add(list, key1, val1); ListDictionary_Add(list, key2, val2); ListDictionary_Add(list, key3, val3); count = ListDictionary_Count(list); if (count != 3) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count); return -1; } ListDictionary_Remove(list, key2); count = ListDictionary_Count(list); if (count != 2) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 2, count); return -1; } ListDictionary_Remove(list, key3); count = ListDictionary_Count(list); if (count != 1) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 1, count); return -1; } ListDictionary_Remove(list, key1); count = ListDictionary_Count(list); if (count != 0) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count); return -1; } ListDictionary_Add(list, key1, val1); ListDictionary_Add(list, key2, val2); ListDictionary_Add(list, key3, val3); count = ListDictionary_Count(list); if (count != 3) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count); return -1; } value = (char*) ListDictionary_GetItemValue(list, key1); if (strcmp(value, val1) != 0) { printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val1, value); return -1; } value = (char*) ListDictionary_GetItemValue(list, key2); if (strcmp(value, val2) != 0) { printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val2, value); return -1; } value = (char*) ListDictionary_GetItemValue(list, key3); if (strcmp(value, val3) != 0) { printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val3, value); return -1; } ListDictionary_SetItemValue(list, key2, "apple"); value = (char*) ListDictionary_GetItemValue(list, key2); if (strcmp(value, "apple") != 0) { printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", "apple", value); return -1; } if (!ListDictionary_Contains(list, key2)) { printf("ListDictionary_Contains: Expected : %d, Actual: %d\n", TRUE, FALSE); return -1; } ListDictionary_Clear(list); count = ListDictionary_Count(list); if (count != 0) { printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count); return -1; } ListDictionary_Free(list); return 0; }
static void smartcard_init(DEVICE* device) { int index; int keyCount; ULONG_PTR* pKeys; SCARDCONTEXT hContext; SMARTCARD_CONTEXT* pContext; SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; /** * On protocol termination, the following actions are performed: * For each context in rgSCardContextList, SCardCancel is called causing all outstanding messages to be processed. * After there are no more outstanding messages, SCardReleaseContext is called on each context and the context MUST * be removed from rgSCardContextList. */ /** * Call SCardCancel on existing contexts, unblocking all outstanding IRPs. */ if (ListDictionary_Count(smartcard->rgSCardContextList) > 0) { pKeys = NULL; keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys); for (index = 0; index < keyCount; index++) { pContext = (SMARTCARD_CONTEXT*) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]); if (!pContext) continue; hContext = pContext->hContext; if (SCardIsValidContext(hContext)) { SCardCancel(hContext); } } free(pKeys); } /** * Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList. */ if (ListDictionary_Count(smartcard->rgSCardContextList) > 0) { pKeys = NULL; keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys); for (index = 0; index < keyCount; index++) { pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, (void*) pKeys[index]); if (!pContext) continue; hContext = pContext->hContext; if (SCardIsValidContext(hContext)) { SCardReleaseContext(hContext); } } free(pKeys); } }
LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { rdpdrPlugin *rdpdr; PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam; rdpdr = (rdpdrPlugin *)GetWindowLongPtr(hWnd, GWLP_USERDATA); switch(Msg) { case WM_DEVICECHANGE: switch (wParam) { case DBT_DEVICEARRIVAL: if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; DWORD unitmask = lpdbv->dbcv_unitmask; int i; char drive_path[4] = { 'c', ':', '/', '\0'}; for (i = 0; i < 26; i++) { if (unitmask & 0x01) { RDPDR_DRIVE* drive; drive_path[0] = 'A' + i; drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); ZeroMemory(drive, sizeof(RDPDR_DRIVE)); drive->Type = RDPDR_DTYP_FILESYSTEM; drive->Path = _strdup(drive_path); drive_path[1] = '\0'; drive->Name = _strdup(drive_path); devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive); rdpdr_send_device_list_announce_request(rdpdr, TRUE); } unitmask = unitmask >> 1; } } break; case DBT_DEVICEREMOVECOMPLETE: if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; DWORD unitmask = lpdbv->dbcv_unitmask; int i, j, count; char drive_name_upper, drive_name_lower; ULONG_PTR *keys; DEVICE_DRIVE_EXT *device_ext; UINT32 ids[1]; for (i = 0; i < 26; i++) { if (unitmask & 0x01) { drive_name_upper = 'A' + i; drive_name_lower = 'a' + i; count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); for (j = 0; j < count; j++) { device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); if (device_ext->path[0] == drive_name_upper || device_ext->path[0] == drive_name_lower) { devman_unregister_device(rdpdr->devman, (void *)keys[j]); ids[0] = keys[j]; rdpdr_send_device_list_remove_request(rdpdr, 1, ids); break; } } } unitmask = unitmask >> 1; } } break; default: break; }
void* encomsp_get_init_handle_data(void* pInitHandle) { void* pUserData = NULL; pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle); return pUserData; }
VOID DumpThreadHandles(void) { char** msg; size_t used, i; void* stack = winpr_backtrace(20); WLog_DBG(TAG, "---------------- Called from ----------------------------"); msg = winpr_backtrace_symbols(stack, &used); for (i = 0; i < used; i++) { WLog_DBG(TAG, "[%d]: %s", i, msg[i]); } free(msg); winpr_backtrace_free(stack); WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------"); if (!thread_list) { WLog_DBG(TAG, "All threads properly shut down and disposed of."); } else { ULONG_PTR* keys = NULL; ListDictionary_Lock(thread_list); int x, count = ListDictionary_GetKeys(thread_list, &keys); WLog_DBG(TAG, "Dumping %d elements", count); for (x = 0; x < count; x++) { WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list, (void*) keys[x]); WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x); msg = winpr_backtrace_symbols(thread->create_stack, &used); for (i = 0; i < used; i++) { WLog_DBG(TAG, "[%d]: %s", i, msg[i]); } free(msg); if (thread->started) { WLog_DBG(TAG, "Thread [%d] still running!", x); } else { WLog_DBG(TAG, "Thread [%d] exited at:", x); msg = winpr_backtrace_symbols(thread->exit_stack, &used); for (i = 0; i < used; i++) WLog_DBG(TAG, "[%d]: %s", i, msg[i]); free(msg); } } free(keys); ListDictionary_Unlock(thread_list); } WLog_DBG(TAG, "---------------- End Dumping thread handles -------------"); }
void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, void* pInitHandle) { void* pUserData = NULL; pUserData = ListDictionary_GetItemValue(handles->init, pInitHandle); return pUserData; }
static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) { int index; int keyCount; ULONG_PTR* pKeys; SCARDCONTEXT hContext; SMARTCARD_CONTEXT* pContext; /** * On protocol termination, the following actions are performed: * For each context in rgSCardContextList, SCardCancel is called causing all SCardGetStatusChange calls to be processed. * After that, SCardReleaseContext is called on each context and the context MUST be removed from rgSCardContextList. */ /** * Call SCardCancel on existing contexts, unblocking all outstanding SCardGetStatusChange calls. */ if (ListDictionary_Count(smartcard->rgSCardContextList) > 0) { pKeys = NULL; keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys); for (index = 0; index < keyCount; index++) { pContext = (SMARTCARD_CONTEXT*) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]); if (!pContext) continue; hContext = pContext->hContext; if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS) { SCardCancel(hContext); } } free(pKeys); } /** * Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList. */ if (ListDictionary_Count(smartcard->rgSCardContextList) > 0) { pKeys = NULL; keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys); for (index = 0; index < keyCount; index++) { pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, (void*) pKeys[index]); if (!pContext) continue; hContext = pContext->hContext; if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS) { SCardReleaseContext(hContext); if (MessageQueue_PostQuit(pContext->IrpQueue, 0) && (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)) WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); CloseHandle(pContext->thread); MessageQueue_Free(pContext->IrpQueue); free(pContext); } } free(pKeys); } }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; LONG status; BOOL asyncIrp = FALSE; SMARTCARD_CONTEXT* pContext = NULL; SMARTCARD_OPERATION* operation = NULL; key = (void*) (size_t) irp->CompletionId; if (!ListDictionary_Add(smartcard->rgOutstandingMessages, key, irp)) { WLog_ERR(TAG, "ListDictionary_Add failed!"); return ERROR_INTERNAL_ERROR; } if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) { operation = (SMARTCARD_OPERATION*) calloc(1, sizeof(SMARTCARD_OPERATION)); if (!operation) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } operation->irp = irp; status = smartcard_irp_device_control_decode(smartcard, operation); if (status != SCARD_S_SUCCESS) { irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL; if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) { WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } return CHANNEL_RC_OK; } asyncIrp = TRUE; /** * The following matches mstsc's behavior of processing * only certain requests asynchronously while processing * those expected to return fast synchronously. */ switch (operation->ioControlCode) { case SCARD_IOCTL_ESTABLISHCONTEXT: case SCARD_IOCTL_RELEASECONTEXT: case SCARD_IOCTL_ISVALIDCONTEXT: case SCARD_IOCTL_LISTREADERGROUPSA: case SCARD_IOCTL_LISTREADERGROUPSW: case SCARD_IOCTL_LISTREADERSA: case SCARD_IOCTL_LISTREADERSW: case SCARD_IOCTL_INTRODUCEREADERGROUPA: case SCARD_IOCTL_INTRODUCEREADERGROUPW: case SCARD_IOCTL_FORGETREADERGROUPA: case SCARD_IOCTL_FORGETREADERGROUPW: case SCARD_IOCTL_INTRODUCEREADERA: case SCARD_IOCTL_INTRODUCEREADERW: case SCARD_IOCTL_FORGETREADERA: case SCARD_IOCTL_FORGETREADERW: case SCARD_IOCTL_ADDREADERTOGROUPA: case SCARD_IOCTL_ADDREADERTOGROUPW: case SCARD_IOCTL_REMOVEREADERFROMGROUPA: case SCARD_IOCTL_REMOVEREADERFROMGROUPW: case SCARD_IOCTL_LOCATECARDSA: case SCARD_IOCTL_LOCATECARDSW: case SCARD_IOCTL_LOCATECARDSBYATRA: case SCARD_IOCTL_LOCATECARDSBYATRW: case SCARD_IOCTL_CANCEL: case SCARD_IOCTL_READCACHEA: case SCARD_IOCTL_READCACHEW: case SCARD_IOCTL_WRITECACHEA: case SCARD_IOCTL_WRITECACHEW: case SCARD_IOCTL_GETREADERICON: case SCARD_IOCTL_GETDEVICETYPEID: asyncIrp = FALSE; break; case SCARD_IOCTL_GETSTATUSCHANGEA: case SCARD_IOCTL_GETSTATUSCHANGEW: asyncIrp = TRUE; break; case SCARD_IOCTL_CONNECTA: case SCARD_IOCTL_CONNECTW: case SCARD_IOCTL_RECONNECT: case SCARD_IOCTL_DISCONNECT: case SCARD_IOCTL_BEGINTRANSACTION: case SCARD_IOCTL_ENDTRANSACTION: case SCARD_IOCTL_STATE: case SCARD_IOCTL_STATUSA: case SCARD_IOCTL_STATUSW: case SCARD_IOCTL_TRANSMIT: case SCARD_IOCTL_CONTROL: case SCARD_IOCTL_GETATTRIB: case SCARD_IOCTL_SETATTRIB: case SCARD_IOCTL_GETTRANSMITCOUNT: asyncIrp = TRUE; break; case SCARD_IOCTL_ACCESSSTARTEDEVENT: case SCARD_IOCTL_RELEASESTARTEDEVENT: asyncIrp = FALSE; break; } pContext = ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) operation->hContext); if (!pContext) asyncIrp = FALSE; if (!asyncIrp) { if ((status = smartcard_irp_device_control_call(smartcard, operation))) { WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %lu!", status); return (UINT32)status; } if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) { WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } free(operation); } else { if (pContext) { if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*) operation, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; } } } } else { WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X", irp->MajorFunction, irp->MinorFunction); irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED; if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) { WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } } return CHANNEL_RC_OK; }
static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) { IRP_THREAD_DATA* data = NULL; HANDLE irpThread; HANDLE previousIrpThread; uintptr_t key; /* for a test/debug purpose, uncomment the code below to get a * single thread for all IRPs. NB: two IRPs could not be * processed at the same time, typically two concurent * Read/Write operations could block each other. */ /* serial_process_irp(serial, irp); */ /* irp->Complete(irp); */ /* return; */ /* NOTE: for good or bad, this implementation relies on the * server to avoid a flooding of requests. see also _purge(). */ EnterCriticalSection(&serial->TerminatingIrpThreadsLock); while (serial->IrpThreadToBeTerminatedCount > 0) { /* Cleaning up termitating and pending irp * threads. See also: irp_thread_func() */ HANDLE irpThread; ULONG_PTR* ids; int i, nbIds; nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids); for (i = 0; i < nbIds; i++) { /* Checking if ids[i] is terminating or pending */ DWORD waitResult; ULONG_PTR id = ids[i]; irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ waitResult = WaitForSingleObject(irpThread, 0); if (waitResult == WAIT_OBJECT_0) { /* terminating thread */ /* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz" naturally died", id); */ CloseHandle(irpThread); ListDictionary_Remove(serial->IrpThreads, (void*)id); serial->IrpThreadToBeTerminatedCount--; } else if (waitResult != WAIT_TIMEOUT) { /* unexpected thread state */ WLog_Print(serial->log, WLOG_WARN, "WaitForSingleObject, got an unexpected result=0x%"PRIX32"\n", waitResult); assert(FALSE); } /* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */ } if (serial->IrpThreadToBeTerminatedCount > 0) { WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount); Sleep(1); /* 1 ms */ } } LeaveCriticalSection(&serial->TerminatingIrpThreadsLock); /* NB: At this point and thanks to the synchronization we're * sure that the incoming IRP uses well a recycled * CompletionId or the server sent again an IRP already posted * which didn't get yet a response (this later server behavior * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and * mstsc.exe). * * FIXME: behavior documented somewhere? behavior not yet * observed with FreeRDP). */ key = irp->CompletionId; previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key); if (previousIrpThread) { /* Thread still alived <=> Request still pending */ WLog_Print(serial->log, WLOG_DEBUG, "IRP recall: IRP with the CompletionId=%"PRIu32" not yet completed!", irp->CompletionId); assert(FALSE); /* unimplemented */ /* TODO: asserts that previousIrpThread handles well * the same request by checking more details. Need an * access to the IRP object used by previousIrpThread */ /* TODO: taking over the pending IRP or sending a kind * of wake up signal to accelerate the pending * request * * To be considered: * if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { * pComm->PendingEvents |= SERIAL_EV_FREERDP_*; * } */ irp->Discard(irp); return; } if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS) { WLog_Print(serial->log, WLOG_WARN, "Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads)); assert(FALSE); /* unimplemented */ /* TODO: MAX_IRP_THREADS has been thought to avoid a * flooding of pending requests. Use * WaitForMultipleObjects() when available in winpr * for threads. */ } /* error_handle to be used ... */ data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA)); if (data == NULL) { WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA."); goto error_handle; } data->serial = serial; data->irp = irp; /* data freed by irp_thread_func */ irpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)irp_thread_func, (void*)data, 0, NULL); if (irpThread == INVALID_HANDLE_VALUE) { WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread."); goto error_handle; } key = irp->CompletionId; if (!ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread)) { WLog_ERR(TAG, "ListDictionary_Add failed!"); goto error_handle; } return; error_handle: irp->IoStatus = STATUS_NO_MEMORY; irp->Complete(irp); free(data); }