diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index a0e15e6e..7d5cb39e 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -113,7 +113,8 @@ do \ #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 */ @@ -126,6 +127,12 @@ do \ #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 */ @@ -155,12 +162,17 @@ static int scard_add_new_device(tui32 device_id); static int scard_get_free_slot(void); static void scard_release_resources(void); static void scard_send_EstablishContext(IRP* irp, int scope); +static void scard_send_ReleaseContext(IRP* irp); static void scard_send_ListReaders(IRP* irp, int wide); static void scard_send_GetStatusChange(IRP* irp, int wide, tui32 timeout, tui32 num_readers, READER_STATE* rsa); static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs); +static void scard_send_BeginTransaction(IRP* irp, tui32 sc_handle); +static void scard_send_EndTransaction(IRP* irp, tui32 sc_handle); +static void scard_send_Status(IRP* irp, int wide, tui32 sc_handle); +static void scard_send_Disconnect(IRP* irp, tui32 sc_handle); /****************************************************************************** ** local callbacks into this module ** @@ -170,6 +182,10 @@ static void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); +static void scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + static void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); @@ -182,6 +198,22 @@ static void scard_handle_Connect_Return(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); +static void scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + /****************************************************************************** ** ** ** externally accessible functions, defined in smartcard.h ** @@ -274,6 +306,33 @@ scard_send_irp_establish_context(struct trans *con, int scope) return 0; } +/** + * Release a previously established Smart Card context + *****************************************************************************/ +int +APP_CC scard_send_release_context(struct trans *con) +{ + 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_ReleaseContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_ReleaseContext(irp); + + return 0; +} + /** * *****************************************************************************/ @@ -364,6 +423,127 @@ scard_send_irp_connect(struct trans *con, int wide, READER_STATE* rs) return 0; } +/** + * 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; + + /* 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_BeginTransaction_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_BeginTransaction(irp, sc_handle); + + return 0; +} + +/** + * 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) +{ + 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_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("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_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 sc_handle) +{ + 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_Disconnect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Disconnect(irp, sc_handle); + + return 0; +} + /****************************************************************************** ** ** ** static functions local to this file ** @@ -532,6 +712,58 @@ scard_send_EstablishContext(IRP *irp, int scope) xstream_free(s); } +/** + * Release a previously established Smart Card context + *****************************************************************************/ +static void +scard_send_ReleaseContext(IRP* irp) +{ + /* 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, sc->Context_len); + xstream_copyin(s, sc->Context, sc->Context_len); + + /* 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); +} + /** * *****************************************************************************/ @@ -551,8 +783,8 @@ 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; @@ -654,8 +886,8 @@ scard_send_GetStatusChange(IRP* irp, int wide, tui32 timeout, return; } - ioctl = (wide > 0) ? SCARD_IOCTL_GET_STATUS_CHANGE_W : - SCARD_IOCTL_GET_STATUS_CHANGE_A; + ioctl = (wide) ? SCARD_IOCTL_GET_STATUS_CHANGE_W : + SCARD_IOCTL_GET_STATUS_CHANGE_A; if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) return; @@ -744,6 +976,9 @@ static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs) tui32 ioctl; int bytes; int len; + int num_chars; + int index; + twchar w_reader_name[100]; if ((sc = smartcards[irp->scard_index]) == NULL) { @@ -751,8 +986,8 @@ static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs) return; } - ioctl = (wide > 0) ? SCARD_IOCTL_CONNECT_A : - SCARD_IOCTL_CONNECT_W; + ioctl = (wide) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) return; @@ -764,7 +999,7 @@ static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs) * 20 bytes padding * u32 4 bytes len 8, LE, v1 * u32 4 bytes filler - * 20 bytes unused (s->p is currently pointed here) + * 20 bytes unused (s->p currently pointed here at unused[0]) * u32 4 bytes dwShareMode * u32 4 bytes dwPreferredProtocol * xx bytes reader name @@ -777,9 +1012,18 @@ static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs) xstream_wr_u32_le(s, rs->preferred_protocol); /* insert reader name */ - /* LK_TODO need to handle unicode */ - len = strlen(rs->reader_name); - xstream_copyin(s, rs->reader_name, len); + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + 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]); + } /* insert context */ xstream_wr_u32_le(s, sc->Context_len); @@ -796,6 +1040,244 @@ static void scard_send_Connect(IRP* irp, int wide, READER_STATE* rs) xstream_free(s); } +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +static void +scard_send_BeginTransaction(IRP* irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 4.9 */ + + 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_BEGIN_TRANSACTION)) == NULL) + return; + + /* + * 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 + */ + + xstream_seek(s, 36); + + /* 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); +} + +/** + * 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 + *****************************************************************************/ +static void +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 + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +static void +scard_send_Status(IRP* irp, int wide, tui32 sc_handle) +{ + /* see [MS-RDPESC] 2.2.2.18 */ + + 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 +scard_send_Disconnect(IRP* irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 3.1.4.30 */ + + 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_DISCONNECT)) == 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 + * 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, sc->Context_len); + xstream_copyin(s, sc->Context, sc->Context_len); + + /* 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 ** @@ -868,6 +1350,38 @@ scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, log_debug("leaving"); } +/** + * + *****************************************************************************/ +static void +scard_handle_ReleaseContext_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("ReleaseContext failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + /** * *****************************************************************************/ @@ -965,3 +1479,131 @@ scard_handle_Connect_Return(struct stream *s, IRP *irp, log_debug("leaving"); } + +/** + * + *****************************************************************************/ +static void +scard_handle_BeginTransaction_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("BeginTransaction failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_EndTransaction_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("EndTransaction failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Status_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("StatusCall failed, device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Disconnect_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("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 8352a01e..046bb14a 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -74,11 +74,16 @@ 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_irp_establish_context(struct trans *con, int scope); +int APP_CC scard_send_release_context(struct trans *con); int APP_CC scard_send_irp_list_readers(struct trans *con); int APP_CC scard_send_irp_get_status_change(struct trans *con, int wide, tui32 timeout, tui32 num_readers, READER_STATE* rsa); int APP_CC scard_send_irp_connect(struct trans *con, int wide, 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 sc_handle); #endif /* end #ifndef _SMARTCARD_C */