summaryrefslogtreecommitdiffstats
path: root/sesman/chansrv/smartcard.c
diff options
context:
space:
mode:
Diffstat (limited to 'sesman/chansrv/smartcard.c')
-rw-r--r--sesman/chansrv/smartcard.c140
1 files changed, 139 insertions, 1 deletions
diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c
index 6140873f..78a47ba0 100644
--- a/sesman/chansrv/smartcard.c
+++ b/sesman/chansrv/smartcard.c
@@ -106,7 +106,8 @@ do \
#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 */
@@ -155,9 +156,12 @@ 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_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);
+
/******************************************************************************
** local callbacks into this module **
******************************************************************************/
@@ -174,6 +178,9 @@ static void scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp,
tui32 DeviceId, tui32 CompletionId,
tui32 IoStatus);
+static void scard_handle_Connect_Return(struct stream *s, IRP *irp,
+ tui32 DeviceId, tui32 CompletionId,
+ tui32 IoStatus);
/******************************************************************************
** **
@@ -327,6 +334,36 @@ scard_send_irp_get_status_change(struct trans *con, int wide, tui32 timeout,
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_irp_connect(struct trans *con, int wide, 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_Connect_Return;
+ irp->user_data = con;
+
+ /* send IRP to client */
+ scard_send_Connect(irp, wide, rs);
+
+ return 0;
+}
+
/******************************************************************************
** **
** static functions local to this file **
@@ -668,6 +705,75 @@ scard_send_GetStatusChange(IRP* irp, int wide, tui32 timeout,
xstream_free(s);
}
+/**
+ * Send connect command
+ *
+ * @param irp I/O resource pkt
+ * @param wide TRUE if unicode string
+ * @param rs reader state
+ *****************************************************************************/
+static void scard_send_Connect(IRP* irp, 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;
+
+ if ((sc = smartcards[irp->scard_index]) == NULL)
+ {
+ log_error("smartcards[%d] is NULL", irp->scard_index);
+ return;
+ }
+
+ ioctl = (wide > 0) ? SCARD_IOCTL_CONNECT_A :
+ SCARD_IOCTL_CONNECT_W;
+
+ 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
+ * 20 bytes unused (s->p is currently pointed here)
+ * 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 */
+ /* LK_TODO need to handle unicode */
+ len = strlen(rs->reader_name);
+ xstream_copyin(s, rs->reader_name, len);
+
+ /* 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);
+}
+
/******************************************************************************
** **
** local callbacks into this module **
@@ -805,3 +911,35 @@ scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp,
log_debug("leaving");
}
+
+/**
+ *
+ *****************************************************************************/
+static void
+scard_handle_Connect_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("failed to connect - device not usable");
+ /* LK_TODO delete irp and smartcard entry */
+ return;
+ }
+
+ /* get OutputBufferLen */
+ xstream_rd_u32_le(s, len);
+
+ log_debug("leaving");
+}