From: Guillaume Raffin <theelectronwill@gmail.com> --- dlls/winscard/tests/winscard.c | 131 +++++++++++++++++++++++++++++++++ dlls/winscard/winscard.c | 87 ++++++++++++++++++++-- 2 files changed, 210 insertions(+), 8 deletions(-) diff --git a/dlls/winscard/tests/winscard.c b/dlls/winscard/tests/winscard.c index f5138c44f00..16bfd0bb7d2 100644 --- a/dlls/winscard/tests/winscard.c +++ b/dlls/winscard/tests/winscard.c @@ -568,6 +568,136 @@ static void test_SCardListCardsW(void) free(matching_cards); } +static void test_SCardListCardsA(void) +{ + LONG ret; + const CHAR *expected; + SCARDCONTEXT ctx = 0; /* SCardListCards does not need a context */ + BYTE atr_full[36]; + DWORD match_len = 0; + CHAR *matching_cards; + + /* test basic error conditions */ + ret = SCardListCardsA(ctx, NULL, NULL, 0, NULL, NULL); + ok(ret == SCARD_E_INVALID_PARAMETER, "should fail when inout_cards_len is null\n"); + + match_len = 2; + matching_cards = calloc(match_len, sizeof(WCHAR)); + ret = SCardListCardsA(ctx, NULL, NULL, 0, matching_cards, &match_len); + ok(ret == SCARD_E_INSUFFICIENT_BUFFER, "should fail when the output buffer is too small\n"); + free(matching_cards); + + /* get length of match */ + ret = SCardListCardsA(ctx, NULL, NULL, 0, NULL, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list all cards: error %#lx\n", ret); + ok(match_len > 0, "match size should not be empty"); + + /* allocate and call */ + matching_cards = calloc(match_len, sizeof(WCHAR)); + ret = SCardListCardsA(ctx, NULL, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list all cards: error %#lx\n", ret); + expected = "PKI-test-1\0PKI-test-2\0"; + ok(match_len == 23, "invalid length: expected %ld, got %ld\n", 23L, match_len); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + free(matching_cards); + + /* test with pre-allocated */ + match_len = 32; + matching_cards = malloc(match_len); + memset(matching_cards, 0xca, match_len); + ret = SCardListCardsA(ctx, NULL, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list all cards: error %#lx\n", ret); + expected = "PKI-test-1\0PKI-test-2\0"; + ok(match_len == 23, "invalid length: expected %ld, got %ld\n", 23L, match_len); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + for (int i = match_len+1; i < 32; i++) + { + ok((BYTE)matching_cards[i] == 0xca, "memory corruption\n"); + } + free(matching_cards); + + /* test with auto alloc */ + match_len = SCARD_AUTOALLOCATE; + matching_cards = NULL; + ret = SCardListCardsA(ctx, NULL, NULL, 0, (CHAR *)&matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list all cards: error %#lx\n", ret); + expected = "PKI-test-1\0PKI-test-2\0\0"; + ok(match_len == 23, "invalid length: expected %ld, got %ld\n", 23L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + ret = SCardFreeMemory(ctx, matching_cards); + ok(ret == ERROR_SUCCESS, "failed to free auto-allocated memory\n"); + + /* test with ATRs that match exactly card 1 */ + match_len = 32; + matching_cards = calloc(match_len, sizeof(WCHAR)); + ret = SCardListCardsA(ctx, CARD_ATR_1, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list card 1: error %#lx\n", ret); + expected = "PKI-test-1\0"; + ok(match_len == 12, "invalid length: expected %ld, got %ld\n", 12L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + /* test with ATRs that match exactly card 2 */ + match_len = 32; + ret = SCardListCardsA(ctx, CARD_ATR_2, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list card 2: error %#lx\n", ret); + expected = "PKI-test-2\0"; + ok(match_len == 12, "invalid length: expected %ld, got %ld\n", 12L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + /* test with zero-padded ATR that match */ + for (int i = 0; i < sizeof(CARD_ATR_2); i++) { + atr_full[i] = CARD_ATR_2[i]; + } + for (int i = sizeof(CARD_ATR_2); i < sizeof(atr_full); i++) { + atr_full[i] = 0; + } + match_len = 32; + ret = SCardListCardsA(ctx, atr_full, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list card 2: error %#lx\n", ret); + expected = "PKI-test-2\0"; + ok(match_len == 12, "invalid length: expected %ld, got %ld\n", 12L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + /* test with an ATR that matches thanks to the mask */ + for (int i = 0; i < sizeof(CARD_ATR_2)-1; i++) { + atr_full[i] = CARD_ATR_2[i]; + } + atr_full[sizeof(CARD_ATR_2)-1] = 0xff; + for (int i = sizeof(CARD_ATR_2); i < sizeof(atr_full); i++) { + atr_full[i] = 0; + } + match_len = 32; + ret = SCardListCardsA(ctx, atr_full, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list card 2: error %#lx\n", ret); + expected = "PKI-test-2\0"; + ok(match_len == 12, "invalid length: expected %ld, got %ld\n", 12L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + /* test with an ATR that doesn't match */ + atr_full[0] = 0x3B; + atr_full[1] = 0x02; + atr_full[2] = 0x14; + atr_full[3] = 0x50; + for (int i = 4; i < sizeof(atr_full); i++) { + atr_full[i] = 0; + } + match_len = 32; + ret = SCardListCardsA(ctx, atr_full, NULL, 0, matching_cards, &match_len); + ok(ret == ERROR_SUCCESS, "failed to list no card: error %#lx\n", ret); + expected = ""; + ok(match_len == 1, "invalid length: expected %ld, got %ld\n", 1L, match_len); + ok(matching_cards != NULL, "the buffer should have been allocated, is NULL\n"); + ok(memcmp(matching_cards, expected, match_len) == 0, "bad output of SCardListCardsA: %s\n", debugstr_an(matching_cards, match_len)); + + free(matching_cards); +} + static void test_smartcard_db(void) { LONG ret; @@ -578,6 +708,7 @@ static void test_smartcard_db(void) test_SCardGetCardTypeProviderName(); test_SCardListCardsW(); + test_SCardListCardsA(); } START_TEST(winscard) diff --git a/dlls/winscard/winscard.c b/dlls/winscard/winscard.c index f8c132ae7ec..908554c5b1a 100644 --- a/dlls/winscard/winscard.c +++ b/dlls/winscard/winscard.c @@ -188,14 +188,6 @@ LONG WINAPI SCardIsValidContext( SCARDCONTEXT context ) return ret; } -LONG WINAPI SCardListCardsA( SCARDCONTEXT context, const BYTE *atr, const GUID *interfaces, DWORD interface_count, - char *cards, DWORD *cards_len ) -{ - FIXME( "%Ix, %p, %p, %lu, %p, %p stub\n", context, atr, interfaces, interface_count, cards, cards_len ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return SCARD_F_INTERNAL_ERROR; -} - LONG WINAPI SCardReleaseContext( SCARDCONTEXT context ) { struct handle *handle = (struct handle *)context; @@ -1334,6 +1326,85 @@ LONG WINAPI SCardListCardsW(SCARDCONTEXT context, const BYTE *atr, const GUID *i return SCARD_S_SUCCESS; } +/******************************************************************************* + * SCardListCardsA (winscard.@) + * + * Look up known cards in the smart card database. + * See SCardListCardsW + */ +LONG WINAPI SCardListCardsA(SCARDCONTEXT context, const BYTE *atr, const GUID *interfaces, DWORD interface_count, char *cards, DWORD *cards_len) +{ + WCHAR *cardsW; + DWORD cards_lenW; + LONG ret; + int converted_len; + + TRACE( "%Ix, %s, %p, %lu, %p, %p\n", context, debug_atr(atr), interfaces, interface_count, cards, cards_len ); + + if (!cards_len) return SCARD_E_INVALID_PARAMETER; + if (!cards) return SCardListCardsW(context, atr, interfaces, interface_count, NULL, cards_len); + + if (*cards_len == SCARD_AUTOALLOCATE) + { + char **new_output; + cards_lenW = SCARD_AUTOALLOCATE; + cardsW = NULL; + ret = SCardListCardsW(context, atr, interfaces, interface_count, (LPWSTR)&cardsW, &cards_lenW); + if (ret != ERROR_SUCCESS) return ret; + + /* determine the size that we need to allocate */ + converted_len = WideCharToMultiByte(CP_ACP, 0, cardsW, cards_lenW, NULL, 0, NULL, NULL); + if (converted_len == 0) + { + FIXME("can't convert %s to ANSI codepage\n", debugstr_w(cardsW)); + return SCARD_F_INTERNAL_ERROR; + } + new_output = (char**)cards; + *new_output = malloc(converted_len); + if (*new_output == NULL) return ERROR_NOT_ENOUGH_MEMORY; + + /* convert */ + WideCharToMultiByte(CP_ACP, 0, cardsW, cards_lenW, *new_output, converted_len, NULL, NULL); + *cards_len = converted_len; + SCardFreeMemory(context, cardsW); + + TRACE("returning %s at %p, length %lu\n", debugstr_an(*new_output, *cards_len), *new_output, *cards_len); + } + else + { + cards_lenW = *cards_len; + cardsW = calloc(cards_lenW, sizeof(WCHAR)); + + ret = SCardListCardsW(context, atr, interfaces, interface_count, cardsW, &cards_lenW); + if (ret != ERROR_SUCCESS) + { + free(cardsW); + return ret; + } + + /* determine the size after conversion and check it */ + converted_len = WideCharToMultiByte(CP_ACP, 0, cardsW, cards_lenW, NULL, 0, NULL, NULL); + if (converted_len == 0) + { + FIXME("can't convert %s to ANSI codepage\n", debugstr_w(cardsW)); + return SCARD_F_INTERNAL_ERROR; + } + + if (converted_len > *cards_len) + { + return SCARD_E_INSUFFICIENT_BUFFER; + } + + /* convert */ + WideCharToMultiByte(CP_ACP, 0, cardsW, cards_lenW, cards, converted_len, NULL, NULL); + *cards_len = converted_len; + free(cardsW); + + TRACE("returning %s, length %lu\n", debugstr_an(cards, *cards_len), *cards_len); + } + return ERROR_SUCCESS; +} + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) { switch (reason) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10751