From: Guillaume Raffin <theelectronwill@gmail.com> --- dlls/winscard/tests/winscard.c | 99 +++++++++++++++++++++++++++++++++- dlls/winscard/winscard.c | 84 +++++++++++++++++++++++++++++ dlls/winscard/winscard.spec | 2 +- 3 files changed, 182 insertions(+), 3 deletions(-) diff --git a/dlls/winscard/tests/winscard.c b/dlls/winscard/tests/winscard.c index 16bfd0bb7d2..7f3f5420c4c 100644 --- a/dlls/winscard/tests/winscard.c +++ b/dlls/winscard/tests/winscard.c @@ -337,7 +337,7 @@ static LONG populate_smartcard_db(void) return 0; } -static void test_SCardGetCardTypeProviderName(void) +static void test_SCardGetCardTypeProviderNameW(void) { LONG ret; SCARDCONTEXT ctx = 0; /* SCardGetCardTypeProviderName does not need a context */ @@ -439,6 +439,100 @@ static void test_SCardGetCardTypeProviderName(void) ok(ret == ERROR_SUCCESS, "failed to release context: error %ld\n", ret); } +static void test_SCardGetCardTypeProviderNameA(void) +{ + LONG ret; + SCARDCONTEXT ctx = 0; /* SCardGetCardTypeProviderName does not need a context */ + DWORD len = 0; + CHAR *provider; + + /* test basic error conditions */ + provider = malloc(1); + ret = SCardGetCardTypeProviderNameA(ctx, NULL, SCARD_PROVIDER_CARD_MODULE, provider, &len); + ok(ret == SCARD_E_INVALID_PARAMETER, "should fail when card_type is null\n"); + + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, provider, NULL); + ok(ret == SCARD_E_INVALID_PARAMETER, "should fail when length is null\n"); + free(provider); + + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, NULL, &len); + ok(ret == SCARD_E_INVALID_PARAMETER, "should fail when provider is null\n"); + + /* test lookup with a pre-allocated space */ + len = 4; /* too small */ + provider = calloc(len, 1); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, provider, &len); + ok(ret == SCARD_E_INSUFFICIENT_BUFFER, "should have failed with SCARD_E_INSUFFICIENT_BUFFER but returned %#lx\n", ret); + ok(len == 4, "the length should not have been set, but was %ld\n", len); + ok(provider[0] == 0, "the provider should not have been set, but was %s\n", debugstr_a(provider)); + free(provider); + + len = 32; /* ok */ + provider = malloc(len); + memset(provider, 0xca, len); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "opensc-driver.dll") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + for (int i = len+1; i < 32; i++) + { + ok((BYTE)provider[i] == 0xca, "memory corruption\n"); + } + free(provider); + + len = 32; + provider = calloc(len, 1); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_2, SCARD_PROVIDER_CARD_MODULE, provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "cardoscm64.dll") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + free(provider); + + len = 32; + provider = calloc(len, 1); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_2, SCARD_PROVIDER_KSP, provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "Test Key Storage Provider") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + free(provider); + + len = 32; + provider = calloc(len, 1); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_2, SCARD_PROVIDER_CSP, provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "Test Crypto Provider") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + free(provider); + + /* test with a context */ + ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &ctx); + ok(ret == ERROR_SUCCESS, "failed to establish context: error %ld\n", ret); + if (ret) return; + + len = 32; + provider = calloc(len, 1); + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "opensc-driver.dll") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + free(provider); + + /* test with auto alloc */ + len = SCARD_AUTOALLOCATE; + provider = NULL; + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CARD_MODULE, (LPSTR)&provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "opensc-driver.dll") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + ok(len == strlen(provider)+1, "bad length from SCardGetCardTypeProviderNameA: got %lu, expected %zu\n", len, strlen(provider)+1); + SCardFreeMemory(ctx, provider); + + len = SCARD_AUTOALLOCATE; + provider = NULL; + ret = SCardGetCardTypeProviderNameA(ctx, CARD_NAME_1, SCARD_PROVIDER_CSP, (LPSTR)&provider, &len); + ok(ret == ERROR_SUCCESS, "SCardGetCardTypeProviderNameA returned an error: %#lx\n", ret); + ok(strcmp(provider, "Microsoft Base Smart Card Crypto Provider") == 0, "bad output of SCardGetCardTypeProviderNameA: '%s' (len %ld)\n", provider, len); + ok(len == strlen(provider)+1, "bad length from SCardGetCardTypeProviderNameA: got %lu, expected %zu\n", len, strlen(provider)+1); + SCardFreeMemory(ctx, provider); + + ret = SCardReleaseContext(ctx); + ok(ret == ERROR_SUCCESS, "failed to release context: error %ld\n", ret); +} + static void test_SCardListCardsW(void) { LONG ret; @@ -706,7 +800,8 @@ static void test_smartcard_db(void) ok(ret == ERROR_SUCCESS, "failed to populate database: error %ld\n", ret); if (ret) return; - test_SCardGetCardTypeProviderName(); + test_SCardGetCardTypeProviderNameW(); + test_SCardGetCardTypeProviderNameA(); test_SCardListCardsW(); test_SCardListCardsA(); } diff --git a/dlls/winscard/winscard.c b/dlls/winscard/winscard.c index 908554c5b1a..6b9c2331c8b 100644 --- a/dlls/winscard/winscard.c +++ b/dlls/winscard/winscard.c @@ -1064,6 +1064,90 @@ LONG WINAPI SCardGetCardTypeProviderNameW(SCARDCONTEXT context, const WCHAR *car return SCARD_S_SUCCESS; } +/******************************************************************************* + * SCardGetCardTypeProviderNameA (winscard.@) + * + * See SCardGetCardTypeProviderNameW + */ +LONG WINAPI SCardGetCardTypeProviderNameA(SCARDCONTEXT context, const CHAR *card_type, DWORD provider_id, char *out_provider, DWORD *inout_provider_len) +{ + LONG ret = SCARD_S_SUCCESS; + WCHAR *card_typeW; + WCHAR *providerW; + DWORD provider_lenW; + int converted_len; + + TRACE("%Ix, %s, %lu, %p, %p\n", context, debugstr_a(card_type), provider_id, out_provider, inout_provider_len); + + if (!card_type || !out_provider || !inout_provider_len) return SCARD_E_INVALID_PARAMETER; + if (ansi_to_utf16(card_type, &card_typeW) < 0) return ERROR_NOT_ENOUGH_MEMORY; + + if (*inout_provider_len == SCARD_AUTOALLOCATE) + { + char **new_output; + provider_lenW = SCARD_AUTOALLOCATE; + providerW = NULL; + ret = SCardGetCardTypeProviderNameW(context, card_typeW, provider_id, (LPWSTR)&providerW, &provider_lenW); + if (ret != ERROR_SUCCESS) goto end; + + /* determine the size that we need to allocate */ + converted_len = WideCharToMultiByte(CP_ACP, 0, providerW, provider_lenW, NULL, 0, NULL, NULL); + if (converted_len == 0) + { + FIXME("can't convert %s to ANSI codepage\n", debugstr_w(providerW)); + ret = SCARD_F_INTERNAL_ERROR; + goto end; + } + new_output = (char**)out_provider; + *new_output = malloc(converted_len); + if (*new_output == NULL) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto end; + } + + /* convert */ + WideCharToMultiByte(CP_ACP, 0, providerW, provider_lenW, *new_output, converted_len, NULL, NULL); + *inout_provider_len = converted_len; + SCardFreeMemory(context, providerW); + } else { + provider_lenW = *inout_provider_len; + providerW = calloc(provider_lenW, sizeof(WCHAR)); + + ret = SCardGetCardTypeProviderNameW(context, card_typeW, provider_id, providerW, &provider_lenW); + if (ret != ERROR_SUCCESS) { + free(providerW); + goto end; + } + + /* determine the size after conversion and check it */ + converted_len = WideCharToMultiByte(CP_ACP, 0, providerW, provider_lenW, NULL, 0, NULL, NULL); + if (converted_len == 0) + { + FIXME("can't convert %s to ANSI codepage\n", debugstr_w(providerW)); + ret = SCARD_F_INTERNAL_ERROR; + goto end; + } + + if (converted_len > *inout_provider_len) + { + ret = SCARD_E_INSUFFICIENT_BUFFER; + goto end; + } + + /* convert */ + WideCharToMultiByte(CP_ACP, 0, providerW, provider_lenW, out_provider, converted_len, NULL, NULL); + *inout_provider_len = converted_len; + free(providerW); + } + + end: + free(card_typeW); + if (ret != SCARD_S_SUCCESS) TRACE("returning %#lx\n", ret); + else TRACE("returning %#lx: %s\n", ret, debugstr_an(out_provider, *inout_provider_len)); + return ret; +} + /** * Parses an ATR string and returns its length, or -1 if the ATR is invalid. * diff --git a/dlls/winscard/winscard.spec b/dlls/winscard/winscard.spec index a50f39d9f04..837c5a66657 100644 --- a/dlls/winscard/winscard.spec +++ b/dlls/winscard/winscard.spec @@ -21,7 +21,7 @@ @ stub SCardForgetReaderW @ stdcall SCardFreeMemory(long ptr) @ stdcall SCardGetAttrib(long long ptr ptr) -@ stub SCardGetCardTypeProviderNameA +@ stdcall SCardGetCardTypeProviderNameA(long str long str ptr) @ stdcall SCardGetCardTypeProviderNameW(long wstr long wstr ptr) @ stub SCardGetProviderIdA @ stub SCardGetProviderIdW -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10751