From a695886f816f86b08b3890895118fb9e88f7bf5d Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Wed, 16 Oct 2013 19:32:53 -0700 Subject: [PATCH] chansrv: work on smartcard --- sesman/chansrv/pcsc/xrdp_pcsc.c | 75 ++++++++++++- sesman/chansrv/smartcard.c | 26 +++-- sesman/chansrv/smartcard.h | 3 +- sesman/chansrv/smartcard_pcsc.c | 185 ++++++++++++++++++++++++++++++++ sesman/chansrv/smartcard_pcsc.h | 3 + 5 files changed, 282 insertions(+), 10 deletions(-) diff --git a/sesman/chansrv/pcsc/xrdp_pcsc.c b/sesman/chansrv/pcsc/xrdp_pcsc.c index b93dba12..c10a1627 100644 --- a/sesman/chansrv/pcsc/xrdp_pcsc.c +++ b/sesman/chansrv/pcsc/xrdp_pcsc.c @@ -520,6 +520,11 @@ SCardBeginTransaction(SCARDHANDLE hCard) PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) { + char msg[256]; + int code; + int bytes; + int status; + LLOGLN(0, ("SCardEndTransaction:")); if (g_sck == -1) { @@ -527,8 +532,31 @@ SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) return SCARD_F_INTERNAL_ERROR; } pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, dwDisposition); + if (send_message(SCARD_BEGIN_TRANSACTION, msg, 8) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_BEGIN_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardEndTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } pthread_mutex_unlock(&g_mutex); - return SCARD_S_SUCCESS; + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardEndTransaction: got status 0x%8.8x", status)); + return status; } /*****************************************************************************/ @@ -652,6 +680,9 @@ SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, LLOGLN(0, ("SCardControl: error, not connected")); return SCARD_F_INTERNAL_ERROR; } + LLOGLN(0, ("SCardControl: dwControlCode %d", dwControlCode)); + LLOGLN(0, ("SCardControl: cbSendLength %d", cbSendLength)); + LLOGLN(0, ("SCardControl: cbRecvLength %d", cbRecvLength)); pthread_mutex_lock(&g_mutex); pthread_mutex_unlock(&g_mutex); return SCARD_S_SUCCESS; @@ -664,13 +695,55 @@ SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) { + char *msg; + int bytes; + int code; + int offset; + int status; + LLOGLN(0, ("SCardTransmit:")); if (g_sck == -1) { LLOGLN(0, ("SCardTransmit: error, not connected")); return SCARD_F_INTERNAL_ERROR; } + LLOGLN(0, ("SCardTransmit: cbSendLength %d", cbSendLength)); + + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, pioSendPci->dwProtocol); + SET_UINT32(msg, 8, pioSendPci->cbPciLength); + SET_UINT32(msg, 12, cbSendLength); + offset = 16; + memcpy(msg + 16, pbSendBuffer, cbSendLength); + offset += cbSendLength; + SET_UINT32(msg, offset, *pcbRecvLength); + offset += 4; pthread_mutex_lock(&g_mutex); + + if (send_message(SCARD_TRANSMIT, msg, offset) != 0) + { + LLOGLN(0, ("SCardTransmit: 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, ("SCardTransmit: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_TRANSMIT) + { + LLOGLN(0, ("SCardTransmit: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); return SCARD_S_SUCCESS; } diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index 9d55807d..2b07b90e 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -177,7 +177,8 @@ 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_EndTransaction(IRP* irp, tui32 sc_handle, + tui32 dwDisposition); 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, @@ -577,7 +578,8 @@ scard_send_begin_transaction(struct trans *con, tui32 sc_handle) * @param sc_handle handle to smartcard *****************************************************************************/ int APP_CC -scard_send_end_transaction(struct trans *con, tui32 sc_handle) +scard_send_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition) { IRP *irp; @@ -595,7 +597,7 @@ scard_send_end_transaction(struct trans *con, tui32 sc_handle) irp->user_data = con; /* send IRP to client */ - scard_send_EndTransaction(irp, sc_handle); + scard_send_EndTransaction(irp, sc_handle, dwDisposition); return 0; } @@ -1469,12 +1471,12 @@ scard_send_BeginTransaction(IRP *irp, tui32 sc_handle) * @param sc_handle handle to smartcard *****************************************************************************/ static void APP_CC -scard_send_EndTransaction(IRP *irp, tui32 sc_handle) +scard_send_EndTransaction(IRP *irp, tui32 sc_handle, tui32 dwDisposition) { /* see [MS-RDPESC] 3.1.4.32 */ - SMARTCARD* sc; - struct stream* s; + SMARTCARD *sc; + struct stream *s; int bytes; if ((sc = smartcards[irp->scard_index]) == NULL) @@ -1501,7 +1503,7 @@ scard_send_EndTransaction(IRP *irp, tui32 sc_handle) */ xstream_seek(s, 24); - xstream_wr_u32_le(s, SCARD_LEAVE_CARD); + xstream_wr_u32_le(s, dwDisposition); xstream_seek(s, 8); /* insert handle */ @@ -1790,7 +1792,8 @@ scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) /** * Cancel any outstanding calls *****************************************************************************/ -static int APP_CC scard_send_Cancel(IRP* irp, tui32 context) +static int APP_CC +scard_send_Cancel(IRP* irp, tui32 context) { /* see [MS-RDPESC] 3.1.4.27 */ @@ -2081,9 +2084,11 @@ scard_handle_Connect_Return(struct stream *s, IRP *irp, /* 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"); } @@ -2128,6 +2133,7 @@ scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, tui32 IoStatus) { tui32 len; + struct trans *con; log_debug("entered"); @@ -2148,6 +2154,10 @@ scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, /* get OutputBufferLen */ xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_begin_transaction_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h index 600aef04..14c5d6f2 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -118,7 +118,8 @@ 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_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition); 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); diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index 62b3b722..b010eee7 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -57,6 +57,9 @@ #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 */ +#define XRDP_PCSC_STATE_GOT_ET (1 << 6) /* end transaction */ +#define XRDP_PCSC_STATE_GOT_TR (1 << 7) /* transmit */ +#define XRDP_PCSC_STATE_GOT_CO (1 << 8) /* control */ /* TODO: put this in con */ static int g_xrdp_pcsc_state = XRDP_PCSC_STATE_NONE; @@ -403,6 +406,185 @@ scard_process_begin_transaction(struct trans *con, struct stream *in_s) return 0; } +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) == 0) + { + LLOGLN(0, ("scard_function_begin_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_BT; + + 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, 0x07); /* SCARD_BEGIN_TRANSACTION 0x07 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_end_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; + int dwDisposition; + + LLOGLN(0, ("scard_process_end_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) + { + LLOGLN(0, ("scard_process_end_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_ET; + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, dwDisposition); + LLOGLN(0, ("scard_process_end_transaction: hCard 0x%8.8x", hCard)); + scard_send_end_transaction(con, hCard, dwDisposition); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_end_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) == 0) + { + LLOGLN(0, ("scard_function_end_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_ET; + + 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, 0x08); /* SCARD_END_TRANSACTION 0x08 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_transmit(struct trans *con, struct stream *in_s) +{ + int hCard; + READER_STATE rs; + + LLOGLN(0, ("scard_process_transmit:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) + { + LLOGLN(0, ("scard_process_transmit: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_TR; + LLOGLN(0, ("scard_process_transmit:")); + + // todo + g_memset(&rs, 0, sizeof(rs)); + + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, rs.dwProtocol); + in_uint32_le(in_s, rs.cbPciLength); + in_uint32_le(in_s, rs.cbSendLength); + LLOGLN(0, ("scard_process_transmit: dwProtocol %d cbPciLength %d " + "cbSendLength %d", rs.dwProtocol, rs.cbPciLength, rs.cbSendLength)); + g_hexdump(in_s->p, rs.cbSendLength); + in_uint8s(in_s, rs.cbSendLength); + in_uint32_le(in_s, rs.cbRecvLength); + LLOGLN(0, ("scard_process_transmit: cbRecvLength %d", rs.cbRecvLength)); + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_transmit_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) == 0) + { + LLOGLN(0, ("scard_function_transmit_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_TR; + + // todo + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_control(struct trans *con, struct stream *in_s) +{ + LLOGLN(0, ("scard_process_control:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) + { + LLOGLN(0, ("scard_process_control: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_CO; + LLOGLN(0, ("scard_process_control:")); + + // todo + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_control_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) == 0) + { + LLOGLN(0, ("scard_function_control_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_CO; + + // todo + + return 0; +} + /*****************************************************************************/ /* returns error */ int APP_CC @@ -556,14 +738,17 @@ scard_process_msg(struct trans *con, struct stream *in_s, int command) case 0x08: /* SCARD_END_TRANSACTION */ LLOGLN(0, ("scard_process_msg: SCARD_END_TRANSACTION")); + rv = scard_process_end_transaction(con, in_s); break; case 0x09: /* SCARD_TRANSMIT */ LLOGLN(0, ("scard_process_msg: SCARD_TRANSMIT")); + rv = scard_process_transmit(con, in_s); break; case 0x0A: /* SCARD_CONTROL */ LLOGLN(0, ("scard_process_msg: SCARD_CONTROL")); + rv = scard_process_control(con, in_s); break; case 0x0B: /* SCARD_STATUS */ diff --git a/sesman/chansrv/smartcard_pcsc.h b/sesman/chansrv/smartcard_pcsc.h index 94effea9..d22f4322 100644 --- a/sesman/chansrv/smartcard_pcsc.h +++ b/sesman/chansrv/smartcard_pcsc.h @@ -44,5 +44,8 @@ int APP_CC scard_function_get_status_change_return(struct trans *con, int APP_CC scard_function_connect_return(struct trans *con, struct stream *in_s, int len); +int APP_CC scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len); #endif /* end #ifndef _SMARTCARD_PCSC_H */