|
|
@ -32,6 +32,8 @@
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* TODO
|
|
|
|
* TODO
|
|
|
|
*
|
|
|
|
*
|
|
|
|
|
|
|
|
* o ensure that all wide calls are handled correctly
|
|
|
|
|
|
|
|
*
|
|
|
|
* o need to query client for build number and determine whether we should use
|
|
|
|
* o need to query client for build number and determine whether we should use
|
|
|
|
* SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN
|
|
|
|
* SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN
|
|
|
|
*
|
|
|
|
*
|
|
|
@ -161,6 +163,7 @@ static int APP_CC scard_get_free_slot(void);
|
|
|
|
static void APP_CC scard_release_resources(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_EstablishContext(IRP* irp, int scope);
|
|
|
|
static void APP_CC scard_send_ReleaseContext(IRP* irp, tui32 context);
|
|
|
|
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_ListReaders(IRP* irp, tui32 context, int wide);
|
|
|
|
|
|
|
|
|
|
|
|
static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide,
|
|
|
|
static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide,
|
|
|
@ -170,6 +173,9 @@ static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide,
|
|
|
|
static void APP_CC scard_send_Connect(IRP* irp, tui32 context, int wide,
|
|
|
|
static void APP_CC scard_send_Connect(IRP* irp, tui32 context, int wide,
|
|
|
|
READER_STATE* rs);
|
|
|
|
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_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);
|
|
|
|
static void APP_CC scard_send_Status(IRP* irp, int wide, tui32 sc_handle);
|
|
|
|
static void APP_CC scard_send_Status(IRP* irp, int wide, tui32 sc_handle);
|
|
|
@ -188,6 +194,11 @@ static void APP_CC scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 IoStatus);
|
|
|
|
tui32 IoStatus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
static void APP_CC scard_handle_ListReaders_Return(struct stream *s, IRP *irp,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 IoStatus);
|
|
|
|
tui32 IoStatus);
|
|
|
@ -200,6 +211,10 @@ static void APP_CC scard_handle_Connect_Return(struct stream *s, IRP *irp,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 IoStatus);
|
|
|
|
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,
|
|
|
|
static void APP_CC scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 DeviceId, tui32 CompletionId,
|
|
|
|
tui32 IoStatus);
|
|
|
|
tui32 IoStatus);
|
|
|
@ -335,6 +350,33 @@ scard_send_release_context(struct trans *con, tui32 context)
|
|
|
|
return 0;
|
|
|
|
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_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_IsContextValid_Return;
|
|
|
|
|
|
|
|
irp->user_data = con;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* send IRP to client */
|
|
|
|
|
|
|
|
scard_send_IsContextValid(irp, context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
*****************************************************************************/
|
|
|
@ -427,6 +469,42 @@ scard_send_connect(struct trans *con, tui32 context, int wide,
|
|
|
|
return 0;
|
|
|
|
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("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_Reconnect_Return;
|
|
|
|
|
|
|
|
irp->user_data = con;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* send IRP to client */
|
|
|
|
|
|
|
|
scard_send_Reconnect(irp, context, sc_handle, rs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Lock smart card reader for exclusive access for specified smart
|
|
|
|
* Lock smart card reader for exclusive access for specified smart
|
|
|
|
* card reader handle.
|
|
|
|
* card reader handle.
|
|
|
@ -768,6 +846,56 @@ scard_send_ReleaseContext(IRP* irp, tui32 context)
|
|
|
|
xstream_free(s);
|
|
|
|
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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
*****************************************************************************/
|
|
|
@ -1066,6 +1194,73 @@ scard_send_Connect(IRP* irp, tui32 context, int wide, READER_STATE* rs)
|
|
|
|
xstream_free(s);
|
|
|
|
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
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* ......
|
|
|
|
|
|
|
|
* 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
|
|
|
|
* Lock smart card reader for exclusive access for specified smart
|
|
|
|
* card reader handle.
|
|
|
|
* card reader handle.
|
|
|
@ -1374,6 +1569,34 @@ scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp,
|
|
|
|
log_debug("leaving");
|
|
|
|
log_debug("leaving");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
*****************************************************************************/
|
|
|
@ -1470,6 +1693,38 @@ scard_handle_Connect_Return(struct stream *s, IRP *irp,
|
|
|
|
log_debug("leaving");
|
|
|
|
log_debug("leaving");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
static void APP_CC
|
|
|
|
|
|
|
|
scard_handle_Reconnect_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 reconnect");
|
|
|
|
|
|
|
|
/* LK_TODO delete irp and smartcard entry */
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* get OutputBufferLen */
|
|
|
|
|
|
|
|
xstream_rd_u32_le(s, len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log_debug("leaving");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
*****************************************************************************/
|
|
|
|