summaryrefslogtreecommitdiffstats
path: root/sesman
diff options
context:
space:
mode:
authorLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2013-09-24 17:19:43 -0700
committerLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2013-09-24 17:19:43 -0700
commit06f01f6c37856ce00930ca3dcbaa9fdfb0c4d72b (patch)
tree88ceac43251b4a3beb88be4a812f067a480efaec /sesman
parent379685bfcaa4dffd707b932574c99f0bab33b83e (diff)
parent675e1b86c44d6b75032ec4cb40f4ccfb8cd06358 (diff)
downloadxrdp-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.c160
-rw-r--r--sesman/chansrv/chansrv.h5
-rw-r--r--sesman/chansrv/devredir.c13
-rw-r--r--sesman/chansrv/irp.h1
-rw-r--r--sesman/chansrv/pcsc/Makefile12
-rw-r--r--sesman/chansrv/pcsc/xrdp_pcsc.c856
-rw-r--r--sesman/chansrv/smartcard.c1711
-rw-r--r--sesman/chansrv/smartcard.h98
-rw-r--r--sesman/chansrv/smartcard_pcsc.c664
-rw-r--r--sesman/chansrv/smartcard_pcsc.h28
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 */