diff options
-rw-r--r-- | sesman/chansrv/smartcard.c | 544 | ||||
-rw-r--r-- | sesman/chansrv/smartcard.h | 46 | ||||
-rw-r--r-- | sesman/chansrv/smartcard_pcsc.c | 8 |
3 files changed, 568 insertions, 30 deletions
diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index e4d144bd..9d55807d 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -104,7 +104,7 @@ do \ #define SCARD_IOCTL_INTRODUCE_READER 0x00090060 /* IntroduceReader */ #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_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup*/ #define SCARD_IOCTL_GET_STATUS_CHANGE_A 0x000900A0 /* GetStatusChangeA */ #define SCARD_IOCTL_GET_STATUS_CHANGE_W 0x000900A4 /* GetStatusChangeW */ #define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */ @@ -179,9 +179,21 @@ static void APP_CC scard_send_Reconnect(IRP* irp, tui32 context, 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); +static int APP_CC scard_send_Transmit(IRP* irp, tui32 sc_handle, + READER_STATE* rs); + +static int APP_CC scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, + READER_STATE* rs); + +static int APP_CC scard_send_Cancel(IRP* irp, tui32 context); + +static int APP_CC scard_send_GetAttrib(IRP* irp, tui32 sc_handle, + READER_STATE* rs); + /****************************************************************************** ** local callbacks into this module ** ******************************************************************************/ @@ -220,7 +232,8 @@ static void APP_CC scard_handle_BeginTransaction_Return(struct stream *s, IRP *i tui32 IoStatus); static void APP_CC scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, + tui32 DeviceId, + tui32 CompletionId, tui32 IoStatus); static void APP_CC scard_handle_Status_Return(struct stream *s, IRP *irp, @@ -231,6 +244,27 @@ static void APP_CC scard_handle_Disconnect_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); + +static void APP_CC scard_handle_Transmit_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Control_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Cancel_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetAttrib_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + /****************************************************************************** ** ** ** externally accessible functions, defined in smartcard.h ** @@ -626,6 +660,116 @@ scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle) return 0; } +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ +int APP_CC +scard_send_transmit(struct trans *con, tui32 sc_handle, READER_STATE* rs) +{ + IRP *irp; + + /* 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_Transmit_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Transmit(irp, sc_handle, rs); + + return 0; +} + +/** + * Communicate directly with the smart card reader + *****************************************************************************/ +int APP_CC +scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs) +{ + IRP *irp; + + /* 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_Control_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Control(irp, context, sc_handle, rs); + + return 0; +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ +int APP_CC +scard_send_cancel(struct trans *con, tui32 context) +{ + IRP *irp; + + /* 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_Cancel_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Cancel(irp, context); + + return 0; +} + +/** + * Get reader attributes + *****************************************************************************/ +int APP_CC +scard_send_get_attrib(struct trans *con, tui32 sc_handle, READER_STATE* rs) +{ + IRP *irp; + + /* 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_GetAttrib_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_GetAttrib(irp, sc_handle, rs); + + return 0; +} + /****************************************************************************** ** ** ** static functions local to this file ** @@ -1151,15 +1295,15 @@ scard_send_Connect(IRP* irp, tui32 context, int wide, READER_STATE* rs) * u32 4 bytes filler * 20 bytes unused (s->p currently pointed here at unused[0]) * u32 4 bytes dwShareMode - * u32 4 bytes dwPreferredProtocol + * u32 4 bytes dwPreferredProtocols * 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); + xstream_wr_u32_le(s, rs->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); /* insert reader name */ num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); @@ -1236,7 +1380,7 @@ scard_send_Reconnect(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) * 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 dwPreferredProtocols * u32 4 bytes dwInitialization * u32 4 bytes context length * u32 4 bytes context @@ -1245,8 +1389,8 @@ scard_send_Reconnect(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) */ 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->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); xstream_wr_u32_le(s, rs->init_type); xstream_wr_u32_le(s, 4); xstream_wr_u32_le(s, context); @@ -1502,6 +1646,250 @@ scard_send_Disconnect(IRP *irp, tui32 context, tui32 sc_handle) xstream_free(s); } +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ +static int APP_CC +scard_send_Transmit(IRP* irp, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.19 */ + + 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_TRANSMIT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwProtocol + * u32 4 bytes cbPciLength + * u32 4 bytes map2 + * u32 4 byts cbSendLength + * u32 4 bytes map3 + * u32 4 bytes map4 + * u32 4 bytes map5 + * u32 4 bytes map6 + * u32 4 bytes cbRecvLength + * u32 4 bytes len of sc_handle + * u32 4 bytes sc_handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, rs->map0); + xstream_seek(s, 4); + xstream_wr_u32_le(s, rs->map1); + xstream_wr_u32_le(s, rs->dwProtocol); + xstream_wr_u32_le(s, rs->cbPciLength); + xstream_wr_u32_le(s, rs->map2); + xstream_wr_u32_le(s, rs->cbSendLength); + xstream_wr_u32_le(s, rs->map3); + xstream_wr_u32_le(s, rs->map4); + xstream_wr_u32_le(s, rs->map5); + xstream_wr_u32_le(s, rs->map6); + xstream_wr_u32_le(s, rs->cbRecvLength); + 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); +} + +/** + * Communicate directly with the smart card reader + *****************************************************************************/ +static int APP_CC +scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.19 */ + + 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_CONTROL)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwControlCode + * u32 4 bytes cbRecvLength + * u32 4 bytes map2 + * 4 bytes unused + * u32 4 bytes cbOutBufferSize + * u32 4 bytes context len + * u32 4 bytes context + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, rs->map0); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->map1); + xstream_wr_u32_le(s, rs->dwControlCode); + xstream_wr_u32_le(s, rs->cbRecvLength); + xstream_wr_u32_le(s, rs->map2); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->cbOutBufferSize); + 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); +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ +static int APP_CC scard_send_Cancel(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.27 */ + + 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_CANCEL)) == 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_seek(s, 16); + 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); +} + +/** + * Get reader attributes + *****************************************************************************/ +static int APP_CC +scard_send_GetAttrib(IRP* irp, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.21 */ + + 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_GETATTRIB)) == 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 dwAttribId + * 4 bytes unused + * u32 4 bytes dwAttrLen + * 8 bytes unused + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->dwAttribId); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->dwAttrLen); + xstream_seek(s, 8); + 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 ** @@ -1560,7 +1948,7 @@ scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, } if (IoStatus != 0) { - log_error("ReleaseContext failed, device not usable"); + log_error("ReleaseContext failed"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1620,7 +2008,7 @@ scard_handle_ListReaders_Return(struct stream *s, IRP *irp, } if (IoStatus != 0) { - log_error("failed to list readers - device not usable"); + log_error("failed to list readers"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1652,7 +2040,7 @@ scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, } if (IoStatus != 0) { - log_error("failed to get status change - device not usable"); + log_error("failed to get status change"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1686,7 +2074,7 @@ scard_handle_Connect_Return(struct stream *s, IRP *irp, if (IoStatus != 0) { - log_error("failed to connect - device not usable"); + log_error("failed to connect"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1752,7 +2140,7 @@ scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, if (IoStatus != 0) { - log_error("BeginTransaction failed, device not usable"); + log_error("BeginTransaction failed"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1784,7 +2172,7 @@ scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, if (IoStatus != 0) { - log_error("EndTransaction failed, device not usable"); + log_error("EndTransaction failed"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1816,7 +2204,7 @@ scard_handle_Status_Return(struct stream *s, IRP *irp, if (IoStatus != 0) { - log_error("StatusCall failed, device not usable"); + log_error("StatusCall failed"); /* LK_TODO delete irp and smartcard entry */ return; } @@ -1848,7 +2236,131 @@ scard_handle_Disconnect_Return(struct stream *s, IRP *irp, if (IoStatus != 0) { - log_error("Disconnect failed, device not usable"); + log_error("Disconnect failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Transmit_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("Transmit failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Control_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("Control failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Cancel_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("Cancel_call failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_GetAttrib_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("GetAttrib_call failed"); /* LK_TODO delete irp and smartcard entry */ return; } diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h index a2019535..600aef04 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -63,13 +63,13 @@ typedef struct reader_state * SCARD_SHARE_DIRECT app demands direct control of smart card, hence * it is not available to other readers */ - tui32 shared_mode_flag; + tui32 dwShareMode; /* * This field MUST have a value from Table A which is logically * OR'ed with a value from Table B. */ - tui32 preferred_protocol; + tui32 dwPreferredProtocols; /* * initialization type, must be one of the initialization type @@ -77,6 +77,24 @@ typedef struct reader_state */ tui32 init_type; + /* required by scard_send_transmit(), scard_send_control() */ + tui32 map0; + tui32 map1; + tui32 map2; + tui32 map3; + tui32 map4; + tui32 map5; + tui32 map6; + + tui32 dwProtocol; + tui32 cbPciLength; + tui32 cbSendLength; + tui32 cbRecvLength; + tui32 dwControlCode; + tui32 cbOutBufferSize; + tui32 dwAttribId; + tui32 dwAttrLen; + } READER_STATE; void scard_device_announce(tui32 device_id); @@ -104,14 +122,22 @@ 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); +int APP_CC scard_send_transmit(struct trans *con, tui32 sc_handle, + READER_STATE* rs); + +int APP_CC scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs); + +int APP_CC scard_send_cancel(struct trans *con, tui32 context); + +int APP_CC scard_send_get_attrib(struct trans *con, tui32 sc_handle, + READER_STATE* rs); + /* - SCardReconnect - SCardTransmit - SCardControl - SCardListReaderGroups - not needed: SCardFreeMemory - SCardCancel - SCardGetAttrib - SCardSetAttrib + * Notes: + * SCardTransmit - partially done + * SCardControl - partially done + * SCardListReaderGroups - not supported + * SCardSetAttrib - not supported */ #endif /* end #ifndef _SMARTCARD_C */ diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index 4d496c97..62b3b722 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -339,11 +339,11 @@ scard_process_connect(struct trans *con, struct stream *in_s) 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); + in_uint32_le(in_s, rs.dwShareMode); + in_uint32_le(in_s, rs.dwPreferredProtocols); LLOGLN(0, ("scard_process_connect: dwShareMode 0x%8.8x " - "dwPreferredProtocols 0x%8.8x", rs.shared_mode_flag, - rs.preferred_protocol)); + "dwPreferredProtocols 0x%8.8x", rs.dwShareMode, + rs.dwPreferredProtocols)); scard_send_connect(con, hContext, 1, &rs); return 0; } |