diff options
author | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2013-09-24 17:19:43 -0700 |
---|---|---|
committer | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2013-09-24 17:19:43 -0700 |
commit | 06f01f6c37856ce00930ca3dcbaa9fdfb0c4d72b (patch) | |
tree | 88ceac43251b4a3beb88be4a812f067a480efaec /sesman | |
parent | 379685bfcaa4dffd707b932574c99f0bab33b83e (diff) | |
parent | 675e1b86c44d6b75032ec4cb40f4ccfb8cd06358 (diff) | |
download | xrdp-proprietary-06f01f6c37856ce00930ca3dcbaa9fdfb0c4d72b.tar.gz xrdp-proprietary-06f01f6c37856ce00930ca3dcbaa9fdfb0c4d72b.zip |
Merge branch 'master' of github.com:neutrinolabs/xrdp
Diffstat (limited to 'sesman')
-rw-r--r-- | sesman/chansrv/chansrv.c | 160 | ||||
-rw-r--r-- | sesman/chansrv/chansrv.h | 5 | ||||
-rw-r--r-- | sesman/chansrv/devredir.c | 13 | ||||
-rw-r--r-- | sesman/chansrv/irp.h | 1 | ||||
-rw-r--r-- | sesman/chansrv/pcsc/Makefile | 12 | ||||
-rw-r--r-- | sesman/chansrv/pcsc/xrdp_pcsc.c | 856 | ||||
-rw-r--r-- | sesman/chansrv/smartcard.c | 1711 | ||||
-rw-r--r-- | sesman/chansrv/smartcard.h | 98 | ||||
-rw-r--r-- | sesman/chansrv/smartcard_pcsc.c | 664 | ||||
-rw-r--r-- | sesman/chansrv/smartcard_pcsc.h | 28 |
10 files changed, 3175 insertions, 373 deletions
diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index d81c488d..86c50960 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -76,6 +76,143 @@ int g_exec_pid = 0; /* this variable gets bumped up once per DVC we create */ tui32 g_dvc_chan_id = 100; +struct timeout_obj +{ + tui32 mstime; + void* data; + void (*callback)(void* data); + struct timeout_obj* next; +}; + +static struct timeout_obj *g_timeout_head = 0; +static struct timeout_obj *g_timeout_tail = 0; + +/*****************************************************************************/ +int APP_CC +add_timeout(int msoffset, void (*callback)(void *data), void *data) +{ + struct timeout_obj *tobj; + tui32 now; + + LOG(10, ("add_timeout:")); + now = g_time3(); + tobj = g_malloc(sizeof(struct timeout_obj), 1); + tobj->mstime = now + msoffset; + tobj->callback = callback; + tobj->data = data; + if (g_timeout_tail == 0) + { + g_timeout_head = tobj; + g_timeout_tail = tobj; + } + else + { + g_timeout_tail->next = tobj; + g_timeout_tail = tobj; + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +get_timeout(int *timeout) +{ + struct timeout_obj *tobj; + tui32 now; + int ltimeout; + + LOG(10, ("get_timeout:")); + ltimeout = *timeout; + if (ltimeout < 1) + { + ltimeout = 0; + } + tobj = g_timeout_head; + if (tobj != 0) + { + now = g_time3(); + while (tobj != 0) + { + LOG(10, (" now %u tobj->mstime %u", now, tobj->mstime)); + if (now < tobj->mstime) + { + ltimeout = tobj->mstime - now; + } + tobj = tobj->next; + } + } + if (ltimeout > 0) + { + LOG(10, (" ltimeout %d", ltimeout)); + if (*timeout < 1) + { + *timeout = ltimeout; + } + else + { + if (*timeout > ltimeout) + { + *timeout = ltimeout; + } + } + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +check_timeout(void) +{ + struct timeout_obj *tobj; + struct timeout_obj *last_tobj; + struct timeout_obj *temp_tobj; + int count; + tui32 now; + + LOG(10, ("check_timeout:")); + count = 0; + tobj = g_timeout_head; + if (tobj != 0) + { + last_tobj = 0; + while (tobj != 0) + { + count++; + now = g_time3(); + if (now >= tobj->mstime) + { + tobj->callback(tobj->data); + if (last_tobj == 0) + { + g_timeout_head = tobj->next; + if (g_timeout_head == 0) + { + g_timeout_tail = 0; + } + } + else + { + last_tobj->next = tobj->next; + if (g_timeout_tail == tobj) + { + g_timeout_tail = last_tobj; + } + } + temp_tobj = tobj; + tobj = tobj->next; + g_free(temp_tobj); + } + else + { + last_tobj = tobj; + tobj = tobj->next; + } + } + } + LOG(10, (" count %d", count)); + return 0; +} + /*****************************************************************************/ int DEFAULT_CC g_is_term(void) @@ -156,11 +293,11 @@ send_data_from_chan_item(struct chan_item *chan_item) out_uint32_le(s, cod->s->size); out_uint8a(s, cod->s->p, size); s_mark_end(s); - LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_data_from_chan_item: -- " "size %d chan_flags 0x%8.8x", size, chan_flags)); g_sent = 1; - error = trans_force_write(g_con_trans); + error = trans_write_copy(g_con_trans); if (error != 0) { return 1; @@ -255,7 +392,7 @@ send_init_response_message(void) out_uint32_le(s, 2); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -278,7 +415,7 @@ send_channel_setup_response_message(void) out_uint32_le(s, 4); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -301,7 +438,7 @@ send_channel_data_response_message(void) out_uint32_le(s, 6); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -500,7 +637,7 @@ process_message_channel_data(struct stream *s) if (chan_flags & 2) /* last */ { s_mark_end(ls); - trans_force_write(g_api_con_trans); + trans_write_copy(g_api_con_trans); } } } @@ -904,7 +1041,9 @@ THREAD_RV THREAD_CC channel_thread_loop(void *in_val) { tbus objs[32]; + tbus wobjs[32]; int num_objs; + int num_wobjs; int timeout; int error; THREAD_RV rv; @@ -918,13 +1057,15 @@ channel_thread_loop(void *in_val) { timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) + while (g_obj_wait(objs, num_objs, wobjs, num_wobjs, timeout) == 0) { + check_timeout(); if (g_is_wait_obj_set(g_term_event)) { LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); @@ -997,16 +1138,19 @@ channel_thread_loop(void *in_val) xfuse_check_wait_objs(); timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_con_trans, objs, &num_objs); + trans_get_wait_objs_rw(g_con_trans, objs, &num_objs, + wobjs, &num_wobjs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_con_trans, objs, &num_objs); xcommon_get_wait_objs(objs, &num_objs, &timeout); sound_get_wait_objs(objs, &num_objs, &timeout); dev_redir_get_wait_objs(objs, &num_objs, &timeout); xfuse_get_wait_objs(objs, &num_objs, &timeout); + get_timeout(&timeout); } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ } diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index 12162dd1..06ecdc07 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -1,8 +1,8 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 - * Copyright (C) Laxmikant Rashinkar 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 + * Copyright (C) Laxmikant Rashinkar 2009-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ g_is_term(void); int APP_CC send_channel_data(int chan_id, char *data, int size); int APP_CC main_cleanup(void); +int APP_CC add_timeout(int msoffset, void (*callback)(void* data), void* data); int APP_CC find_empty_slot_in_dvc_channels(); struct xrdp_api_data * APP_CC struct_from_dvc_chan_id(tui32 dvc_chan_id); int remove_struct_with_chan_id(tui32 dvc_chan_id); diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 1f9eb492..cdcc9e94 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -587,53 +587,50 @@ void dev_redir_proc_client_core_cap_resp(struct stream *s) tui16 cap_type; tui16 cap_len; tui32 cap_version; + char* holdp; xstream_rd_u16_le(s, num_caps); xstream_seek(s, 2); /* padding */ for (i = 0; i < num_caps; i++) { + holdp = s->p; xstream_rd_u16_le(s, cap_type); xstream_rd_u16_le(s, cap_len); xstream_rd_u32_le(s, cap_version); - /* remove header length and version */ - cap_len -= 8; - switch (cap_type) { case CAP_GENERAL_TYPE: log_debug("got CAP_GENERAL_TYPE"); - xstream_seek(s, cap_len); break; case CAP_PRINTER_TYPE: log_debug("got CAP_PRINTER_TYPE"); g_is_printer_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_PORT_TYPE: log_debug("got CAP_PORT_TYPE"); g_is_port_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_DRIVE_TYPE: log_debug("got CAP_DRIVE_TYPE"); g_is_drive_redir_supported = 1; if (cap_version == 2) + { g_drive_redir_version = 2; - xstream_seek(s, cap_len); + } break; case CAP_SMARTCARD_TYPE: log_debug("got CAP_SMARTCARD_TYPE"); g_is_smartcard_redir_supported = 1; scard_init(); - xstream_seek(s, cap_len); break; } + s->p = holdp + cap_len; } } diff --git a/sesman/chansrv/irp.h b/sesman/chansrv/irp.h index e1a65d83..a13ea8e5 100644 --- a/sesman/chansrv/irp.h +++ b/sesman/chansrv/irp.h @@ -52,6 +52,7 @@ struct irp void (*callback)(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); + void *user_data; }; IRP * APP_CC devredir_irp_new(void); diff --git a/sesman/chansrv/pcsc/Makefile b/sesman/chansrv/pcsc/Makefile new file mode 100644 index 00000000..483151f2 --- /dev/null +++ b/sesman/chansrv/pcsc/Makefile @@ -0,0 +1,12 @@ + +OBJS = xrdp_pcsc.o + +CFLAGS = -Wall -O2 -fPIC + +all: libpcsclite.so + +libpcsclite.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -o libpcsclite.so $(OBJS) + +clean: + rm -f $(OBJS) libpcsclite.so diff --git a/sesman/chansrv/pcsc/xrdp_pcsc.c b/sesman/chansrv/pcsc/xrdp_pcsc.c new file mode 100644 index 00000000..b93dba12 --- /dev/null +++ b/sesman/chansrv/pcsc/xrdp_pcsc.c @@ -0,0 +1,856 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> + +#define PCSC_API + +typedef unsigned char BYTE; +typedef BYTE *LPBYTE; +typedef unsigned int LONG; +typedef unsigned int DWORD; +typedef DWORD *LPDWORD; +typedef const void *LPCVOID; +typedef const char *LPCSTR; +typedef char *LPSTR; +typedef void *LPVOID; +typedef const BYTE *LPCBYTE; + +typedef LONG SCARDCONTEXT; +typedef SCARDCONTEXT *LPSCARDCONTEXT; + +typedef LONG SCARDHANDLE; +typedef SCARDHANDLE *LPSCARDHANDLE; + +#define MAX_ATR_SIZE 33 + +typedef struct _SCARD_READERSTATE +{ + const char *szReader; + void *pvUserData; + DWORD dwCurrentState; + DWORD dwEventState; + DWORD cbAtr; + unsigned char rgbAtr[MAX_ATR_SIZE]; +} SCARD_READERSTATE, *LPSCARD_READERSTATE; + +typedef struct _SCARD_IO_REQUEST +{ + unsigned long dwProtocol; + unsigned long cbPciLength; +} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; + +#define LLOG_LEVEL 5 +#define LLOGLN(_level, _args) \ + do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + +#define SCARD_ESTABLISH_CONTEXT 0x01 +#define SCARD_RELEASE_CONTEXT 0x02 +#define SCARD_LIST_READERS 0x03 +#define SCARD_CONNECT 0x04 +#define SCARD_RECONNECT 0x05 +#define SCARD_DISCONNECT 0x06 +#define SCARD_BEGIN_TRANSACTION 0x07 +#define SCARD_END_TRANSACTION 0x08 +#define SCARD_TRANSMIT 0x09 +#define SCARD_CONTROL 0x0A +#define SCARD_STATUS 0x0B +#define SCARD_GET_STATUS_CHANGE 0x0C +#define SCARD_CANCEL 0x0D +#define SCARD_CANCEL_TRANSACTION 0x0E +#define SCARD_GET_ATTRIB 0x0F +#define SCARD_SET_ATTRIB 0x10 + +#define SCARD_S_SUCCESS 0x00000000 +#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001) + +#define SET_UINT32(_data, _offset, _val) do { \ + (((BYTE*)(_data)) + (_offset))[0] = ((_val) >> 0) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[1] = ((_val) >> 8) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[2] = ((_val) >> 16) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[3] = ((_val) >> 24) & 0xff; } while (0) + +#define GET_UINT32(_data, _offset) \ + ((((BYTE*)(_data)) + (_offset))[0] << 0) | \ + ((((BYTE*)(_data)) + (_offset))[1] << 8) | \ + ((((BYTE*)(_data)) + (_offset))[2] << 16) | \ + ((((BYTE*)(_data)) + (_offset))[3] << 24) + +#define LMIN(_val1, _val2) (_val1) < (_val2) ? (_val1) : (_val2) +#define LMAX(_val1, _val2) (_val1) > (_val2) ? (_val1) : (_val2) + +static int g_sck = -1; /* unix domain socket */ + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* for pcsc_stringify_error */ +static char g_error_str[512]; + +/*****************************************************************************/ +static int +get_display_num_from_display(const char *display_text) +{ + int rv; + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + char host[256]; + char disp[256]; + char scre[256]; + + memset(host, 0, 256); + memset(disp, 0, 256); + memset(scre, 0, 256); + + index = 0; + host_index = 0; + disp_index = 0; + scre_index = 0; + mode = 0; + + while (display_text[index] != 0) + { + if (display_text[index] == ':') + { + mode = 1; + } + else if (display_text[index] == '.') + { + mode = 2; + } + else if (mode == 0) + { + host[host_index] = display_text[index]; + host_index++; + } + else if (mode == 1) + { + disp[disp_index] = display_text[index]; + disp_index++; + } + else if (mode == 2) + { + scre[scre_index] = display_text[index]; + scre_index++; + } + index++; + } + host[host_index] = 0; + disp[disp_index] = 0; + scre[scre_index] = 0; + LLOGLN(0, ("get_display_num_from_display: host [%s] disp [%s] scre [%s]", + host, disp, scre)); + rv = atoi(disp); + return rv; +} + +/*****************************************************************************/ +static int +connect_to_chansrv(void) +{ + int bytes; + int dis; + int error; + char *xrdp_session; + char *xrdp_display; + char *home_str; + struct sockaddr_un saddr; + struct sockaddr *psaddr; + + if (g_sck != -1) + { + /* already connected */ + return 0; + } + xrdp_session = getenv("XRDP_SESSION"); + if (xrdp_session == NULL) + { + /* XRDP_SESSION must be set */ + LLOGLN(0, ("connect_to_chansrv: error, not xrdp session")); + return 1; + } + xrdp_display = getenv("DISPLAY"); + if (xrdp_display == NULL) + { + /* DISPLAY must be set */ + LLOGLN(0, ("connect_to_chansrv: error, display not set")); + return 1; + } + home_str = getenv("HOME"); + if (home_str == NULL) + { + /* HOME must be set */ + LLOGLN(0, ("connect_to_chansrv: error, home not set")); + return 1; + } + dis = get_display_num_from_display(xrdp_display); + if (dis < 10) + { + /* DISPLAY must be > 9 */ + LLOGLN(0, ("connect_to_chansrv: error, display not > 9 %d", dis)); + return 1; + } + g_sck = socket(PF_LOCAL, SOCK_STREAM, 0); + if (g_sck == -1) + { + LLOGLN(0, ("connect_to_chansrv: error, socket failed")); + return 1; + } + memset(&saddr, 0, sizeof(struct sockaddr_un)); + saddr.sun_family = AF_UNIX; + bytes = sizeof(saddr.sun_path); + snprintf(saddr.sun_path, bytes, "%s/.pcsc%d/pcscd.comm", home_str, dis); + saddr.sun_path[bytes - 1] = 0; + LLOGLN(0, ("connect_to_chansrv: connecting to %s", saddr.sun_path)); + psaddr = (struct sockaddr *) &saddr; + bytes = sizeof(struct sockaddr_un); + error = connect(g_sck, psaddr, bytes); + if (error == 0) + { + } + else + { + perror("connect_to_chansrv"); + close(g_sck); + g_sck = -1; + LLOGLN(0, ("connect_to_chansrv: error, open %s", saddr.sun_path)); + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +send_message(int code, char *data, int bytes) +{ + char header[8]; + + SET_UINT32(header, 0, bytes); + SET_UINT32(header, 4, code); + if (send(g_sck, header, 8, 0) != 8) + { + return 1; + } + if (send(g_sck, data, bytes, 0) != bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +get_message(int *code, char *data, int *bytes) +{ + char header[8]; + int max_bytes; + + if (recv(g_sck, header, 8, 0) != 8) + { + return 1; + } + max_bytes = *bytes; + *bytes = GET_UINT32(header, 0); + *code = GET_UINT32(header, 4); + if (*bytes > max_bytes) + { + return 1; + } + if (recv(g_sck, data, *bytes, 0) != *bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, + LPSCARDCONTEXT phContext) +{ + char msg[256]; + DWORD context; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardEstablishContext:")); + if (g_sck == -1) + { + if (connect_to_chansrv() != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, can not connect " + "to chansrv")); + return SCARD_F_INTERNAL_ERROR; + } + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, dwScope); + if (send_message(SCARD_ESTABLISH_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_ESTABLISH_CONTEXT) || (bytes != 8)) + { + LLOGLN(0, ("SCardEstablishContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + context = GET_UINT32(msg, 0); + status = GET_UINT32(msg, 4); + LLOGLN(10, ("SCardEstablishContext: got context 0x%8.8x", context)); + *phContext = context; + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReleaseContext(SCARDCONTEXT hContext) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardReleaseContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReleaseContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_RELEASE_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_RELEASE_CONTEXT) || (bytes != 4)) + { + LLOGLN(0, ("SCardReleaseContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardIsValidContext(SCARDCONTEXT hContext) +{ + LLOGLN(0, ("SCardIsValidContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardIsValidContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, + DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, + LPDWORD pdwActiveProtocol) +{ + char msg[256]; + int code; + int bytes; + int status; + int offset; + + LLOGLN(0, ("SCardConnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardConnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + offset = 0; + SET_UINT32(msg, offset, hContext); + offset += 4; + bytes = strlen(szReader); + if (bytes > 99) + { + LLOGLN(0, ("SCardConnect: error, name too long")); + return SCARD_F_INTERNAL_ERROR; + } + memcpy(msg + offset, szReader, bytes); + memset(msg + bytes, 0, 100 - bytes); + offset += 100; + SET_UINT32(msg, offset, dwShareMode); + offset += 4; + SET_UINT32(msg, offset, dwPreferredProtocols); + offset += 4; + if (send_message(SCARD_CONNECT, msg, offset) != 0) + { + LLOGLN(0, ("SCardConnect: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardConnect: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_CONNECT) + { + LLOGLN(0, ("SCardConnect: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + *phCard = GET_UINT32(msg, 0); + *pdwActiveProtocol = GET_UINT32(msg, 4); + status = GET_UINT32(msg, 8); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, + DWORD dwPreferredProtocols, DWORD dwInitialization, + LPDWORD pdwActiveProtocol) +{ + LLOGLN(0, ("SCardReconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + LLOGLN(0, ("SCardDisconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardDisconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardBeginTransaction(SCARDHANDLE hCard) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardBeginTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardBeginTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + if (send_message(SCARD_BEGIN_TRANSACTION, msg, 4) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_BEGIN_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardBeginTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardBeginTransaction: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) +{ + LLOGLN(0, ("SCardEndTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardEndTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, + LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, + LPDWORD pcbAtrLen) +{ + LLOGLN(0, ("SCardStatus:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardStatus: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, + LPSCARD_READERSTATE rgReaderStates, DWORD cReaders) +{ + char *msg; + int bytes; + int code; + int index; + int offset; + int str_len; + int status; + + LLOGLN(0, ("SCardGetStatusChange:")); + LLOGLN(10, (" dwTimeout %d cReaders %d", dwTimeout, cReaders)); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetStatusChange: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hContext); + SET_UINT32(msg, 4, dwTimeout); + SET_UINT32(msg, 8, cReaders); + offset = 12; + for (index = 0; index < cReaders; index++) + { + str_len = strlen(rgReaderStates[index].szReader); + str_len = LMIN(str_len, 99); + memset(msg + offset, 0, 100); + memcpy(msg + offset, rgReaderStates[index].szReader, str_len); + offset += 100; + LLOGLN(10, (" in dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwCurrentState); + offset += 4; + LLOGLN(10, (" in dwEventState %d", rgReaderStates[index].dwEventState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwEventState); + offset += 4; + LLOGLN(10, (" in cbAtr %d", rgReaderStates[index].cbAtr)); + SET_UINT32(msg, offset, rgReaderStates[index].cbAtr); + offset += 4; + memset(msg + offset, 0, 36); + memcpy(msg + offset, rgReaderStates[index].rgbAtr, 33); + offset += 36; + } + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_GET_STATUS_CHANGE, msg, offset) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_GET_STATUS_CHANGE) + { + LLOGLN(0, ("SCardGetStatusChange: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + cReaders = GET_UINT32(msg, 0); + offset = 4; + LLOGLN(10, ("SCardGetStatusChange: got back cReaders %d", cReaders)); + for (index = 0; index < cReaders; index++) + { + rgReaderStates[index].dwCurrentState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + rgReaderStates[index].dwEventState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwEventState %d", rgReaderStates[index].dwEventState)); + rgReaderStates[index].cbAtr = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out cbAtr %d", rgReaderStates[index].cbAtr)); + memcpy(rgReaderStates[index].rgbAtr, msg + offset, 33); + offset += 36; + } + status = GET_UINT32(msg, offset); + offset += 4; + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, + DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, + LPDWORD lpBytesReturned) +{ + LLOGLN(0, ("SCardControl:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardControl: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, + SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, + LPDWORD pcbRecvLength) +{ + LLOGLN(0, ("SCardTransmit:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardTransmit: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, + LPDWORD pcchGroups) +{ + LLOGLN(0, ("SCardListReaderGroups:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaderGroups: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, + LPDWORD pcchReaders) +{ + char* msg; + char* reader_names; + int reader_names_index; + int code; + int bytes; + int num_readers; + int status; + int offset; + int index; + char reader[100]; + + LLOGLN(0, ("SCardListReaders:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaders: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_LIST_READERS, msg, 4) != 0) + { + LLOGLN(0, ("SCardListReaders: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardListReaders: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_LIST_READERS) + { + LLOGLN(0, ("SCardListReaders: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + offset = 0; + num_readers = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, ("hi - mszReaders %p pcchReaders %p num_readers %d", mszReaders, pcchReaders, num_readers)); + reader_names = (char *) malloc(8192); + reader_names_index = 0; + for (index = 0; index < num_readers; index++) + { + memcpy(reader, msg + offset, 100); + bytes = strlen(reader); + memcpy(reader_names + reader_names_index, reader, bytes); + reader_names_index += bytes; + reader_names[reader_names_index] = 0; + reader_names_index++; + offset += 100; + LLOGLN(10, ("SCardListReaders: readername %s", reader)); + } + reader_names[reader_names_index] = 0; + reader_names_index++; + status = GET_UINT32(msg, offset); + offset += 4; + if (pcchReaders != 0) + { + *pcchReaders = reader_names_index; + } + if (mszReaders != 0) + { + memcpy(mszReaders, reader_names, reader_names_index); + } + free(msg); + free(reader_names); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem) +{ + LLOGLN(0, ("SCardFreeMemory:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardFreeMemory: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardCancel(SCARDCONTEXT hContext) +{ + LLOGLN(0, ("SCardCancel:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardCancel: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, + LPDWORD pcbAttrLen) +{ + LLOGLN(0, ("SCardGetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, + DWORD cbAttrLen) +{ + LLOGLN(0, ("SCardSetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardSetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +char * +pcsc_stringify_error(const long code) +{ + switch (code) + { + case SCARD_S_SUCCESS: + snprintf(g_error_str, 511, "Command successful."); + break; + case SCARD_F_INTERNAL_ERROR: + snprintf(g_error_str, 511, "Internal error."); + break; + default: + snprintf(g_error_str, 511, "error 0x%8.8x", (int)code); + break; + } + g_error_str[511] = 0; + return g_error_str; +} diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index c370479e..e4d144bd 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -21,6 +21,7 @@ * smartcard redirection support */ +#include <string.h> #include "os_calls.h" #include "smartcard.h" #include "log.h" @@ -31,6 +32,8 @@ /* * TODO * + * o ensure that all wide calls are handled correctly + * * o need to query client for build number and determine whether we should use * SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN * @@ -60,13 +63,15 @@ #endif #define log_error(_params...) \ +do \ { \ g_write("[%10.10u]: SMART_CARD %s: %d : ERROR: ", \ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ -} +} while (0) #define log_info(_params...) \ +do \ { \ if (LOG_INFO <= LOG_LEVEL) \ { \ @@ -74,9 +79,10 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) #define log_debug(_params...) \ +do \ { \ if (LOG_DEBUG <= LOG_LEVEL) \ { \ @@ -84,7 +90,7 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) /* [MS-RDPESC] 3.1.4 */ #define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */ @@ -99,15 +105,18 @@ #define SCARD_IOCTL_FORGET_READER 0x00090068 /* IntroduceReader */ #define SCARD_IOCTL_ADD_READER_TO_GROUP 0x00090070 /* AddReaderToGroup */ #define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */ -#define SCARD_IOCTL_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_GET_STATUS_CHANGE_A 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_GET_STATUS_CHANGE_W 0x000900A4 /* GetStatusChangeW */ #define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */ -#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_A 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_W 0x000900B0 /* ConnectW */ #define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */ #define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */ #define SCARD_IOCTL_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */ #define SCARD_IOCTL_END_TRANSACTION 0x000900C0 /* EndTransaction */ #define SCARD_IOCTL_STATE 0x000900C4 /* State */ -#define SCARD_IOCTL_STATUS 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_A 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_W 0x000900CC /* StatusW */ #define SCARD_IOCTL_TRANSMIT 0x000900D0 /* Transmit */ #define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */ #define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */ @@ -120,191 +129,664 @@ #define SCARD_SCOPE_TERMINAL 0x00000001 #define SCARD_SCOPE_SYSTEM 0x00000002 +/* disposition - action to take on card */ +#define SCARD_LEAVE_CARD 0x00000000 +#define SCARD_RESET_CARD 0x00000001 +#define SCARD_UNPOWER_CARD 0x00000002 +#define SCARD_EJECT_CARD 0x00000003 + #define MAX_SMARTCARDS 16 /* stores info about a smart card */ typedef struct smartcard { tui32 DeviceId; - char Context[16]; /* opaque context; save as passed to us */ - int Context_len; /* Context len in bytes */ } SMARTCARD; -SMARTCARD *smartcards[MAX_SMARTCARDS]; -int g_smartcards_inited = 0; +/* globals */ +SMARTCARD* smartcards[MAX_SMARTCARDS]; +int g_smartcards_inited = 0; +static tui32 g_device_id = 0; +static int g_scard_index = 0; +/* externs */ extern tui32 g_completion_id; -extern int g_rdpdr_chan_id; /* in chansrv.c */ +extern int g_rdpdr_chan_id; /* in chansrv.c */ + + +/****************************************************************************** +** static functions local to this file ** +******************************************************************************/ +static struct stream * APP_CC scard_make_new_ioctl(IRP *irp, tui32 ioctl); +static int APP_CC scard_add_new_device(tui32 device_id); +static int APP_CC scard_get_free_slot(void); +static void APP_CC scard_release_resources(void); +static void APP_CC scard_send_EstablishContext(IRP* irp, int scope); +static void APP_CC scard_send_ReleaseContext(IRP* irp, tui32 context); +static void APP_CC scard_send_IsContextValid(IRP* irp, tui32 context); +static void APP_CC scard_send_ListReaders(IRP* irp, tui32 context, int wide); + +static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa); + +static void APP_CC scard_send_Connect(IRP* irp, tui32 context, int wide, + READER_STATE* rs); + +static void APP_CC scard_send_Reconnect(IRP* irp, tui32 context, + tui32 sc_handle, READER_STATE* rs); + +static void APP_CC scard_send_BeginTransaction(IRP* irp, tui32 sc_handle); +static void APP_CC scard_send_EndTransaction(IRP* irp, tui32 sc_handle); +static void APP_CC scard_send_Status(IRP* irp, int wide, tui32 sc_handle); +static void APP_CC scard_send_Disconnect(IRP* irp, tui32 context, + tui32 sc_handle); + +/****************************************************************************** +** local callbacks into this module ** +******************************************************************************/ + +static void APP_CC scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + -/* forward declarations specific to this file */ -static void scard_send_EstablishContext(IRP *irp); -static void scard_send_ListReaders(IRP *irp, int wide); -static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl); -static int scard_add_new_device(tui32 device_id); -static int scard_get_free_slot(void); -static void scard_release_resources(void); +static void APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); /****************************************************************************** -** non static functions ** +** ** +** externally accessible functions, defined in smartcard.h ** +** ** ******************************************************************************/ +/** + *****************************************************************************/ void APP_CC scard_device_announce(tui32 device_id) { - IRP *irp; - log_debug("entered: device_id=%d", device_id); - if (!g_smartcards_inited) + if (g_smartcards_inited) + return; + + g_memset(&smartcards, 0, sizeof(smartcards)); + g_smartcards_inited = 1; + g_device_id = device_id; + g_scard_index = scard_add_new_device(device_id); + + if (g_scard_index < 0) + log_debug("scard_add_new_device failed with DeviceId=%d", g_device_id); + else + log_debug("added smartcard with DeviceId=%d to list", g_device_id); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_get_wait_objs(tbus *objs, int *count, int *timeout) +{ + return scard_pcsc_get_wait_objs(objs, count, timeout); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_check_wait_objs(void) +{ + return scard_pcsc_check_wait_objs(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_init(void) +{ + log_debug("init"); + return scard_pcsc_init(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_deinit(void) +{ + log_debug("deinit"); + return scard_pcsc_deinit(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_send_establish_context(struct trans *con, int scope) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - g_memset(&smartcards, 0, sizeof(smartcards)); - g_smartcards_inited = 1; + log_error("system out of memory"); + return 1; } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EstablishContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_EstablishContext(irp, scope); + + return 0; +} + +/** + * Release a previously established Smart Card context + *****************************************************************************/ +int APP_CC +scard_send_release_context(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ if ((irp = devredir_irp_new()) == NULL) { log_error("system out of memory"); - return; + return 1; } - irp->scard_index = scard_add_new_device(device_id); - if (irp->scard_index < 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ReleaseContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_ReleaseContext(irp, context); + + return 0; +} + +/** + * Checks if a previously established context is still valid + *****************************************************************************/ +int APP_CC +scard_send_is_valid_context(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("NOT adding smartcard with DeviceId=%d to list", device_id); - devredir_irp_delete(irp); - return; + log_error("system out of memory"); + return 1; } - log_debug("added smartcard with DeviceId=%d to list", device_id); - + irp->scard_index = g_scard_index; irp->CompletionId = g_completion_id++; - irp->DeviceId = device_id; - irp->callback = scard_handle_EstablishContext_Return; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_IsContextValid_Return; + irp->user_data = con; - scard_send_EstablishContext(irp); - log_debug("leaving"); + /* send IRP to client */ + scard_send_IsContextValid(irp, context); + + return 0; } -/****************************************************************************** -** callbacks into this module ** -******************************************************************************/ +/** + * + *****************************************************************************/ +int APP_CC +scard_send_list_readers(struct trans *con, tui32 context, int wide) +{ + IRP *irp; -void APP_CC -scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ListReaders_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_ListReaders(irp, context, wide); + + return 0; +} + +/** + * Send get change in status command + * + * @param con connection to client + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs + *****************************************************************************/ +int APP_CC +scard_send_get_status_change(struct trans *con, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa) { - tui32 len; - int tmp; - SMARTCARD *sc; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_GetStatusChange_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_GetStatusChange(irp, context, wide, timeout, num_readers, rsa); + + return 0; +} + +/** + * Open a connection to the smart card located in the reader + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Connect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Connect(irp, context, wide, rs); + + return 0; +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +int APP_CC +scard_send_reconnect(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to establish context - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - sc = smartcards[irp->scard_index]; + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Reconnect_Return; + irp->user_data = con; - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + /* send IRP to client */ + scard_send_Reconnect(irp, context, sc_handle, rs); - /* LK_TODO */ - g_hexdump(s->p, len); + return 0; +} - xstream_rd_u32_le(s, tmp); /* should be len 8, LE, V1 */ - xstream_rd_u32_le(s, tmp); /* marshalling flag */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, tmp); /* ?? */ - xstream_rd_u32_le(s, len); /* len of context in bytes */ - sc->Context_len = len; - xstream_copyout(sc->Context, s, len); +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +int APP_CC +scard_send_begin_transaction(struct trans *con, tui32 sc_handle) +{ + IRP *irp; - if (LOG_LEVEL == LOG_DEBUG) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("dumping context (%d bytes)", sc->Context_len); - g_hexdump(sc->Context, sc->Context_len); + log_error("system out of memory"); + return 1; } - irp->callback = scard_handle_ListReaders_Return; - scard_send_ListReaders(irp, 1); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_BeginTransaction_Return; + irp->user_data = con; - /* LK_TODO need to delete IRP */ - log_debug("leaving"); + /* send IRP to client */ + scard_send_BeginTransaction(irp, sc_handle); + + return 0; } -void APP_CC -scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) +/** + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_end_transaction(struct trans *con, tui32 sc_handle) { - tui32 len; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EndTransaction_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_EndTransaction(irp, sc_handle); + + return 0; +} + +/** + * Get the status of a connection for a valid smart card reader handle + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_status(struct trans *con, int wide, tui32 sc_handle) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Status_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Status(irp, wide, sc_handle); + + return 0; +} + +/** + * Release a smart card reader handle that was acquired in ConnectA/ConnectW + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to list readers - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Disconnect_Return; + irp->user_data = con; - /* LK_TODO */ - log_debug("dumping %d bytes", len); - g_hexdump(s->p, len); + /* send IRP to client */ + scard_send_Disconnect(irp, context, sc_handle); - log_debug("leaving"); + return 0; } /****************************************************************************** +** ** ** static functions local to this file ** +** ** ******************************************************************************/ /** + * Crate a new stream and insert specified IOCTL + * + * @param irp information about the I/O + * @param ioctl the IOCTL code + * + * @return stream with IOCTL inserted in it, NULL on error + *****************************************************************************/ +static struct stream * APP_CC +scard_make_new_ioctl(IRP *irp, tui32 ioctl) +{ + /* + * format of device control request + * + * DeviceIoRequest + * u16 RDPDR_CTYP_CORE + * u16 PAKID_CORE_DEVICE_IOREQUEST + * u32 DeviceId + * u32 FileId + * u32 CompletionId + * u32 MajorFunction + * u32 MinorFunction + * + * u32 OutputBufferLength SHOULD be 2048 + * u32 InputBufferLength + * u32 IoControlCode + * 20 bytes padding + * xx bytes InputBuffer (variable) + */ + + struct stream *s; + + xstream_new(s, 1024 * 4); + if (s == NULL) + { + log_error("system out of memory"); + return s; + } + + devredir_insert_DeviceIoRequest(s, + irp->DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_DEVICE_CONTROL, + 0); + + xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ + xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ + xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ + xstream_seek(s, 20); /* padding */ + + /* [MS-RPCE] 2.2.6.1 */ + xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ + xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + + return s; +} + +/** + * Create a new smart card device entry and insert it into smartcards[] + * + * @param device_id DeviceId of new card * + * @return index into smartcards[] on success, -1 on failure *****************************************************************************/ +static int APP_CC +scard_add_new_device(tui32 device_id) +{ + int index; + SMARTCARD *sc; + if ((index = scard_get_free_slot()) < 0) + { + log_error("scard_get_free_slot failed"); + return -1; + } + + if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + { + log_error("system out of memory"); + return -1; + } + + sc->DeviceId = device_id; + smartcards[index] = sc; + + return index; +} + +/** + * Find first unused entry in smartcards + * + * @return index of first unused entry in smartcards or -1 if smartcards + * is full + *****************************************************************************/ +static int APP_CC +scard_get_free_slot(void) +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] == NULL) + { + log_debug("found free slot at index %d", i); + return i; + } + } + + log_error("too many smart card devices; rejecting this one"); + return -1; +} + +/** + * Release resources prior to shutting down + *****************************************************************************/ static void APP_CC -scard_send_EstablishContext(IRP *irp) +scard_release_resources(void) +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] != NULL) + { + g_free(smartcards[i]); + smartcards[i] = NULL; + } + } +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_send_EstablishContext(IRP *irp, int scope) { struct stream *s; int bytes; if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_ESTABLISH_CONTEXT)) == NULL) + { + log_error("scard_make_new_ioctl failed"); return; + } - xstream_wr_u32_le(s, 0x08); /* len */ - xstream_wr_u32_le(s, 0); /* unused */ - xstream_wr_u32_le(s, SCARD_SCOPE_SYSTEM); /* Ioctl specific data */ - xstream_wr_u32_le(s, 0); /* don't know what this is, */ - /* but Win7 is sending it */ + xstream_wr_u32_le(s, 0x08); /* len */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, scope); /* Ioctl specific data */ + xstream_wr_u32_le(s, 0); /* don't know what this is, */ + /* but Win7 is sending it */ /* get stream len */ bytes = xstream_len(s); - /* InputBufferLength is number of bytes AFTER 20 byte padding */ + /* InputBufferLength is number of bytes AFTER 20 byte padding */ *(s->data + 28) = bytes - 56; /* send to client */ @@ -313,11 +795,112 @@ scard_send_EstablishContext(IRP *irp) } /** - * + * Release a previously established Smart Card context + *****************************************************************************/ +static void APP_CC +scard_send_ReleaseContext(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.2 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RELEASE_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 4 bytes len - don't know what this is, zero for now + * 12 bytes unused + * u32 4 bytes context len + * 4 bytes context + */ + + xstream_wr_u32_le(s, 0); + xstream_seek(s, 12); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Checks if a previously established context is still valid *****************************************************************************/ +static void APP_CC +scard_send_IsContextValid(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.3 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_IS_VALID_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 16 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes context len + * u32 4 bytes context + */ + + xstream_wr_u32_le(s, 16); + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * + *****************************************************************************/ static void APP_CC -scard_send_ListReaders(IRP *irp, int wide) +scard_send_ListReaders(IRP *irp, tui32 context, int wide) { /* see [MS-RDPESC] 2.2.2.4 */ @@ -332,18 +915,18 @@ scard_send_ListReaders(IRP *irp, int wide) return; } - ioctl = (wide > 0) ? SCARD_IOCTL_LIST_READERS_W : - SCARD_IOCTL_LIST_READERS_A; + ioctl = (wide) ? SCARD_IOCTL_LIST_READERS_W : + SCARD_IOCTL_LIST_READERS_A; if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) return; xstream_wr_u32_le(s, 72); /* number of bytes to follow */ - xstream_seek(s, 0x1c); /* freerdp does not use this */ + xstream_seek(s, 28); /* freerdp does not use this */ /* insert context */ - xstream_wr_u32_le(s, sc->Context_len); - xstream_copyin(s, sc->Context, sc->Context_len); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); xstream_wr_u32_le(s, 36); /* length of mszGroups */ xstream_wr_u16_le(s, 0x0053); @@ -389,185 +972,889 @@ scard_send_ListReaders(IRP *irp, int wide) */ /* - scard_device_control: dumping 120 bytes of data - 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ - 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ - 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... - 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... - 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. - 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. - 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. - 0070 72 00 73 00 00 00 00 00 r.s..... - scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 + scard_device_control: dumping 120 bytes of data + 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ + 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ + 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... + 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... + 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. + 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. + 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. + 0070 72 00 73 00 00 00 00 00 r.s..... + scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 */ } +/*****************************************************************************/ +static int +align_s(struct stream *s, int bytes) +{ + int i32; + + i32 = (int) (s->p - s->data); + while ((i32 % bytes) != 0) + { + out_uint8s(s, 1); + i32 = (int) (s->p - s->data); + } + return 0; +} + /** - * Crate a new stream and insert specified IOCTL - * - * @param irp information about the I/O - * @param ioctl the IOCTL code + * Get change in status * - * @return stream with IOCTL inserted in it, NULL on error + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs *****************************************************************************/ +static void APP_CC +scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa) +{ + /* see [MS-RDPESC] 2.2.2.11 for ASCII */ + /* see [MS-RDPESC] 2.2.2.12 for Wide char */ -static struct stream * APP_CC -scard_make_new_ioctl(IRP *irp, tui32 ioctl) + SMARTCARD* sc; + READER_STATE* rs; + struct stream* s; + tui32 ioctl; + int bytes; + int i; + int len; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_GET_STATUS_CHANGE_W : + SCARD_IOCTL_GET_STATUS_CHANGE_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + xstream_seek(s, 16); /* unused */ + xstream_wr_u32_le(s, timeout); + xstream_wr_u32_le(s, num_readers); + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert card reader state */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, rs->current_state); + xstream_wr_u32_le(s, rs->event_state); + xstream_wr_u32_le(s, rs->atr_len); + xstream_copyin(s, rs->atr, 33); + out_uint8s(s, 3); + } + + if (wide) + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + else + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Send connect command + * + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param rs reader state + *****************************************************************************/ +static void APP_CC +scard_send_Connect(IRP* irp, tui32 context, int wide, READER_STATE* rs) { + /* see [MS-RDPESC] 2.2.2.13 for ASCII */ + /* see [MS-RDPESC] 2.2.2.14 for Wide char */ + + SMARTCARD* sc; + struct stream* s; + tui32 ioctl; + int bytes; + int len; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + /* - * format of device control request + * command format * - * DeviceIoRequest - * u16 RDPDR_CTYP_CORE - * u16 PAKID_CORE_DEVICE_IOREQUEST - * u32 DeviceId - * u32 FileId - * u32 CompletionId - * u32 MajorFunction - * u32 MinorFunction + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 20 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocol + * xx bytes reader name + * u32 4 bytes context length (len) + * len bytes context + */ + + xstream_seek(s, 20); + xstream_wr_u32_le(s, rs->shared_mode_flag); + xstream_wr_u32_le(s, rs->preferred_protocol); + + /* insert reader name */ + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, num_chars); + if (wide) + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + } + else + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + } + align_s(s, 4); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +static void APP_CC +scard_send_Reconnect(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.15 */ + /* see [MS-RDPESC] 3.1.4.36 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RECONNECT)) == NULL) + return; + + /* + * command format * - * u32 OutputBufferLength SHOULD be 2048 - * u32 InputBufferLength - * u32 IoControlCode - * 20 bytes padding - * xx bytes InputBuffer (variable) + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocol + * u32 4 bytes dwInitialization + * u32 4 bytes context length + * u32 4 bytes context + * u32 4 bytes handle length + * u32 4 bytes handle */ + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->shared_mode_flag); + xstream_wr_u32_le(s, rs->preferred_protocol); + xstream_wr_u32_le(s, rs->init_type); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +static void APP_CC +scard_send_BeginTransaction(IRP *irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 4.9 */ + + SMARTCARD *sc; struct stream *s; + int bytes; - xstream_new(s, 1024 * 3); - if (s == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return s; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - devredir_insert_DeviceIoRequest(s, - irp->DeviceId, - irp->FileId, - irp->CompletionId, - IRP_MJ_DEVICE_CONTROL, - 0); + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_BEGIN_TRANSACTION)) == NULL) + return; - xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ - xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ - xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ - xstream_seek(s, 20); /* padding */ + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 36 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle + */ - /* [MS-RPCE] 2.2.6.1 */ - xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ - xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + xstream_seek(s, 36); - return s; + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Create a new smart card device entry and insert it into smartcards[] + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction * - * @param device_id DeviceId of new card + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +static void APP_CC +scard_send_EndTransaction(IRP *irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 3.1.4.32 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_END_TRANSACTION)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * 8 unused + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, SCARD_LEAVE_CARD); + xstream_seek(s, 8); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Get the status of a connection for a valid smart card reader handle * - * @return index into smartcards[] on success, -1 on failure + * @param con connection to client + * @param wide TRUE if unicode string *****************************************************************************/ +static void APP_CC +scard_send_Status(IRP *irp, int wide, tui32 sc_handle) +{ + /* see [MS-RDPESC] 2.2.2.18 */ -static int APP_CC -scard_add_new_device(tui32 device_id) + SMARTCARD *sc; + struct stream *s; + int bytes; + tui32 ioctl; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 28 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes reader len + * u32 4 bytes ATR len + * 8 bytes unused + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle + * 4 bytes unused + */ + + xstream_seek(s, 28); + xstream_wr_u32_le(s, -1); /* readerLen, see [MS-RDPESC] 4.11 */ + xstream_wr_u32_le(s, 36); /* atrLen, see [MS-RDPESC] 4.11 */ + xstream_seek(s, 8); + + /* insert sc_handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + xstream_wr_u32_le(s, 0); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Release a smart card reader handle that was acquired in ConnectA/ConnectW + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +static void APP_CC +scard_send_Disconnect(IRP *irp, tui32 context, tui32 sc_handle) { - int index; - SMARTCARD *sc; + /* see [MS-RDPESC] 3.1.4.30 */ - if ((index = scard_get_free_slot()) < 0) - return -1; + SMARTCARD* sc; + struct stream* s; + int bytes; - if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return -1; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - sc->DeviceId = device_id; - smartcards[index] = sc; + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_DISCONNECT)) == NULL) + return; - return index; + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * u32 4 bytes context len + * 4 bytes context + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, SCARD_RESET_CARD); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } +/****************************************************************************** +** ** +** local callbacks into this module ** +** ** +******************************************************************************/ + /** - * Find first unused entry in smartcards * - * @return index of first unused entry in smartcards or -1 if smartcards - * is full *****************************************************************************/ +static void APP_CC +scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; -static int APP_CC -scard_get_free_slot(void) + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("failed to establish context - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_establish_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - int i; + tui32 len; + struct trans *con; - for (i = 0; i < MAX_SMARTCARDS; i++) + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { - if (smartcards[i] == NULL) - { - log_debug("found free slot at index %d", i); - return i; - } + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("ReleaseContext failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_release_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} - log_error("too many smart card devices; rejecting this one"); - return -1; +static void APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Error checking context validity"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** - * Release resources prior to shutting down + * *****************************************************************************/ +static void APP_CC +scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("failed to list readers - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_list_readers_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + if (IoStatus != 0) + { + log_error("failed to get status change - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_get_status_change_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to connect - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_connect_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} +/** + * + *****************************************************************************/ static void APP_CC -scard_release_resources(void) +scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - int i; + tui32 len; - for (i = 0; i < MAX_SMARTCARDS; i++) + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { - if (smartcards[i] != NULL) - { - g_free(smartcards[i]); - smartcards[i] = NULL; - } + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to reconnect"); + /* LK_TODO delete irp and smartcard entry */ + return; } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout) +static void +scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_get_wait_objs(objs, count, timeout); + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("BeginTransaction failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_check_wait_objs(void) +static void +scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_check_wait_objs(); + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("EndTransaction failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_init(void) +static void +scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("init") - return scard_pcsc_init(); + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("StatusCall failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_deinit(void) +static void +scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("deinit") - return scard_pcsc_deinit(); + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Disconnect failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h index a85b9f5f..a2019535 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -26,26 +26,92 @@ #include "parse.h" #include "irp.h" +#include "trans.h" + +#define SCARD_SHARE_EXCLUSIVE 0x00000001 +#define SCARD_SHARE_SHARED 0x00000002 +#define SCARD_SHARE_DIRECT 0x00000003 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table A */ +#define SCARD_PROTOCOL_UNDEFINED 0x00000000 +#define SCARD_PROTOCOL_T0 0x00000001 +#define SCARD_PROTOCOL_T1 0x00000002 +#define SCARD_PROTOCOL_Tx 0x00000003 +#define SCARD_PROTOCOL_RAW 0x00010000 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table B */ +#define SCARD_PROTOCOL_DEFAULT 0x80000000 +#define SCARD_PROTOCOL_OPTIMAL 0x00000000 + +/* initialization type */ +#define SCARD_LEAVE_CARD 0x00000000 /* do not do anything */ +#define SCARD_RESET_CARD 0x00000001 /* reset smart card */ +#define SCARD_UNPOWER_CARD 0x00000002 /* turn off and reset card */ + +typedef struct reader_state +{ + char reader_name[128]; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + + /* + * share mode flag, can be one of: + * SCARD_SHARE_EXCLUSIVE app not willing to share smartcard with other apps + * SCARD_SHARE_SHARED app willing to share smartcard with other apps + * SCARD_SHARE_DIRECT app demands direct control of smart card, hence + * it is not available to other readers + */ + tui32 shared_mode_flag; + + /* + * This field MUST have a value from Table A which is logically + * OR'ed with a value from Table B. + */ + tui32 preferred_protocol; + + /* + * initialization type, must be one of the initialization type + * defined above + */ + tui32 init_type; + +} READER_STATE; -/* forward declarations */ void scard_device_announce(tui32 device_id); +int APP_CC scard_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_check_wait_objs(void); +int APP_CC scard_init(void); +int APP_CC scard_deinit(void); +int APP_CC scard_send_establish_context(struct trans *con, int scope); +int APP_CC scard_send_release_context(struct trans *con, tui32 context); +int APP_CC scard_send_is_valid_context(struct trans *con, tui32 context); +int APP_CC scard_send_list_readers(struct trans *con, tui32 context, int wide); -/* callbacks into this module */ -void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_get_status_change(struct trans *con, tui32 context, + int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa); -void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs); -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_check_wait_objs(void); -int APP_CC -scard_init(void); -int APP_CC -scard_deinit(void); +int APP_CC scard_send_reconnect(struct trans *con, tui32 context, + tui32 sc_handle, READER_STATE* rs); +int APP_CC scard_send_begin_transaction(struct trans *con, tui32 sc_handle); +int APP_CC scard_send_end_transaction(struct trans *con, tui32 sc_handle); +int APP_CC scard_send_status(struct trans *con, int wide, tui32 sc_handle); +int APP_CC scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle); + +/* + SCardReconnect + SCardTransmit + SCardControl + SCardListReaderGroups + not needed: SCardFreeMemory + SCardCancel + SCardGetAttrib + SCardSetAttrib + */ #endif /* end #ifndef _SMARTCARD_C */ diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index 909c7df3..4d496c97 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -20,88 +20,46 @@ /* * smartcard redirection support, PCSC daemon standin * this will act like pcsc daemon + * pcsc lib and daemon write struct on unix domain socket for communication */ +#define JAY_TODO_CONTEXT 0 +#define JAY_TODO_WIDE 1 + #define PCSC_STANDIN 1 -#include "chansrv.h" #include "os_calls.h" #include "smartcard.h" #include "log.h" #include "irp.h" #include "devredir.h" #include "trans.h" +#include "chansrv.h" #if PCSC_STANDIN -/* module based logging */ -#define LOG_ERROR 0 -#define LOG_INFO 1 -#define LOG_DEBUG 2 -#define LOG_LEVEL LOG_ERROR - -#define log_error(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ERROR: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_always(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ALWAYS: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_info(_params...) \ -{ \ - if (LOG_INFO <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define log_debug(_params...) \ -{ \ - if (LOG_DEBUG <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define PCSCLITE_MSG_KEY_LEN 16 -#define PCSCLITE_MAX_MESSAGE_SIZE 2048 - -struct version_struct -{ - tsi32 major; /**< IPC major \ref PROTOCOL_VERSION_MAJOR */ - tsi32 minor; /**< IPC minor \ref PROTOCOL_VERSION_MINOR */ - tui32 rv; -}; -typedef struct version_struct version_struct; - -struct rxSharedSegment -{ - tui32 mtype; /** one of the \c pcsc_adm_commands */ - tui32 user_id; - tui32 group_id; - tui32 command; /** one of the \c pcsc_msg_commands */ - tui64 date; - tui8 key[PCSCLITE_MSG_KEY_LEN]; /* 16 bytes */ - union _u - { - tui8 data[PCSCLITE_MAX_MESSAGE_SIZE]; - struct version_struct veStr; - } u; -}; -typedef struct rxSharedSegment sharedSegmentMsg, *psharedSegmentMsg; - -#define RXSHAREDSEGMENT_BYTES 2088 +#define LLOG_LEVEL 11 +#define LLOGLN(_level, _args) \ + do \ + { \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("chansrv:smartcard_pcsc [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ + } \ + while (0) + +#define XRDP_PCSC_STATE_NONE 0 +#define XRDP_PCSC_STATE_GOT_EC (1 << 0) /* establish context */ +#define XRDP_PCSC_STATE_GOT_LR (1 << 1) /* list readers */ +#define XRDP_PCSC_STATE_GOT_RC (1 << 2) /* release context */ +#define XRDP_PCSC_STATE_GOT_GSC (1 << 3) /* get status change */ +#define XRDP_PCSC_STATE_GOT_C (1 << 4) /* connect */ +#define XRDP_PCSC_STATE_GOT_BT (1 << 5) /* begin transaction */ + +/* TODO: put this in con */ +static int g_xrdp_pcsc_state = XRDP_PCSC_STATE_NONE; extern int g_display_num; /* in chansrv.c */ @@ -116,15 +74,14 @@ static struct pcsc_client *g_tail = 0; static struct trans *g_lis = 0; static struct trans *g_con = 0; /* todo, remove this */ - -static char g_pcsc_directory[256] = ""; +static char g_pcsclite_ipc_dir[256] = ""; +static int g_pub_file_fd = 0; /*****************************************************************************/ int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) { - log_debug("scard_pcsc_get_wait_objs"); - + LLOGLN(0, ("scard_pcsc_get_wait_objs")); if (g_lis != 0) { trans_get_wait_objs(g_lis, objs, count); @@ -140,8 +97,7 @@ scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) int APP_CC scard_pcsc_check_wait_objs(void) { - log_debug("scard_pcsc_check_wait_objs"); - + LLOGLN(0, ("scard_pcsc_check_wait_objs")); if (g_lis != 0) { trans_check_wait_objs(g_lis); @@ -156,34 +112,488 @@ scard_pcsc_check_wait_objs(void) /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_version(psharedSegmentMsg msg) +scard_process_establish_context(struct trans *con, struct stream *in_s) { + int dwScope; + + LLOGLN(0, ("scard_process_establish_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_EC; + in_uint32_le(in_s, dwScope); + LLOGLN(0, ("scard_process_establish_context: dwScope 0x%8.8x", dwScope)); + scard_send_establish_context(con, dwScope); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_msg(struct stream *s) +scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len) { - sharedSegmentMsg msg; - int rv; + int bytes; + tui32 context; + tui32 context_len; + struct stream *out_s; + + LLOGLN(0, ("scard_function_establish_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_EC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, context_len); + if (context_len != 4) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + in_uint32_le(in_s, context); + LLOGLN(0, ("scard_function_establish_context_return: context 0x%8.8x", context)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, context); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x01); /* SCARD_ESTABLISH_CONTEXT 0x01 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_release_context(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(0, ("scard_process_release_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_RC; + in_uint32_le(in_s, hContext); + LLOGLN(0, ("scard_process_release_context: hContext 0x%8.8x", hContext)); + scard_send_release_context(con, hContext); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + struct stream *out_s; + tui32 context; + + LLOGLN(0, ("scard_function_release_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) == 0) + { + LLOGLN(0, ("scard_function_release_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_RC; + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x02); /* SCARD_RELEASE_CONTEXT 0x02 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_list_readers(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(0, ("scard_process_list_readers:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) + { + LLOGLN(0, ("scard_process_list_readers: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_LR; + in_uint32_le(in_s, hContext); + LLOGLN(0, ("scard_process_list_readers: dwScope 0x%8.8x", hContext)); + scard_send_list_readers(con, hContext, 1); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int chr; + int readers; + int rn_index; + int index; + int bytes; + twchar reader_name[100]; + char lreader_name[16][100]; + + LLOGLN(10, ("scard_function_list_readers_return:")); + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) == 0) + { + LLOGLN(10, ("scard_function_list_readers_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_LR; + + g_memset(reader_name, 0, sizeof(reader_name)); + g_memset(lreader_name, 0, sizeof(lreader_name)); + in_uint8s(in_s, 28); + len -= 28; + in_uint32_le(in_s, len); + g_writeln("len %d", len); + rn_index = 0; + readers = 0; + while (len > 0) + { + in_uint16_le(in_s, chr); + len -= 2; + if (chr == 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + g_writeln("1 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + reader_name[0] = 0; + rn_index = 0; + } + else + { + reader_name[rn_index] = chr; + rn_index++; + } + } + if (rn_index > 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + g_writeln("2 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + } + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, readers); + for (index = 0; index < readers; index++) + { + g_writeln("3 - %s", lreader_name[index]); + out_uint8a(out_s, lreader_name[index], 100); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x03); /* SCARD_LIST_READERS 0x03 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_connect(struct trans *con, struct stream *in_s) +{ + int hContext; + char szReader[100]; + READER_STATE rs; + + LLOGLN(0, ("scard_process_connect:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) + { + LLOGLN(0, ("scard_process_connect: opps")); + return 1; + } + g_memset(&rs, 0, sizeof(rs)); + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_C; + in_uint32_le(in_s, hContext); + in_uint8a(in_s, szReader, 100); + in_uint32_le(in_s, rs.shared_mode_flag); + in_uint32_le(in_s, rs.preferred_protocol); + LLOGLN(0, ("scard_process_connect: dwShareMode 0x%8.8x " + "dwPreferredProtocols 0x%8.8x", rs.shared_mode_flag, + rs.preferred_protocol)); + scard_send_connect(con, hContext, 1, &rs); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len) +{ + int dwActiveProtocol; + int hCard; + int bytes; + struct stream *out_s; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) == 0) + { + LLOGLN(0, ("scard_function_connect_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_C; + in_uint8s(in_s, 36); + in_uint32_le(in_s, dwActiveProtocol); + in_uint8s(in_s, 36); + in_uint32_le(in_s, hCard); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, hCard); + out_uint32_le(out_s, dwActiveProtocol); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x04); /* SCARD_CONNECT 0x04 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_begin_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; - g_memset(&msg, 0, sizeof(msg)); - in_uint32_le(s, msg.mtype); - in_uint32_le(s, msg.user_id); - in_uint32_le(s, msg.group_id); - in_uint32_le(s, msg.command); - in_uint64_le(s, msg.date); + LLOGLN(0, ("scard_process_begin_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) + { + LLOGLN(0, ("scard_process_begin_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_BT; + in_uint32_le(in_s, hCard); + LLOGLN(0, ("scard_process_begin_transaction: hCard 0x%8.8x", hCard)); + scard_send_begin_transaction(con, hCard); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_get_status_change(struct trans *con, struct stream *in_s) +{ + int index; + int hContext; + int dwTimeout; + int cReaders; + READER_STATE *rsa; + + LLOGLN(0, ("scard_process_get_status_change:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) + { + LLOGLN(0, ("scard_process_get_status_change: opps")); + return 1; + } + in_uint32_le(in_s, hContext); + in_uint32_le(in_s, dwTimeout); + in_uint32_le(in_s, cReaders); + if ((cReaders < 0) || (cReaders > 16)) + { + LLOGLN(0, ("scard_process_get_status_change: bad cReaders %d", cReaders)); + return 1; + } + rsa = (READER_STATE *) g_malloc(sizeof(READER_STATE) * cReaders, 1); + + for (index = 0; index < cReaders; index++) + { + in_uint8a(in_s, rsa[index].reader_name, 100); + LLOGLN(10, ("scard_process_get_status_change: reader_name %s", + rsa[index].reader_name)); + in_uint32_le(in_s, rsa[index].current_state); + LLOGLN(10, ("scard_process_get_status_change: current_state %d", + rsa[index].current_state)); + in_uint32_le(in_s, rsa[index].event_state); + LLOGLN(10, ("scard_process_get_status_change: event_state %d", + rsa[index].event_state)); + in_uint32_le(in_s, rsa[index].atr_len); + LLOGLN(10, ("scard_process_get_status_change: atr_len %d", + rsa[index].atr_len)); + in_uint8a(in_s, rsa[index].atr, 36); + } + + LLOGLN(0, ("scard_process_get_status_change: hContext 0x%8.8x dwTimeout " + "%d cReaders %d", hContext, dwTimeout, cReaders)); + + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_GSC; + + scard_send_get_status_change(con, hContext, 1, dwTimeout, cReaders, rsa); + + g_free(rsa); + + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + int index; + int cReaders; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + struct stream *out_s; + + LLOGLN(0, ("scard_function_get_status_change_return:")); + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_GSC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, cReaders); + if (cReaders > 0) + { + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, cReaders); + for (index = 0; index < cReaders; index++) + { + in_uint32_le(in_s, current_state); + out_uint32_le(out_s, current_state); + in_uint32_le(in_s, event_state); + out_uint32_le(out_s, event_state); + in_uint32_le(in_s, atr_len); + out_uint32_le(out_s, atr_len); + in_uint8a(in_s, atr, 36); + out_uint8a(out_s, atr, 36); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x0C); /* SCARD_ESTABLISH_CONTEXT 0x0C */ + return trans_force_write(con); + } + return 0; +} - log_debug("scard_process_msg: mtype 0x%2.2x command 0x%2.2x", - msg.mtype, msg.command); +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_msg(struct trans *con, struct stream *in_s, int command) +{ + int rv; + LLOGLN(0, ("scard_process_msg: command 0x%4.4x", command)); rv = 0; - switch (msg.mtype) + switch (command) { - case 0xF8: /* CMD_VERSION */ - rv = scard_process_version(&msg); + case 0x01: /* SCARD_ESTABLISH_CONTEXT */ + LLOGLN(0, ("scard_process_msg: SCARD_ESTABLISH_CONTEXT")); + rv = scard_process_establish_context(con, in_s); + break; + case 0x02: /* SCARD_RELEASE_CONTEXT */ + LLOGLN(0, ("scard_process_msg: SCARD_RELEASE_CONTEXT")); + rv = scard_process_release_context(con, in_s); + break; + + case 0x03: /* SCARD_LIST_READERS */ + LLOGLN(0, ("scard_process_msg: SCARD_LIST_READERS")); + rv = scard_process_list_readers(con, in_s); + break; + + case 0x04: /* SCARD_CONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_CONNECT")); + rv = scard_process_connect(con, in_s); + break; + + case 0x05: /* SCARD_RECONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_RECONNECT")); + break; + + case 0x06: /* SCARD_DISCONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_DISCONNECT")); + break; + + case 0x07: /* SCARD_BEGIN_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_BEGIN_TRANSACTION")); + rv = scard_process_begin_transaction(con, in_s); + break; + + case 0x08: /* SCARD_END_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_END_TRANSACTION")); + break; + + case 0x09: /* SCARD_TRANSMIT */ + LLOGLN(0, ("scard_process_msg: SCARD_TRANSMIT")); + break; + + case 0x0A: /* SCARD_CONTROL */ + LLOGLN(0, ("scard_process_msg: SCARD_CONTROL")); + break; + + case 0x0B: /* SCARD_STATUS */ + LLOGLN(0, ("scard_process_msg: SCARD_STATUS")); + break; + + case 0x0C: /* SCARD_GET_STATUS_CHANGE */ + LLOGLN(0, ("scard_process_msg: SCARD_GET_STATUS_CHANGE")); + rv = scard_process_get_status_change(con, in_s); + break; + + case 0x0D: /* SCARD_CANCEL */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL")); + break; + + case 0x0E: /* SCARD_CANCEL_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL_TRANSACTION")); + break; + + case 0x0F: /* SCARD_GET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_GET_ATTRIB")); + break; + + case 0x10: /* SCARD_SET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_SET_ATTRIB")); + break; + + default: + LLOGLN(0, ("scard_process_msg: unknown mtype 0x%4.4x", command)); + rv = 1; break; } return rv; @@ -197,22 +607,27 @@ my_pcsc_trans_data_in(struct trans *trans) struct stream *s; int id; int size; + int command; int error; - log_debug("my_pcsc_trans_data_in:"); - + LLOGLN(0, ("my_pcsc_trans_data_in:")); if (trans == 0) { return 0; } - if (trans != g_con) { return 1; } s = trans_get_in_s(trans); - g_hexdump(s->p, 64); - error = scard_process_msg(s); + in_uint32_le(s, size); + in_uint32_le(s, command); + LLOGLN(0, ("my_pcsc_trans_data_in: size %d command %d", size, command)); + error = trans_force_read(trans, size); + if (error == 0) + { + error = scard_process_msg(g_con, s, command); + } return error; } @@ -221,7 +636,7 @@ my_pcsc_trans_data_in(struct trans *trans) int DEFAULT_CC my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) { - log_debug("my_pcsc_trans_conn_in:"); + LLOGLN(0, ("my_pcsc_trans_conn_in:")); if (trans == 0) { @@ -240,11 +655,13 @@ my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) g_con = new_trans; g_con->trans_data_in = my_pcsc_trans_data_in; +#if 1 + g_con->header_size = 8; +#else g_con->header_size = RXSHAREDSEGMENT_BYTES; - - log_debug("my_pcsc_trans_conn_in: sizeof sharedSegmentMsg is %d", - sizeof(sharedSegmentMsg)); - + LLOGLN(0, ("my_pcsc_trans_conn_in: sizeof sharedSegmentMsg is %d", + sizeof(sharedSegmentMsg))); +#endif return 0; } @@ -253,34 +670,40 @@ int APP_CC scard_pcsc_init(void) { char port[256]; + char *home; + int disp; int error; + int index; - log_debug("scard_pcsc_init:"); - + LLOGLN(0, ("scard_pcsc_init:")); if (g_lis == 0) { - g_lis = trans_create(TRANS_MODE_UNIX, 8192, 8192); - g_lis->is_term = g_is_term; - g_snprintf(g_pcsc_directory, 255, "/tmp/.xrdp/pcsc%d", g_display_num); - if (g_directory_exist(g_pcsc_directory)) + g_lis = trans_create(2, 8192, 8192); + + //g_snprintf(g_pcsclite_ipc_dir, 255, "/tmp/.xrdp/pcsc%d", g_display_num); + home = g_getenv("HOME"); + disp = g_display_num; + g_snprintf(g_pcsclite_ipc_dir, 255, "%s/.pcsc%d", home, disp); + + if (g_directory_exist(g_pcsclite_ipc_dir)) { - if (g_remove_dir(g_pcsc_directory) != 0) + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_init: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_remove_dir failed")); } } - if (g_create_dir(g_pcsc_directory) != 0) + if (!g_create_dir(g_pcsclite_ipc_dir)) { - log_error("scard_pcsc_init: g_create_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_create_dir failed")); } - g_chmod_hex(g_pcsc_directory, 0x1777); - g_snprintf(port, 255, "%s/pcscd.comm", g_pcsc_directory); + g_chmod_hex(g_pcsclite_ipc_dir, 0x1777); + g_snprintf(port, 255, "%s/pcscd.comm", g_pcsclite_ipc_dir); g_lis->trans_conn_in = my_pcsc_trans_conn_in; error = trans_listen(g_lis, port); if (error != 0) { - log_error("scard_pcsc_init: trans_listen failed for port %s", - port); + LLOGLN(0, ("scard_pcsc_init: trans_listen failed for port %s", + port)); return 1; } } @@ -291,17 +714,20 @@ scard_pcsc_init(void) int APP_CC scard_pcsc_deinit(void) { - log_debug("scard_pcsc_deinit:"); - + LLOGLN(0, ("scard_pcsc_deinit:")); if (g_lis != 0) { trans_delete(g_lis); g_lis = 0; - if (g_remove_dir(g_pcsc_directory) != 0) + + g_file_close(g_pub_file_fd); + g_pub_file_fd = 0; + + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_deinit: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_deinit: g_remove_dir failed")); } - g_pcsc_directory[0] = 0; + g_pcsclite_ipc_dir[0] = 0; } return 0; } diff --git a/sesman/chansrv/smartcard_pcsc.h b/sesman/chansrv/smartcard_pcsc.h index a97a70d3..94effea9 100644 --- a/sesman/chansrv/smartcard_pcsc.h +++ b/sesman/chansrv/smartcard_pcsc.h @@ -24,13 +24,25 @@ #ifndef _SMARTCARD_PCSC_H #define _SMARTCARD_PCSC_H -int APP_CC -scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_pcsc_check_wait_objs(void); -int APP_CC -scard_pcsc_init(void); -int APP_CC -scard_pcsc_deinit(void); +int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_pcsc_check_wait_objs(void); +int APP_CC scard_pcsc_init(void); +int APP_CC scard_pcsc_deinit(void); +int APP_CC scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len); #endif /* end #ifndef _SMARTCARD_PCSC_H */ |