You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xrdp-proprietary/sesman/chansrv/smartcard_pcsc.c

1333 lines
40 KiB

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2013 jay.sorg@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* smartcard redirection support, PCSC daemon standin
* this will act like pcsc daemon
* pcsc lib and daemon write struct on unix domain socket for communication
*/
#define JAY_TODO_CONTEXT 0
#define JAY_TODO_WIDE 1
#define PCSC_STANDIN 1
#include "os_calls.h"
#include "smartcard.h"
#include "log.h"
#include "irp.h"
#include "devredir.h"
#include "trans.h"
#include "chansrv.h"
#if PCSC_STANDIN
#define LLOG_LEVEL 1
#define LLOGLN(_level, _args) \
do \
{ \
if (_level < LLOG_LEVEL) \
{ \
g_write("chansrv:smartcard_pcsc [%10.10u]: ", g_time3()); \
g_writeln _args ; \
} \
} \
while (0)
#define XRDP_PCSC_STATE_NONE 0
#define XRDP_PCSC_STATE_GOT_EC (1 << 0) /* establish context */
#define XRDP_PCSC_STATE_GOT_LR (1 << 1) /* list readers */
#define XRDP_PCSC_STATE_GOT_RC (1 << 2) /* release context */
#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 */
#define XRDP_PCSC_STATE_GOT_D (1 << 9) /* disconnect */
#define XRDP_PCSC_STATE_GOT_ST (1 << 10) /* get status */
/* TODO: put this in con */
static int g_xrdp_pcsc_state = XRDP_PCSC_STATE_NONE;
static int g_xrdp_pcsc_extra1;
extern int g_display_num; /* in chansrv.c */
/*****************************************************************************/
struct pcsc_client
{
struct trans *con;
};
#if 0
static struct pcsc_client *g_head = 0;
static struct pcsc_client *g_tail = 0;
#endif
static struct trans *g_lis = 0;
static struct trans *g_con = 0; /* todo, remove this */
static char g_pcsclite_ipc_dir[256] = "";
static char g_pcsclite_ipc_file[256] = "";
static int g_pub_file_fd = 0;
/*****************************************************************************/
int APP_CC
scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout)
{
LLOGLN(10, ("scard_pcsc_get_wait_objs"));
if (g_lis != 0)
{
trans_get_wait_objs(g_lis, objs, count);
}
if (g_con != 0)
{
trans_get_wait_objs(g_con, objs, count);
}
return 0;
}
/*****************************************************************************/
int APP_CC
scard_pcsc_check_wait_objs(void)
{
LLOGLN(10, ("scard_pcsc_check_wait_objs:"));
if (g_lis != 0)
{
if (trans_check_wait_objs(g_lis) != 0)
{
LLOGLN(0, ("scard_pcsc_check_wait_objs: g_lis trans_check_wait_objs error"));
}
}
if (g_con != 0)
{
if (trans_check_wait_objs(g_con) != 0)
{
LLOGLN(0, ("scard_pcsc_check_wait_objs: g_con trans_check_wait_objs error"));
/* TODO: cleanup better */
trans_delete(g_con);
g_con = 0;
g_xrdp_pcsc_state = 0;
}
}
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_establish_context(struct trans *con, struct stream *in_s)
{
int dwScope;
LLOGLN(10, ("scard_process_establish_context:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC)
{
LLOGLN(0, ("scard_process_establish_context: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_EC;
in_uint32_le(in_s, dwScope);
LLOGLN(10, ("scard_process_establish_context: dwScope 0x%8.8x", dwScope));
scard_send_establish_context(con, dwScope);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_establish_context_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
int bytes;
tui32 context;
tui32 context_len;
struct stream *out_s;
LLOGLN(10, ("scard_function_establish_context_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) == 0)
{
LLOGLN(0, ("scard_function_establish_context_return: opps "
"g_xrdp_pcsc_state 0x%8.8x, g_xrdp_pcsc_state"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_EC;
context = 0;
if (status == 0)
{
in_uint8s(in_s, 28);
in_uint32_le(in_s, context_len);
if (context_len != 4)
{
LLOGLN(0, ("scard_function_establish_context_return: opps "
"context_len %d", context_len));
return 1;
}
in_uint32_le(in_s, context);
LLOGLN(10, ("scard_function_establish_context_return: context 0x%8.8x",
context));
}
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, context);
out_uint32_le(out_s, status); /* 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, 0x01); /* SCARD_ESTABLISH_CONTEXT 0x01 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_release_context(struct trans *con, struct stream *in_s)
{
int hContext;
LLOGLN(10, ("scard_process_release_context:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC)
{
LLOGLN(0, ("scard_process_establish_context: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_RC;
in_uint32_le(in_s, hContext);
LLOGLN(10, ("scard_process_release_context: hContext 0x%8.8x", hContext));
scard_send_release_context(con, hContext);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_release_context_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
int bytes;
struct stream *out_s;
LLOGLN(10, ("scard_function_release_context_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) == 0)
{
LLOGLN(0, ("scard_function_release_context_return: opps"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_RC;
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, status); /* 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, 0x02); /* SCARD_RELEASE_CONTEXT 0x02 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_list_readers(struct trans *con, struct stream *in_s)
{
int hContext;
int bytes_groups;
int cchReaders;
char *groups;
LLOGLN(10, ("scard_process_list_readers:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR)
{
LLOGLN(0, ("scard_process_list_readers: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_LR;
in_uint32_le(in_s, hContext);
in_uint32_le(in_s, bytes_groups);
groups = (char *) g_malloc(bytes_groups + 1, 1);
in_uint8a(in_s, groups, bytes_groups);
in_uint32_le(in_s, cchReaders);
g_xrdp_pcsc_extra1 = cchReaders;
LLOGLN(10, ("scard_process_list_readers: hContext 0x%8.8x cchReaders %d",
hContext, cchReaders));
scard_send_list_readers(con, hContext, groups, cchReaders, 1);
g_free(groups);
return 0;
}
/*****************************************************************************/
int APP_CC
scard_function_list_readers_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
struct stream *out_s;
int chr;
int readers;
int rn_index;
int index;
int bytes;
int cchReaders;
int llen;
twchar reader_name[100];
char lreader_name[16][100];
LLOGLN(10, ("scard_function_list_readers_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) == 0)
{
LLOGLN(0, ("scard_function_list_readers_return: opps"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_LR;
cchReaders = g_xrdp_pcsc_extra1;
g_memset(reader_name, 0, sizeof(reader_name));
g_memset(lreader_name, 0, sizeof(lreader_name));
rn_index = 0;
readers = 0;
llen = 0;
if (status == 0)
{
in_uint8s(in_s, 28);
in_uint32_le(in_s, len);
llen = len;
if (cchReaders > 0)
{
while (len > 0)
{
in_uint16_le(in_s, chr);
len -= 2;
if (chr == 0)
{
if (reader_name[0] != 0)
{
g_wcstombs(lreader_name[readers], reader_name, 99);
g_memset(reader_name, 0, sizeof(reader_name));
readers++;
}
reader_name[0] = 0;
rn_index = 0;
}
else
{
reader_name[rn_index] = chr;
rn_index++;
}
}
}
if (rn_index > 0)
{
if (reader_name[0] != 0)
{
g_wcstombs(lreader_name[readers], reader_name, 99);
g_memset(reader_name, 0, sizeof(reader_name));
readers++;
}
}
}
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, llen);
out_uint32_le(out_s, readers);
for (index = 0; index < readers; index++)
{
out_uint8a(out_s, lreader_name[index], 100);
}
out_uint32_le(out_s, status); /* 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, 0x03); /* SCARD_LIST_READERS 0x03 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_connect(struct trans *con, struct stream *in_s)
{
int hContext;
READER_STATE rs;
LLOGLN(10, ("scard_process_connect:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C)
{
LLOGLN(0, ("scard_process_connect: opps"));
return 1;
}
g_memset(&rs, 0, sizeof(rs));
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_C;
in_uint32_le(in_s, hContext);
in_uint8a(in_s, rs.reader_name, 100);
in_uint32_le(in_s, rs.dwShareMode);
in_uint32_le(in_s, rs.dwPreferredProtocols);
LLOGLN(10, ("scard_process_connect: rs.reader_name %s dwShareMode 0x%8.8x "
"dwPreferredProtocols 0x%8.8x", rs.reader_name, rs.dwShareMode,
rs.dwPreferredProtocols));
scard_send_connect(con, hContext, 1, &rs);
return 0;
}
/*****************************************************************************/
int APP_CC
scard_function_connect_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
int dwActiveProtocol;
int hCard;
int bytes;
struct stream *out_s;
LLOGLN(10, ("scard_function_connect_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) == 0)
{
LLOGLN(0, ("scard_function_connect_return: opps"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_C;
dwActiveProtocol = 0;
hCard = 0;
if (status == 0)
{
in_uint8s(in_s, 36);
in_uint32_le(in_s, dwActiveProtocol);
in_uint8s(in_s, 4);
in_uint32_le(in_s, hCard);
LLOGLN(10, (" hCard %d dwActiveProtocol %d", hCard, dwActiveProtocol));
}
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, hCard);
out_uint32_le(out_s, dwActiveProtocol);
out_uint32_le(out_s, status); /* 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, 0x04); /* SCARD_CONNECT 0x04 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_disconnect(struct trans *con, struct stream *in_s)
{
int hContext;
int hCard;
int dwDisposition;
LLOGLN(10, ("scard_process_disconnect:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_D)
{
LLOGLN(0, ("scard_process_disconnect: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_D;
in_uint32_le(in_s, hCard);
in_uint32_le(in_s, dwDisposition);
hContext = 1;
scard_send_disconnect(con, hContext, hCard, dwDisposition);
return 0;
}
/*****************************************************************************/
int APP_CC
scard_function_disconnect_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
int dwActiveProtocol;
int hCard;
int bytes;
struct stream *out_s;
LLOGLN(10, ("scard_function_disconnect_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_D) == 0)
{
LLOGLN(0, ("scard_function_connect_return: opps"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_D;
dwActiveProtocol = 0;
hCard = 0;
if (status == 0)
{
in_uint8s(in_s, 36);
in_uint32_le(in_s, dwActiveProtocol);
in_uint8s(in_s, 4);
in_uint32_le(in_s, hCard);
LLOGLN(10, ("scard_function_connect_return: hCard %d "
"dwActiveProtocol %d", hCard, dwActiveProtocol));
}
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, status); /* 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, 0x06); /* SCARD_DISCONNECT 0x06 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_begin_transaction(struct trans *con, struct stream *in_s)
{
int hCard;
LLOGLN(10, ("scard_process_begin_transaction:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT)
{
LLOGLN(0, ("scard_process_begin_transaction: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_BT;
in_uint32_le(in_s, hCard);
LLOGLN(10, ("scard_process_begin_transaction: hCard 0x%8.8x", hCard));
scard_send_begin_transaction(con, hCard);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_begin_transaction_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
struct stream *out_s;
int bytes;
LLOGLN(10, ("scard_function_begin_transaction_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//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, status); /* 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(10, ("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(10, ("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, int status)
{
struct stream *out_s;
int bytes;
LLOGLN(10, ("scard_function_end_transaction_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//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, status); /* 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_function_cancel_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_get_attrib_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_transmit(struct trans *con, struct stream *in_s)
{
int hCard;
int recv_bytes;
int send_bytes;
char *send_data;
struct xrdp_scard_io_request send_ior;
struct xrdp_scard_io_request recv_ior;
LLOGLN(10, ("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(10, ("scard_process_transmit:"));
in_uint32_le(in_s, hCard);
in_uint32_le(in_s, send_ior.dwProtocol);
in_uint32_le(in_s, send_ior.cbPciLength);
in_uint32_le(in_s, send_ior.extra_bytes);
in_uint8p(in_s, send_ior.extra_data, send_ior.extra_bytes);
in_uint32_le(in_s, send_bytes);
in_uint8p(in_s, send_data, send_bytes);
in_uint32_le(in_s, recv_ior.dwProtocol);
in_uint32_le(in_s, recv_ior.cbPciLength);
in_uint32_le(in_s, recv_ior.extra_bytes);
in_uint8p(in_s, recv_ior.extra_data, recv_ior.extra_bytes);
in_uint32_le(in_s, recv_bytes);
LLOGLN(10, ("scard_process_transmit: send dwProtocol %d cbPciLength %d "
"recv dwProtocol %d cbPciLength %d send_bytes %d ",
send_ior.dwProtocol, send_ior.cbPciLength, recv_ior.dwProtocol,
recv_ior.cbPciLength, send_bytes));
//g_hexdump(in_s->p, send_bytes);
LLOGLN(10, ("scard_process_transmit: recv_bytes %d", recv_bytes));
scard_send_transmit(con, hCard, send_data, send_bytes, recv_bytes,
&send_ior, &recv_ior);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_transmit_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
struct stream *out_s;
int bytes;
int val;
int cbRecvLength;
struct xrdp_scard_io_request recv_ior;
char *recvBuf;
LLOGLN(10, ("scard_function_transmit_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//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;
g_memset(&recv_ior, 0, sizeof(recv_ior));
cbRecvLength = 0;
recvBuf = 0;
if (status == 0)
{
in_uint8s(in_s, 20);
in_uint32_le(in_s, val);
if (val != 0)
{
/* pioRecvPci */
in_uint8s(in_s, 8);
in_uint32_le(in_s, recv_ior.dwProtocol);
in_uint32_le(in_s, recv_ior.cbPciLength);
recv_ior.cbPciLength += 8;
in_uint32_le(in_s, recv_ior.extra_bytes);
if (recv_ior.extra_bytes > 0)
{
in_uint8p(in_s, recv_ior.extra_data, recv_ior.extra_bytes);
}
}
in_uint8s(in_s, 4);
in_uint32_le(in_s, val);
if (val != 0)
{
in_uint32_le(in_s, cbRecvLength);
in_uint8p(in_s, recvBuf, cbRecvLength);
}
}
LLOGLN(10, ("scard_function_transmit_return: cbRecvLength %d", cbRecvLength));
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, recv_ior.dwProtocol);
out_uint32_le(out_s, recv_ior.cbPciLength);
out_uint32_le(out_s, recv_ior.extra_bytes);
out_uint8a(out_s, recv_ior.extra_data, recv_ior.extra_bytes);
out_uint32_le(out_s, cbRecvLength);
out_uint8a(out_s, recvBuf, cbRecvLength);
out_uint32_le(out_s, status); /* 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, 0x09); /* SCARD_TRANSMIT 0x09 */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_control(struct trans *con, struct stream *in_s)
{
int hCard;
int send_bytes;
int recv_bytes;
int control_code;
char *send_data;
LLOGLN(10, ("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(10, ("scard_process_control:"));
in_uint32_le(in_s, hCard);
in_uint32_le(in_s, control_code);
in_uint32_le(in_s, send_bytes);
in_uint8p(in_s, send_data, send_bytes);
in_uint32_le(in_s, recv_bytes);
scard_send_control(con, hCard, send_data, send_bytes, recv_bytes,
control_code);
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_control_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
struct stream *out_s;
int bytes;
int cbRecvLength;
char *recvBuf;
LLOGLN(10, ("scard_function_control_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//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;
cbRecvLength = 0;
recvBuf = 0;
if (status == 0)
{
in_uint8s(in_s, 28);
in_uint32_le(in_s, cbRecvLength);
in_uint8p(in_s, recvBuf, cbRecvLength);
}
LLOGLN(10, ("scard_function_control_return: cbRecvLength %d", cbRecvLength));
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
out_uint32_le(out_s, cbRecvLength);
out_uint8a(out_s, recvBuf, cbRecvLength);
out_uint32_le(out_s, status); /* 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, 0x0A); /* SCARD_CONTROL 0x0A */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_status(struct trans *con, struct stream *in_s)
{
int hCard;
int cchReaderLen;
int cbAtrLen;
LLOGLN(10, ("scard_process_status:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ST)
{
LLOGLN(0, ("scard_process_status: opps"));
return 1;
}
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_ST;
in_uint32_le(in_s, hCard);
in_uint32_le(in_s, cchReaderLen);
in_uint32_le(in_s, cbAtrLen);
scard_send_status(con, 1, hCard, cchReaderLen, cbAtrLen);
return 0;
}
#define MS_SCARD_UNKNOWN 0
#define MS_SCARD_ABSENT 1
#define MS_SCARD_PRESENT 2
#define MS_SCARD_SWALLOWED 3
#define MS_SCARD_POWERED 4
#define MS_SCARD_NEGOTIABLE 5
#define MS_SCARD_SPECIFIC 6
#define PC_SCARD_UNKNOWN 0x0001 /**< Unknown state */
#define PC_SCARD_ABSENT 0x0002 /**< Card is absent */
#define PC_SCARD_PRESENT 0x0004 /**< Card is present */
#define PC_SCARD_SWALLOWED 0x0008 /**< Card not powered */
#define PC_SCARD_POWERED 0x0010 /**< Card is powered */
#define PC_SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */
#define PC_SCARD_SPECIFIC 0x0040 /**< PTS has been set */
static int g_ms2pc[] = { PC_SCARD_UNKNOWN, PC_SCARD_ABSENT,
PC_SCARD_PRESENT, PC_SCARD_SWALLOWED,
PC_SCARD_POWERED, PC_SCARD_NEGOTIABLE,
PC_SCARD_SPECIFIC };
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_status_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
struct stream *out_s;
int index;
int bytes;
int dwReaderLen;
int dwState;
int dwProtocol;
int dwAtrLen;
char attr[32];
twchar reader_name[100];
char lreader_name[100];
LLOGLN(10, ("scard_function_status_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ST) == 0)
{
LLOGLN(0, ("scard_function_status_return: opps"));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_ST;
dwReaderLen = 0;
dwState = 0;
dwProtocol = 0;
dwAtrLen = 0;
lreader_name[0] = 0;
if (status == 0)
{
in_uint8s(in_s, 20);
in_uint32_le(in_s, dwReaderLen);
in_uint8s(in_s, 4);
in_uint32_le(in_s, dwState);
dwState = g_ms2pc[dwState % 6];
in_uint32_le(in_s, dwProtocol);
in_uint8a(in_s, attr, 32);
in_uint32_le(in_s, dwAtrLen);
in_uint32_le(in_s, dwReaderLen);
dwReaderLen /= 2;
g_memset(reader_name, 0, sizeof(reader_name));
g_memset(lreader_name, 0, sizeof(lreader_name));
for (index = 0; index < dwReaderLen; index++)
{
in_uint16_le(in_s, reader_name[index]);
}
g_wcstombs(lreader_name, reader_name, 99);
}
LLOGLN(10, ("scard_function_status_return: dwAtrLen %d dwReaderLen %d "
"dwProtocol %d dwState %d name %s",
dwAtrLen, dwReaderLen, dwProtocol, dwState, lreader_name));
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
dwReaderLen = g_strlen(lreader_name);
out_uint32_le(out_s, dwReaderLen);
out_uint8a(out_s, lreader_name, dwReaderLen);
out_uint32_le(out_s, dwState);
out_uint32_le(out_s, dwProtocol);
out_uint32_le(out_s, dwAtrLen);
out_uint8a(out_s, attr, dwAtrLen);
out_uint32_le(out_s, status); /* 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, 0x0B); /* SCARD_STATUS 0x0B */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_get_status_change(struct trans *con, struct stream *in_s)
{
int index;
int hContext;
int dwTimeout;
int cReaders;
READER_STATE *rsa;
LLOGLN(10, ("scard_process_get_status_change:"));
if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC)
{
LLOGLN(0, ("scard_process_get_status_change: opps"));
return 1;
}
in_uint32_le(in_s, hContext);
in_uint32_le(in_s, dwTimeout);
in_uint32_le(in_s, cReaders);
if ((cReaders < 0) || (cReaders > 16))
{
LLOGLN(0, ("scard_process_get_status_change: bad cReaders %d", cReaders));
return 1;
}
rsa = (READER_STATE *) g_malloc(sizeof(READER_STATE) * cReaders, 1);
for (index = 0; index < cReaders; index++)
{
in_uint8a(in_s, rsa[index].reader_name, 100);
LLOGLN(10, ("scard_process_get_status_change: reader_name %s",
rsa[index].reader_name));
in_uint32_le(in_s, rsa[index].current_state);
LLOGLN(10, ("scard_process_get_status_change: current_state %d",
rsa[index].current_state));
in_uint32_le(in_s, rsa[index].event_state);
LLOGLN(10, ("scard_process_get_status_change: event_state %d",
rsa[index].event_state));
in_uint32_le(in_s, rsa[index].atr_len);
LLOGLN(10, ("scard_process_get_status_change: atr_len %d",
rsa[index].atr_len));
in_uint8a(in_s, rsa[index].atr, 36);
}
LLOGLN(10, ("scard_process_get_status_change: hContext 0x%8.8x dwTimeout "
"%d cReaders %d", hContext, dwTimeout, cReaders));
g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_GSC;
scard_send_get_status_change(con, hContext, 1, dwTimeout, cReaders, rsa);
g_free(rsa);
return 0;
}
/*****************************************************************************/
int APP_CC
scard_function_get_status_change_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
int bytes;
int index;
int cReaders;
tui32 current_state;
tui32 event_state;
tui32 atr_len; /* number of bytes in atr[] */
tui8 atr[36];
struct stream *out_s;
LLOGLN(10, ("scard_function_get_status_change_return:"));
LLOGLN(10, (" status 0x%8.8x", status));
//g_hexdump(in_s->p, len);
if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) == 0)
{
LLOGLN(0, ("scard_function_get_status_change_return: opps "
"g_xrdp_pcsc_state 0x%8.8x", g_xrdp_pcsc_state));
return 1;
}
g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_GSC;
out_s = trans_get_out_s(con, 8192);
s_push_layer(out_s, iso_hdr, 8);
if (status != 0)
{
out_uint32_le(out_s, 0); /* cReaders */
out_uint32_le(out_s, status); /* SCARD_S_SUCCESS status */
}
else
{
in_uint8s(in_s, 28);
in_uint32_le(in_s, cReaders);
LLOGLN(10, (" cReaders %d", cReaders));
out_uint32_le(out_s, cReaders);
if (cReaders > 0)
{
for (index = 0; index < cReaders; index++)
{
in_uint32_le(in_s, current_state);
out_uint32_le(out_s, current_state);
in_uint32_le(in_s, event_state);
out_uint32_le(out_s, event_state);
in_uint32_le(in_s, atr_len);
out_uint32_le(out_s, atr_len);
in_uint8a(in_s, atr, 36);
out_uint8a(out_s, atr, 36);
}
}
out_uint32_le(out_s, status); /* 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, 0x0C); /* SCARD_ESTABLISH_CONTEXT 0x0C */
return trans_force_write(con);
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_function_is_context_valid_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC scard_function_reconnect_return(struct trans *con,
struct stream *in_s,
int len, int status)
{
return 0;
}
/*****************************************************************************/
/* returns error */
int APP_CC
scard_process_msg(struct trans *con, struct stream *in_s, int command)
{
int rv;
LLOGLN(10, ("scard_process_msg: command 0x%4.4x", command));
rv = 0;
switch (command)
{
case 0x01: /* SCARD_ESTABLISH_CONTEXT */
LLOGLN(10, ("scard_process_msg: SCARD_ESTABLISH_CONTEXT"));
rv = scard_process_establish_context(con, in_s);
break;
case 0x02: /* SCARD_RELEASE_CONTEXT */
LLOGLN(10, ("scard_process_msg: SCARD_RELEASE_CONTEXT"));
rv = scard_process_release_context(con, in_s);
break;
case 0x03: /* SCARD_LIST_READERS */
LLOGLN(10, ("scard_process_msg: SCARD_LIST_READERS"));
rv = scard_process_list_readers(con, in_s);
break;
case 0x04: /* SCARD_CONNECT */
LLOGLN(10, ("scard_process_msg: SCARD_CONNECT"));
rv = scard_process_connect(con, in_s);
break;
case 0x05: /* SCARD_RECONNECT */
LLOGLN(0, ("scard_process_msg: SCARD_RECONNECT"));
break;
case 0x06: /* SCARD_DISCONNECT */
LLOGLN(10, ("scard_process_msg: SCARD_DISCONNECT"));
rv = scard_process_disconnect(con, in_s);
break;
case 0x07: /* SCARD_BEGIN_TRANSACTION */
LLOGLN(10, ("scard_process_msg: SCARD_BEGIN_TRANSACTION"));
rv = scard_process_begin_transaction(con, in_s);
break;
case 0x08: /* SCARD_END_TRANSACTION */
LLOGLN(10, ("scard_process_msg: SCARD_END_TRANSACTION"));
rv = scard_process_end_transaction(con, in_s);
break;
case 0x09: /* SCARD_TRANSMIT */
LLOGLN(10, ("scard_process_msg: SCARD_TRANSMIT"));
rv = scard_process_transmit(con, in_s);
break;
case 0x0A: /* SCARD_CONTROL */
LLOGLN(10, ("scard_process_msg: SCARD_CONTROL"));
rv = scard_process_control(con, in_s);
break;
case 0x0B: /* SCARD_STATUS */
LLOGLN(10, ("scard_process_msg: SCARD_STATUS"));
rv = scard_process_status(con, in_s);
break;
case 0x0C: /* SCARD_GET_STATUS_CHANGE */
LLOGLN(10, ("scard_process_msg: SCARD_GET_STATUS_CHANGE"));
rv = scard_process_get_status_change(con, in_s);
break;
case 0x0D: /* SCARD_CANCEL */
LLOGLN(0, ("scard_process_msg: SCARD_CANCEL"));
break;
case 0x0E: /* SCARD_CANCEL_TRANSACTION */
LLOGLN(0, ("scard_process_msg: SCARD_CANCEL_TRANSACTION"));
break;
case 0x0F: /* SCARD_GET_ATTRIB */
LLOGLN(0, ("scard_process_msg: SCARD_GET_ATTRIB"));
break;
case 0x10: /* SCARD_SET_ATTRIB */
LLOGLN(0, ("scard_process_msg: SCARD_SET_ATTRIB"));
break;
default:
LLOGLN(0, ("scard_process_msg: unknown mtype 0x%4.4x", command));
rv = 1;
break;
}
return rv;
}
/*****************************************************************************/
/* returns error */
int DEFAULT_CC
my_pcsc_trans_data_in(struct trans *trans)
{
struct stream *s;
int size;
int command;
int error;
LLOGLN(10, ("my_pcsc_trans_data_in:"));
if (trans == 0)
{
return 0;
}
if (trans != g_con)
{
return 1;
}
s = trans_get_in_s(trans);
in_uint32_le(s, size);
in_uint32_le(s, command);
LLOGLN(10, ("my_pcsc_trans_data_in: size %d command %d", size, command));
error = trans_force_read(trans, size);
if (error == 0)
{
error = scard_process_msg(g_con, s, command);
}
return error;
}
/*****************************************************************************/
/* got a new connection from libpcsclite */
int DEFAULT_CC
my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans)
{
LLOGLN(10, ("my_pcsc_trans_conn_in:"));
if (trans == 0)
{
return 1;
}
if (trans != g_lis)
{
return 1;
}
if (new_trans == 0)
{
return 1;
}
g_con = new_trans;
g_con->trans_data_in = my_pcsc_trans_data_in;
g_con->header_size = 8;
return 0;
}
/*****************************************************************************/
int APP_CC
scard_pcsc_init(void)
{
char *home;
int disp;
int error;
LLOGLN(0, ("scard_pcsc_init:"));
if (g_lis == 0)
{
g_lis = trans_create(2, 8192, 8192);
home = g_getenv("HOME");
disp = g_display_num;
g_snprintf(g_pcsclite_ipc_dir, 255, "%s/.pcsc%d", home, disp);
if (g_directory_exist(g_pcsclite_ipc_dir))
{
if (!g_remove_dir(g_pcsclite_ipc_dir))
{
LLOGLN(0, ("scard_pcsc_init: g_remove_dir failed"));
}
}
if (!g_directory_exist(g_pcsclite_ipc_dir))
{
if (!g_create_dir(g_pcsclite_ipc_dir))
{
if (!g_directory_exist(g_pcsclite_ipc_dir))
{
LLOGLN(0, ("scard_pcsc_init: g_create_dir failed"));
}
}
}
g_chmod_hex(g_pcsclite_ipc_dir, 0x1777);
g_snprintf(g_pcsclite_ipc_file, 255, "%s/pcscd.comm", g_pcsclite_ipc_dir);
g_lis->trans_conn_in = my_pcsc_trans_conn_in;
error = trans_listen(g_lis, g_pcsclite_ipc_file);
if (error != 0)
{
LLOGLN(0, ("scard_pcsc_init: trans_listen failed for port %s",
g_pcsclite_ipc_file));
return 1;
}
}
return 0;
}
/*****************************************************************************/
int APP_CC
scard_pcsc_deinit(void)
{
LLOGLN(0, ("scard_pcsc_deinit:"));
if (g_lis != 0)
{
trans_delete(g_lis);
g_lis = 0;
}
if (g_pub_file_fd != 0)
{
g_file_close(g_pub_file_fd);
g_pub_file_fd = 0;
}
if (g_pcsclite_ipc_dir[0] != 0)
{
g_file_delete(g_pcsclite_ipc_file);
if (!g_remove_dir(g_pcsclite_ipc_dir))
{
LLOGLN(0, ("scard_pcsc_deinit: g_remove_dir failed"));
}
g_pcsclite_ipc_dir[0] = 0;
}
return 0;
}
#else
int APP_CC
scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout)
{
return 0;
}
int APP_CC
scard_pcsc_check_wait_objs(void)
{
return 0;
}
int APP_CC
scard_pcsc_init(void)
{
return 0;
}
int APP_CC
scard_pcsc_deinit(void)
{
return 0;
}
#endif