/* * Copyright 2007 Mounir IDRASSI (mounir.idrassi@idrix.fr, for IDRIX) * Copyright 2022 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "windef.h" #include "winbase.h" #include "winscard.h" #include "winternl.h" #include "wine/debug.h" #include "wine/unixlib.h" #include "unixlib.h" WINE_DEFAULT_DEBUG_CHANNEL(winscard); #define UNIX_CALL( func, params ) WINE_UNIX_CALL( unix_ ## func, params ) static HANDLE g_startedEvent; const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 }; const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 }; const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 }; static inline int utf16_to_utf8( const WCHAR *src, char **dst ) { int len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ); if (dst) { if (!(*dst = malloc( len ))) return -1; WideCharToMultiByte( CP_UTF8, 0, src, -1, *dst, len, NULL, NULL ); } return len; } static inline int ansi_to_utf16( const char *src, WCHAR **dst ) { int len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); if (dst) { if (!(*dst = malloc( len * sizeof(WCHAR) ))) return -1; MultiByteToWideChar( CP_ACP, 0, src, -1, *dst, len ); } return len; } static inline int ansi_to_utf8( const char *src, char **dst ) { WCHAR *tmp; int len; if (ansi_to_utf16( src, &tmp ) < 0) return -1; len = utf16_to_utf8( tmp, dst ); free( tmp ); return len; } static inline int utf8_to_utf16( const char *src, WCHAR **dst ) { int len = MultiByteToWideChar( CP_UTF8, 0, src, -1, NULL, 0 ); if (dst) { if (!(*dst = malloc( len * sizeof(WCHAR) ))) return -1; MultiByteToWideChar( CP_UTF8, 0, src, -1, *dst, len ); } return len; } static inline int utf16_to_ansi( const WCHAR *src, char **dst ) { int len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, src, -1, NULL, 0, NULL, NULL ); if (*src && !len) { FIXME( "can't convert %s to ANSI codepage\n", debugstr_w(src) ); return -1; } if (dst) { if (!(*dst = malloc( len ))) return -1; WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, src, -1, *dst, len, NULL, NULL ); } return len; } static inline int utf8_to_ansi( const char *src, char **dst ) { WCHAR *tmp; int len; if (utf8_to_utf16( src, &tmp ) < 0) return -1; len = utf16_to_ansi( tmp, dst ); free( tmp ); return len; } HANDLE WINAPI SCardAccessStartedEvent(void) { FIXME( "stub\n" ); return g_startedEvent; } LONG WINAPI SCardAddReaderToGroupA( SCARDCONTEXT context, const char *reader, const char *group ) { WCHAR *readerW = NULL, *groupW = NULL; LONG ret; TRACE( "%Ix, %s, %s\n", context, debugstr_a(reader), debugstr_a(group) ); if (reader && ansi_to_utf16( reader, &readerW ) < 0) return SCARD_E_NO_MEMORY; if (group && ansi_to_utf16( group, &groupW ) < 0) { free( readerW ); return SCARD_E_NO_MEMORY; } ret = SCardAddReaderToGroupW( context, readerW, groupW ); free( readerW ); free( groupW ); return ret; } LONG WINAPI SCardAddReaderToGroupW( SCARDCONTEXT context, const WCHAR *reader, const WCHAR *group ) { FIXME( "%Ix, %s, %s\n", context, debugstr_w(reader), debugstr_w(group) ); return SCARD_S_SUCCESS; } #define CONTEXT_MAGIC (('C' << 24) | ('T' << 16) | ('X' << 8) | '0') #define CONNECT_MAGIC (('C' << 24) | ('O' << 16) | ('N' << 8) | '0') struct handle { DWORD magic; UINT64 unix_handle; }; LONG WINAPI SCardEstablishContext( DWORD scope, const void *reserved1, const void *reserved2, SCARDCONTEXT *context ) { struct scard_establish_context_params params; struct handle *handle; LONG ret; TRACE( "%#lx, %p, %p, %p\n", scope, reserved1, reserved2, context ); if (!context) return SCARD_E_INVALID_PARAMETER; if (!(handle = malloc( sizeof(*handle) ))) return SCARD_E_NO_MEMORY; handle->magic = CONTEXT_MAGIC; params.scope = scope; params.handle = &handle->unix_handle; if (!(ret = UNIX_CALL( scard_establish_context, ¶ms ))) *context = (SCARDCONTEXT)handle; else free( handle ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardIsValidContext( SCARDCONTEXT context ) { struct handle *handle = (struct handle *)context; struct scard_is_valid_context_params params; LONG ret; TRACE( "%Ix\n", context ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; ret = UNIX_CALL( scard_is_valid_context, ¶ms ); TRACE( "returning %#lx\n", ret ); 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; struct scard_release_context_params params; LONG ret; TRACE( "%Ix\n", context ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; ret = UNIX_CALL( scard_release_context, ¶ms ); handle->magic = 0; free( handle ); TRACE( "returning %#lx\n", ret ); return ret; } static LONG copy_multiszA( const char *src, char *dst, DWORD *dst_len ) { int len, total_len = 0; const char *src_ptr = src; char *dst_ptr; if (!dst && !dst_len) return SCARD_S_SUCCESS; while (*src_ptr) { if ((len = utf8_to_ansi( src_ptr, NULL )) < 0) return SCARD_E_INVALID_PARAMETER; total_len += len; src_ptr += len; } total_len++; /* double null */ if (*dst_len == SCARD_AUTOALLOCATE) { if (!(dst_ptr = malloc( total_len ))) return SCARD_E_NO_MEMORY; } else { if (dst && *dst_len < total_len) { *dst_len = total_len; return SCARD_E_INSUFFICIENT_BUFFER; } if (!dst) { *dst_len = total_len; return SCARD_S_SUCCESS; } dst_ptr = dst; } src_ptr = src; total_len = 0; while (*src_ptr) { char *str; if ((len = utf8_to_ansi( src_ptr, &str )) < 0) { if (dst_ptr != dst) free( dst_ptr ); return SCARD_E_NO_MEMORY; } memcpy( dst_ptr + total_len, str, len ); total_len += len; src_ptr += len; free( str ); } dst_ptr[total_len] = 0; if (dst_ptr != dst) *(char **)dst = dst_ptr; *dst_len = ++total_len; return SCARD_S_SUCCESS; } LONG WINAPI SCardStatusA( SCARDHANDLE connect, char *names, DWORD *names_len, DWORD *state, DWORD *protocol, BYTE *atr, DWORD *atr_len ) { struct handle *handle = (struct handle *)connect; struct scard_status_params params; UINT64 state64, protocol64, atr_len64, names_len_utf8 = 0; LONG ret; TRACE( "%Ix, %p, %p, %p, %p, %p, %p\n", connect, names, names_len, state, protocol, atr, atr_len ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; if (atr_len && *atr_len == SCARD_AUTOALLOCATE) { FIXME( "SCARD_AUTOALLOCATE not supported for attr\n" ); return SCARD_F_INTERNAL_ERROR; } params.handle = handle->unix_handle; params.names = NULL; params.names_len = &names_len_utf8; params.state = &state64; params.protocol = &protocol64; params.atr = NULL; if (!atr_len) params.atr_len = NULL; else { atr_len64 = *atr_len; params.atr_len = &atr_len64; } if ((ret = UNIX_CALL( scard_status, ¶ms ))) return ret; if (!(params.names = malloc( names_len_utf8 ))) return SCARD_E_NO_MEMORY; if (!(ret = UNIX_CALL( scard_status, ¶ms )) && !(ret = copy_multiszA( params.names, names, names_len ))) { if (state) *state = state64; if (protocol) *protocol = protocol64; if (atr_len) *atr_len = atr_len64; } free( params.names ); TRACE( "returning %#lx\n", ret ); return ret; } static LONG copy_multiszW( const char *src, WCHAR *dst, DWORD *dst_len ) { int len, total_len = 0; const char *src_ptr = src; WCHAR *dst_ptr; if (!dst && !dst_len) return SCARD_S_SUCCESS; while (*src_ptr) { if ((len = utf8_to_utf16( src_ptr, NULL )) < 0) return SCARD_E_INVALID_PARAMETER; total_len += len; src_ptr += len; } total_len++; /* double null */ if (*dst_len == SCARD_AUTOALLOCATE) { if (!(dst_ptr = malloc( total_len * sizeof(WCHAR) ))) return SCARD_E_NO_MEMORY; } else { if (dst && *dst_len < total_len) { *dst_len = total_len; return SCARD_E_INSUFFICIENT_BUFFER; } if (!dst) { *dst_len = total_len; return SCARD_S_SUCCESS; } dst_ptr = dst; } src_ptr = src; total_len = 0; while (*src_ptr) { WCHAR *str; if ((len = utf8_to_utf16( src_ptr, &str )) < 0) { if (dst_ptr != dst) free( dst_ptr ); return SCARD_E_NO_MEMORY; } memcpy( dst_ptr + total_len, str, len * sizeof(WCHAR) ); total_len += len; src_ptr += len; free( str ); } dst_ptr[total_len] = 0; if (dst_ptr != dst) *(WCHAR **)dst = dst_ptr; *dst_len = ++total_len; return SCARD_S_SUCCESS; } LONG WINAPI SCardStatusW( SCARDHANDLE connect, WCHAR *names, DWORD *names_len, DWORD *state, DWORD *protocol, BYTE *atr, DWORD *atr_len ) { struct handle *handle = (struct handle *)connect; struct scard_status_params params; UINT64 state64, protocol64, atr_len64, names_len_utf8 = 0; LONG ret; TRACE( "%Ix, %p, %p, %p, %p, %p, %p\n", connect, names, names_len, state, protocol, atr, atr_len ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; if (atr_len && *atr_len == SCARD_AUTOALLOCATE) { FIXME( "SCARD_AUTOALLOCATE not supported for attr\n" ); return SCARD_F_INTERNAL_ERROR; } params.handle = handle->unix_handle; params.names = NULL; params.names_len = &names_len_utf8; params.state = &state64; params.protocol = &protocol64; params.atr = atr; if (!atr_len) params.atr_len = NULL; else { atr_len64 = *atr_len; params.atr_len = &atr_len64; } if ((ret = UNIX_CALL( scard_status, ¶ms ))) return ret; if (!(params.names = malloc( names_len_utf8 ))) return SCARD_E_NO_MEMORY; if (!(ret = UNIX_CALL( scard_status, ¶ms )) && !(ret = copy_multiszW( params.names, names, names_len ))) { if (state) *state = state64; if (protocol) *protocol = protocol64; if (atr_len) *atr_len = atr_len64; } free( params.names ); TRACE( "returning %#lx\n", ret ); return ret; } void WINAPI SCardReleaseStartedEvent(void) { FIXME( "stub\n" ); } LONG WINAPI SCardListReadersA( SCARDCONTEXT context, const char *groups, char *readers, DWORD *readers_len ) { struct handle *handle = (struct handle *)context; struct scard_list_readers_params params; UINT64 readers_len_utf8; LONG ret; TRACE( "%Ix, %s, %p, %p\n", context, debugstr_a(groups), readers, readers_len ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!readers_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; if (!groups) params.groups = NULL; else if (ansi_to_utf8( groups, (char **)¶ms.groups ) < 0) return SCARD_E_NO_MEMORY; params.readers = NULL; params.readers_len = &readers_len_utf8; if ((ret = UNIX_CALL( scard_list_readers, ¶ms ))) goto done; if (!(params.readers = malloc( readers_len_utf8 ))) { free( (void *)params.groups ); return SCARD_E_NO_MEMORY; } if (!(ret = UNIX_CALL( scard_list_readers, ¶ms ))) { ret = copy_multiszA( params.readers, readers, readers_len ); } done: free( (void *)params.groups ); free( params.readers ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardListReadersW( SCARDCONTEXT context, const WCHAR *groups, WCHAR *readers, DWORD *readers_len ) { struct handle *handle = (struct handle *)context; struct scard_list_readers_params params; UINT64 readers_len_utf8; LONG ret; TRACE( "%Ix, %s, %p, %p\n", context, debugstr_w(groups), readers, readers_len ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!readers_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; if (!groups) params.groups = NULL; else if (utf16_to_utf8( groups, (char **)¶ms.groups ) < 0) return SCARD_E_NO_MEMORY; params.readers = NULL; params.readers_len = &readers_len_utf8; if ((ret = UNIX_CALL( scard_list_readers, ¶ms ))) goto done; params.handle = handle->unix_handle; if (!(params.readers = malloc( readers_len_utf8 ))) { free( (void *)params.groups ); return SCARD_E_NO_MEMORY; } if (!(ret = UNIX_CALL( scard_list_readers, ¶ms ))) { ret = copy_multiszW( params.readers, readers, readers_len ); } done: free( (void *)params.groups ); free( params.readers ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardCancel( SCARDCONTEXT context ) { struct handle *handle = (struct handle *)context; struct scard_cancel_params params; LONG ret; TRACE( "%Ix\n", context ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; ret = UNIX_CALL( scard_cancel, ¶ms ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardListReaderGroupsA( SCARDCONTEXT context, char *groups, DWORD *groups_len ) { struct handle *handle = (struct handle *)context; struct scard_list_reader_groups_params params; UINT64 groups_len_utf8; LONG ret; TRACE( "%Ix, %p, %p\n", context, groups, groups_len ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!groups_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; params.groups = NULL; params.groups_len = &groups_len_utf8; if ((ret = UNIX_CALL( scard_list_reader_groups, ¶ms ))) goto done; params.handle = handle->unix_handle; if (!(params.groups = malloc( groups_len_utf8 ))) return SCARD_E_NO_MEMORY; if (!(ret = UNIX_CALL( scard_list_reader_groups, ¶ms ))) { ret = copy_multiszA( params.groups, groups, groups_len ); } done: free( params.groups ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardListReaderGroupsW( SCARDCONTEXT context, WCHAR *groups, DWORD *groups_len ) { struct handle *handle = (struct handle *)context; struct scard_list_reader_groups_params params; UINT64 groups_len_utf8; LONG ret; TRACE( "%Ix, %p, %p\n", context, groups, groups_len ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!groups_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; params.groups = NULL; params.groups_len = &groups_len_utf8; if ((ret = UNIX_CALL( scard_list_reader_groups, ¶ms ))) goto done; if (!(params.groups = malloc( groups_len_utf8 ))) return SCARD_E_NO_MEMORY; if (!(ret = UNIX_CALL( scard_list_reader_groups, ¶ms ))) { ret = copy_multiszW( params.groups, groups, groups_len ); } done: TRACE( "returning %#lx\n", ret ); free( params.groups ); return ret; } static LONG map_states_inA( const SCARD_READERSTATEA *src, struct reader_state *dst, DWORD count ) { DWORD i; memset( dst, 0, sizeof(*dst) * count ); for (i = 0; i < count; i++) { if (src[i].szReader && ansi_to_utf8( src[i].szReader, (char **)&dst[i].reader ) < 0) return SCARD_E_NO_MEMORY; } return SCARD_S_SUCCESS; } static void map_states_out( const struct reader_state *src, SCARD_READERSTATEA *dst, DWORD count ) { DWORD i; for (i = 0; i < count; i++) { dst[i].dwCurrentState = src[i].current_state; dst[i].dwEventState = src[i].event_state; dst[i].cbAtr = src[i].atr_size; memcpy( dst[i].rgbAtr, src[i].atr, src[i].atr_size ); } } static void free_states( struct reader_state *states, DWORD count ) { DWORD i; for (i = 0; i < count; i++) free( (void *)(ULONG_PTR)states[i].reader ); free( states ); } LONG WINAPI SCardGetStatusChangeA( SCARDCONTEXT context, DWORD timeout, SCARD_READERSTATEA *states, DWORD count ) { struct handle *handle = (struct handle *)context; struct scard_get_status_change_params params; struct reader_state *states_utf8 = NULL; LONG ret; TRACE( "%Ix, %lu, %p, %lu\n", context, timeout, states, count ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!(states_utf8 = calloc( count, sizeof(*states_utf8) ))) return SCARD_E_NO_MEMORY; if ((ret = map_states_inA( states, states_utf8, count ))) { free_states( states_utf8, count ); return ret; } params.handle = handle->unix_handle; params.timeout = timeout; params.states = states_utf8; params.count = count; if (!(ret = UNIX_CALL( scard_get_status_change, ¶ms )) && states) { map_states_out( states_utf8, states, count ); } free_states( states_utf8, count ); TRACE( "returning %#lx\n", ret ); return ret; } static LONG map_states_inW( SCARD_READERSTATEW *src, struct reader_state *dst, DWORD count ) { DWORD i; memset( dst, 0, sizeof(*dst) * count ); for (i = 0; i < count; i++) { if (src[i].szReader && utf16_to_utf8( src[i].szReader, (char **)&dst[i].reader ) < 0) return SCARD_E_NO_MEMORY; } return SCARD_S_SUCCESS; } LONG WINAPI SCardGetStatusChangeW( SCARDCONTEXT context, DWORD timeout, SCARD_READERSTATEW *states, DWORD count ) { struct handle *handle = (struct handle *)context; struct scard_get_status_change_params params; struct reader_state *states_utf8; LONG ret; TRACE( "%Ix, %lu, %p, %lu\n", context, timeout, states, count ); if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!(states_utf8 = calloc( count, sizeof(*states_utf8) ))) return SCARD_E_NO_MEMORY; if ((ret = map_states_inW( states, states_utf8, count ))) { free_states( states_utf8, count ); return ret; } params.handle = handle->unix_handle; params.timeout = timeout; params.states = states_utf8; params.count = count; if (!(ret = UNIX_CALL( scard_get_status_change, ¶ms ))) { map_states_out( states_utf8, (SCARD_READERSTATEA *)states, count ); } free_states( states_utf8, count ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardConnectA( SCARDCONTEXT context, const char *reader, DWORD share_mode, DWORD preferred_protocols, SCARDHANDLE *connect, DWORD *protocol ) { struct handle *context_handle = (struct handle *)context, *connect_handle; struct scard_connect_params params; char *reader_utf8; UINT64 protocol64; LONG ret; TRACE( "%Ix, %s, %#lx, %#lx, %p, %p\n", context, debugstr_a(reader), share_mode, preferred_protocols, connect, protocol ); if (!context_handle || context_handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!connect) return SCARD_E_INVALID_PARAMETER; if (!(connect_handle = malloc( sizeof(*connect_handle) ))) return SCARD_E_NO_MEMORY; connect_handle->magic = CONNECT_MAGIC; if (ansi_to_utf8( reader, &reader_utf8 ) < 0) { free( connect_handle ); return SCARD_E_NO_MEMORY; } params.context_handle = context_handle->unix_handle; params.reader = reader_utf8; params.share_mode = share_mode; params.preferred_protocols = preferred_protocols; params.connect_handle = &connect_handle->unix_handle; params.protocol = &protocol64; if ((ret = UNIX_CALL( scard_connect, ¶ms ))) free( connect_handle ); else { *connect = (SCARDHANDLE)connect_handle; if (protocol) *protocol = protocol64; } free( reader_utf8 ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardConnectW( SCARDCONTEXT context, const WCHAR *reader, DWORD share_mode, DWORD preferred_protocols, SCARDHANDLE *connect, DWORD *protocol ) { struct handle *context_handle = (struct handle *)context, *connect_handle; struct scard_connect_params params; char *reader_utf8; UINT64 protocol64; LONG ret; TRACE( "%Ix, %s, %#lx, %#lx, %p, %p\n", context, debugstr_w(reader), share_mode, preferred_protocols, connect, protocol ); if (!context_handle || context_handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; if (!connect) return SCARD_E_INVALID_PARAMETER; if (!(connect_handle = malloc( sizeof(*connect_handle) ))) return SCARD_E_NO_MEMORY; connect_handle->magic = CONNECT_MAGIC; if (utf16_to_utf8( reader, &reader_utf8 ) < 0) { free( connect_handle ); return SCARD_E_NO_MEMORY; } params.context_handle = context_handle->unix_handle; params.reader = reader_utf8; params.share_mode = share_mode; params.preferred_protocols = preferred_protocols; params.connect_handle = &connect_handle->unix_handle; params.protocol = &protocol64; if ((ret = UNIX_CALL( scard_connect, ¶ms ))) free( connect_handle ); else { *connect = (SCARDHANDLE)connect_handle; if (protocol) *protocol = protocol64; } free( reader_utf8 ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardReconnect( SCARDHANDLE connect, DWORD share_mode, DWORD preferred_protocols, DWORD initialization, DWORD *protocol ) { struct handle *handle = (struct handle *)connect; struct scard_reconnect_params params; UINT64 protocol64; LONG ret; TRACE( "%Ix, %#lx, %#lx, %#lx, %p\n", connect, share_mode, preferred_protocols, initialization, protocol ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; params.share_mode = share_mode; params.preferred_protocols = preferred_protocols; params.initialization = initialization; params.protocol = &protocol64; if (!(ret = UNIX_CALL( scard_reconnect, ¶ms )) && protocol) *protocol = protocol64; TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardDisconnect( SCARDHANDLE connect, DWORD disposition ) { struct handle *handle = (struct handle *)connect; struct scard_disconnect_params params; LONG ret; TRACE( "%Ix, %#lx\n", connect, disposition ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; params.disposition = disposition; if (!(ret = UNIX_CALL( scard_disconnect, ¶ms ))) { handle->magic = 0; free( handle ); } TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardBeginTransaction( SCARDHANDLE connect ) { struct handle *handle = (struct handle *)connect; struct scard_begin_transaction_params params; LONG ret; TRACE( "%Ix\n", connect ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; ret = UNIX_CALL( scard_begin_transaction, ¶ms ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardEndTransaction( SCARDHANDLE connect, DWORD disposition ) { struct handle *handle = (struct handle *)connect; struct scard_end_transaction_params params; LONG ret; TRACE( "%Ix, %#lx\n", connect, disposition ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; params.disposition = disposition; ret = UNIX_CALL( scard_end_transaction, ¶ms ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardTransmit( SCARDHANDLE connect, const SCARD_IO_REQUEST *send, const BYTE *send_buf, DWORD send_buflen, SCARD_IO_REQUEST *recv, BYTE *recv_buf, DWORD *recv_buflen ) { struct handle *handle = (struct handle *)connect; struct scard_transmit_params params; struct io_request send64 = { send->dwProtocol, send->cbPciLength }, recv64; UINT64 recv_buflen64; LONG ret; TRACE( "%Ix, %p, %p, %lu, %p, %p, %p\n", connect, send, send_buf, send_buflen, recv, recv_buf, recv_buflen ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; if (!recv_buflen) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; params.send = &send64; params.send_buf = send_buf; params.send_buflen = send_buflen; params.recv = &recv64; params.recv_buf = recv_buf; recv_buflen64 = *recv_buflen; params.recv_buflen = &recv_buflen64; if (!(ret = UNIX_CALL( scard_transmit, ¶ms ))) { if (recv) { recv->dwProtocol = recv64.protocol; recv->cbPciLength = recv64.pci_len; } *recv_buflen = recv_buflen64; } TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardControl( SCARDHANDLE connect, DWORD code, const void *in_buf, DWORD in_buflen, void *out_buf, DWORD out_buflen, DWORD *ret_len ) { struct handle *handle = (struct handle *)connect; struct scard_control_params params; UINT64 ret_len64; LONG ret; TRACE( "%Ix, %#lx, %p, %lu, %p, %lu, %p\n", connect, code, in_buf, in_buflen, out_buf, out_buflen, ret_len ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; if (!ret_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; params.code = code; params.in_buf = in_buf; params.in_buflen = in_buflen; params.out_buf = out_buf; params.out_buflen = out_buflen; params.ret_len = &ret_len64; if (!(ret = UNIX_CALL( scard_control, ¶ms ))) *ret_len = ret_len64; TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardGetAttrib( SCARDHANDLE connect, DWORD id, BYTE *attr, DWORD *attr_len ) { struct handle *handle = (struct handle *)connect; struct scard_get_attrib_params params; UINT64 attr_len64; LONG ret; TRACE( "%Ix, %#lx, %p, %p\n", connect, id, attr, attr_len ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; if (!attr_len) return SCARD_E_INVALID_PARAMETER; params.handle = handle->unix_handle; params.id = id; params.attr = attr; attr_len64 = *attr_len; params.attr_len = &attr_len64; if (!(ret = UNIX_CALL( scard_get_attrib, ¶ms ))) *attr_len = attr_len64; TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardSetAttrib( SCARDHANDLE connect, DWORD id, const BYTE *attr, DWORD attr_len ) { struct handle *handle = (struct handle *)connect; struct scard_set_attrib_params params; LONG ret; TRACE( "%Ix, %#lx, %p, %lu\n", connect, id, attr, attr_len ); if (!handle || handle->magic != CONNECT_MAGIC) return ERROR_INVALID_HANDLE; params.handle = handle->unix_handle; params.id = id; params.attr = attr; params.attr_len = attr_len; ret = UNIX_CALL( scard_set_attrib, ¶ms ); TRACE( "returning %#lx\n", ret ); return ret; } LONG WINAPI SCardFreeMemory( SCARDCONTEXT context, const void *mem ) { TRACE( "%Ix, %p\n", context, mem ); free( (void *)mem ); return SCARD_S_SUCCESS; } BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) { switch (reason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinst ); if (__wine_init_unix_call()) ERR( "no pcsclite support, expect problems\n" ); /* FIXME: for now, we act as if the pcsc daemon is always started */ g_startedEvent = CreateEventW( NULL, TRUE, TRUE, NULL ); break; case DLL_PROCESS_DETACH: if (reserved) break; CloseHandle( g_startedEvent ); g_startedEvent = NULL; break; } return TRUE; }