smartcard: developer checkin for smartcard support

ulab-next
Laxmikant Rashinkar 12 years ago
parent cd0a8721d1
commit 89b7cd269e

@ -368,18 +368,18 @@ do \
} while (0) } while (0)
/* copy data into stream */ /* copy data into stream */
#define xstream_copyin(_s, _dest, _len) \ #define xstream_copyin(_s, _dest, _len) \
do \ do \
{ \ { \
g_memcpy((_s)->p, (_dest), (_len)); \ g_memcpy((_s)->p, (_dest), (_len)); \
(_s)->p += (_len); \ (_s)->p += (_len); \
} while (0) } while (0)
/* copy data out of stream */ /* copy data out of stream */
#define xstream_copyout(_dest, _s, _len) \ #define xstream_copyout(_dest, _s, _len) \
{ \
do \ do \
g_memcpy((_dest), (_s)->p, (_len)); \ { \
g_memcpy((_dest), (_s)->p, (_len)); \
(_s)->p += (_len); \ (_s)->p += (_len); \
} while (0) } while (0)

@ -35,10 +35,12 @@ xrdp_chansrv_SOURCES = \
clipboard.c \ clipboard.c \
clipboard_file.c \ clipboard_file.c \
devredir.c \ devredir.c \
smartcard.c \
rail.c \ rail.c \
xcommon.c \ xcommon.c \
drdynvc.c \ drdynvc.c \
chansrv_fuse.c chansrv_fuse.c \
irp.c
xrdp_chansrv_LDFLAGS = \ xrdp_chansrv_LDFLAGS = \
$(EXTRA_FLAGS) $(EXTRA_FLAGS)

@ -116,7 +116,7 @@ void xfuse_devredir_cb_file_close(void *vp) {}
#define LOG_ERROR 0 #define LOG_ERROR 0
#define LOG_INFO 1 #define LOG_INFO 1
#define LOG_DEBUG 2 #define LOG_DEBUG 2
#define LOG_LEVEL LOG_ERROR #define LOG_LEVEL LOG_DEBUG
#define log_error(_params...) \ #define log_error(_params...) \
{ \ { \

@ -34,7 +34,57 @@
* o mark local funcs with static * o mark local funcs with static
*/ */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "arch.h"
#include "parse.h"
#include "os_calls.h"
#include "log.h"
#include "chansrv_fuse.h"
#include "devredir.h" #include "devredir.h"
#include "smartcard.h"
/* module based logging */
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_DEBUG
#endif
#define log_error(_params...) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ERROR: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
/* globals */ /* globals */
extern int g_rdpdr_chan_id; /* in chansrv.c */ extern int g_rdpdr_chan_id; /* in chansrv.c */
@ -43,14 +93,12 @@ int g_is_port_redir_supported = 0;
int g_is_drive_redir_supported = 0; int g_is_drive_redir_supported = 0;
int g_is_smartcard_redir_supported = 0; int g_is_smartcard_redir_supported = 0;
int g_drive_redir_version = 1; int g_drive_redir_version = 1;
char g_preferred_dos_name_for_filesystem[9];
char g_full_name_for_filesystem[1024]; char g_full_name_for_filesystem[1024];
tui32 g_completion_id = 1; tui32 g_completion_id = 1;
tui32 g_clientID; /* unique client ID - announced by client */ tui32 g_clientID; /* unique client ID - announced by client */
tui32 g_device_id; /* unique device ID - announced by client */ tui32 g_device_id; /* unique device ID - announced by client */
tui16 g_client_rdp_version; /* returned by client */ tui16 g_client_rdp_version; /* returned by client */
IRP *g_irp_head = NULL;
struct stream *g_input_stream = NULL; struct stream *g_input_stream = NULL;
void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length); void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length);
@ -207,7 +255,7 @@ dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length,
break; break;
case PAKID_CORE_DEVICELIST_ANNOUNCE: case PAKID_CORE_DEVICELIST_ANNOUNCE:
dev_redir_proc_client_devlist_announce_req(ls); devredir_proc_client_devlist_announce_req(ls);
break; break;
case PAKID_CORE_DEVICE_IOCOMPLETION: case PAKID_CORE_DEVICE_IOCOMPLETION:
@ -347,7 +395,7 @@ void dev_redir_send_server_user_logged_on()
xstream_free(s); xstream_free(s);
} }
void dev_redir_send_server_device_announce_resp(tui32 device_id) void devredir_send_server_device_announce_resp(tui32 device_id)
{ {
struct stream *s; struct stream *s;
int bytes; int bytes;
@ -389,14 +437,14 @@ int dev_redir_send_drive_create_request(tui32 device_id, char *path,
xstream_new(s, 1024 + len); xstream_new(s, 1024 + len);
dev_redir_insert_dev_io_req_header(s, devredir_insert_DeviceIoRequest(s,
device_id, device_id,
0, 0,
completion_id, completion_id,
IRP_MJ_CREATE, IRP_MJ_CREATE,
0); 0);
xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */ xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */
xstream_wr_u32_le(s, 0); /* AllocationSize high unused */ xstream_wr_u32_le(s, 0); /* AllocationSize high unused */
xstream_wr_u32_le(s, 0); /* AllocationSize low unused */ xstream_wr_u32_le(s, 0); /* AllocationSize low unused */
xstream_wr_u32_le(s, 0); /* FileAttributes */ xstream_wr_u32_le(s, 0); /* FileAttributes */
@ -404,7 +452,7 @@ int dev_redir_send_drive_create_request(tui32 device_id, char *path,
xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */ xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */
xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */ xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */
xstream_wr_u32_le(s, len); /* PathLength */ xstream_wr_u32_le(s, len); /* PathLength */
devredir_cvt_to_unicode(s->p, path); /* path in unicode */ devredir_cvt_to_unicode(s->p, path); /* path in unicode */
xstream_seek(s, len); xstream_seek(s, len);
/* send to client */ /* send to client */
@ -432,8 +480,8 @@ int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
xstream_new(s, 1024); xstream_new(s, 1024);
dev_redir_insert_dev_io_req_header(s, DeviceId, FileId, CompletionId, devredir_insert_DeviceIoRequest(s, DeviceId, FileId, CompletionId,
MajorFunction, MinorFunc); MajorFunction, MinorFunc);
if (pad_len) if (pad_len)
xstream_seek(s, pad_len); xstream_seek(s, pad_len);
@ -476,12 +524,12 @@ void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
xstream_new(s, 1024 + path_len); xstream_new(s, 1024 + path_len);
irp->completion_type = CID_DIRECTORY_CONTROL; irp->completion_type = CID_DIRECTORY_CONTROL;
dev_redir_insert_dev_io_req_header(s, devredir_insert_DeviceIoRequest(s,
device_id, device_id,
irp->FileId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_DIRECTORY_CONTROL, IRP_MJ_DIRECTORY_CONTROL,
IRP_MN_QUERY_DIRECTORY); IRP_MN_QUERY_DIRECTORY);
#ifdef USE_SHORT_NAMES_IN_DIR_LISTING #ifdef USE_SHORT_NAMES_IN_DIR_LISTING
xstream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */ xstream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */
@ -574,13 +622,14 @@ void dev_redir_proc_client_core_cap_resp(struct stream *s)
} }
} }
void dev_redir_proc_client_devlist_announce_req(struct stream *s) void devredir_proc_client_devlist_announce_req(struct stream *s)
{ {
int i; int i;
int j; int j;
tui32 device_count; tui32 device_count;
tui32 device_type; tui32 device_type;
tui32 device_data_len; tui32 device_data_len;
char preferred_dos_name[9];
/* get number of devices being announced */ /* get number of devices being announced */
xstream_rd_u32_le(s, device_count); xstream_rd_u32_le(s, device_count);
@ -590,8 +639,7 @@ void dev_redir_proc_client_devlist_announce_req(struct stream *s)
for (i = 0; i < device_count; i++) for (i = 0; i < device_count; i++)
{ {
xstream_rd_u32_le(s, device_type); xstream_rd_u32_le(s, device_type);
xstream_rd_u32_le(s, g_device_id); /* LK_TODO need to support */ xstream_rd_u32_le(s, g_device_id);
/* multiple drives */
switch (device_type) switch (device_type)
{ {
@ -599,14 +647,11 @@ void dev_redir_proc_client_devlist_announce_req(struct stream *s)
/* get preferred DOS name */ /* get preferred DOS name */
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
g_preferred_dos_name_for_filesystem[j] = *s->p++; preferred_dos_name[j] = *s->p++;
} }
/* DOS names that are 8 chars long are not NULL terminated */ /* DOS names that are 8 chars long are not NULL terminated */
g_preferred_dos_name_for_filesystem[8] = 0; preferred_dos_name[8] = 0;
/* LK_TODO need to check for invalid chars in DOS name */
/* see section 2.2.1.3 of the protocol documentation */
/* get device data len */ /* get device data len */
xstream_rd_u32_le(s, device_data_len); xstream_rd_u32_le(s, device_data_len);
@ -618,22 +663,40 @@ void dev_redir_proc_client_devlist_announce_req(struct stream *s)
log_debug("device_type=FILE_SYSTEM device_id=0x%x dosname=%s " log_debug("device_type=FILE_SYSTEM device_id=0x%x dosname=%s "
"device_data_len=%d full_name=%s", g_device_id, "device_data_len=%d full_name=%s", g_device_id,
g_preferred_dos_name_for_filesystem, preferred_dos_name,
device_data_len, g_full_name_for_filesystem); device_data_len, g_full_name_for_filesystem);
dev_redir_send_server_device_announce_resp(g_device_id); devredir_send_server_device_announce_resp(g_device_id);
/* create share directory in xrdp file system; */ /* create share directory in xrdp file system; */
/* think of this as the mount point for this share */ /* think of this as the mount point for this share */
xfuse_create_share(g_device_id, xfuse_create_share(g_device_id, preferred_dos_name);
g_preferred_dos_name_for_filesystem); break;
case RDPDR_DTYP_SMARTCARD:
/* get preferred DOS name */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
/* DOS names that are 8 chars long are not NULL terminated */
preferred_dos_name[8] = 0;
/* for smart cards, device data len always 0 */
log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s "
"device_data_len=%d",
g_device_id, preferred_dos_name, device_data_len);
devredir_send_server_device_announce_resp(g_device_id);
scard_device_announce(g_device_id);
break; break;
/* we don't yet support these devices */ /* we don't yet support these devices */
case RDPDR_DTYP_SERIAL: case RDPDR_DTYP_SERIAL:
case RDPDR_DTYP_PARALLEL: case RDPDR_DTYP_PARALLEL:
case RDPDR_DTYP_PRINT: case RDPDR_DTYP_PRINT:
case RDPDR_DTYP_SMARTCARD:
log_debug("unsupported dev: 0x%x", device_type); log_debug("unsupported dev: 0x%x", device_type);
break; break;
} }
@ -658,12 +721,19 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId); log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId);
if ((irp = dev_redir_irp_find(CompletionId)) == NULL) if ((irp = devredir_irp_find(CompletionId)) == NULL)
{ {
log_error("IRP with completion ID %d not found", CompletionId); log_error("IRP with completion ID %d not found", CompletionId);
return; return;
} }
/* if callback has been set, call it */
if (irp->callback)
{
(*irp->callback)(s, irp, DeviceId, CompletionId, IoStatus);
goto done;
}
switch (irp->completion_type) switch (irp->completion_type)
{ {
case CID_CREATE_DIR_REQ: case CID_CREATE_DIR_REQ:
@ -679,7 +749,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
IoStatus); IoStatus);
free(fuse_data); free(fuse_data);
} }
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
return; return;
} }
@ -698,7 +768,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
xfuse_devredir_cb_open_file(fuse_data->data_ptr, xfuse_devredir_cb_open_file(fuse_data->data_ptr,
DeviceId, irp->FileId); DeviceId, irp->FileId);
if (irp->type == S_IFDIR) if (irp->type == S_IFDIR)
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
break; break;
case CID_READ: case CID_READ:
@ -718,15 +788,15 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
case CID_CLOSE: case CID_CLOSE:
log_debug("got CID_CLOSE"); log_debug("got CID_CLOSE");
log_debug("deleting irp with completion_id=%d comp_type=%d", log_debug("deleting irp with completion_id=%d comp_type=%d",
irp->completion_id, irp->completion_type); irp->CompletionId, irp->completion_type);
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
break; break;
case CID_FILE_CLOSE: case CID_FILE_CLOSE:
log_debug("got CID_FILE_CLOSE"); log_debug("got CID_FILE_CLOSE");
fuse_data = dev_redir_fuse_data_dequeue(irp); fuse_data = dev_redir_fuse_data_dequeue(irp);
xfuse_devredir_cb_file_close(fuse_data->data_ptr); xfuse_devredir_cb_file_close(fuse_data->data_ptr);
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
break; break;
case CID_DIRECTORY_CONTROL: case CID_DIRECTORY_CONTROL:
@ -767,6 +837,8 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
break; break;
} }
done:
if (fuse_data) if (fuse_data)
free(fuse_data); free(fuse_data);
@ -815,7 +887,7 @@ void dev_redir_proc_query_dir_response(IRP *irp,
PAKID_CORE_DEVICE_IOREQUEST, PAKID_CORE_DEVICE_IOREQUEST,
DeviceId, DeviceId,
irp->FileId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_CLOSE, 0, 32); IRP_MJ_CLOSE, 0, 32);
free(fuse_data); free(fuse_data);
return; return;
@ -908,15 +980,15 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path)
log_debug("fusep=%p", fusep); log_debug("fusep=%p", fusep);
if ((irp = dev_redir_irp_new()) == NULL) if ((irp = devredir_irp_new()) == NULL)
return -1; return -1;
/* cvt / to windows compatible \ */ /* cvt / to windows compatible \ */
devredir_cvt_slash(path); devredir_cvt_slash(path);
irp->completion_id = g_completion_id++; irp->CompletionId = g_completion_id++;
irp->completion_type = CID_CREATE_DIR_REQ; irp->completion_type = CID_CREATE_DIR_REQ;
irp->device_id = device_id; irp->DeviceId = device_id;
strcpy(irp->pathname, path); strcpy(irp->pathname, path);
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
@ -927,7 +999,7 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path)
rval = dev_redir_send_drive_create_request(device_id, path, rval = dev_redir_send_drive_create_request(device_id, path,
DesiredAccess, CreateOptions, DesiredAccess, CreateOptions,
CreateDisposition, CreateDisposition,
irp->completion_id); irp->CompletionId);
log_debug("looking for device_id=%d path=%s", device_id, path); log_debug("looking for device_id=%d path=%s", device_id, path);
@ -953,7 +1025,7 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
log_debug("device_id=%d path=%s mode=0x%x", device_id, path, mode); log_debug("device_id=%d path=%s mode=0x%x", device_id, path, mode);
if ((irp = dev_redir_irp_new()) == NULL) if ((irp = devredir_irp_new()) == NULL)
return -1; return -1;
if (type & OP_RENAME_FILE) if (type & OP_RENAME_FILE)
@ -966,8 +1038,8 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
irp->completion_type = CID_CREATE_OPEN_REQ; irp->completion_type = CID_CREATE_OPEN_REQ;
} }
irp->completion_id = g_completion_id++; irp->CompletionId = g_completion_id++;
irp->device_id = device_id; irp->DeviceId = device_id;
strcpy(irp->pathname, path); strcpy(irp->pathname, path);
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
@ -1009,7 +1081,7 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
rval = dev_redir_send_drive_create_request(device_id, path, rval = dev_redir_send_drive_create_request(device_id, path,
DesiredAccess, CreateOptions, DesiredAccess, CreateOptions,
CreateDisposition, CreateDisposition,
irp->completion_id); irp->CompletionId);
return rval; return rval;
} }
@ -1021,26 +1093,26 @@ int devredir_file_close(void *fusep, tui32 device_id, tui32 FileId)
log_debug("entered"); log_debug("entered");
#if 0 #if 0
if ((irp = dev_redir_irp_new()) == NULL) if ((irp = devredir_irp_new()) == NULL)
return -1; return -1;
irp->completion_id = g_completion_id++; irp->CompletionId = g_completion_id++;
#else #else
if ((irp = dev_redir_irp_find_by_fileid(FileId)) == NULL) if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
{ {
log_error("no IRP found with FileId = %d", FileId); log_error("no IRP found with FileId = %d", FileId);
return -1; return -1;
} }
#endif #endif
irp->completion_type = CID_FILE_CLOSE; irp->completion_type = CID_FILE_CLOSE;
irp->device_id = device_id; irp->DeviceId = device_id;
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
PAKID_CORE_DEVICE_IOREQUEST, PAKID_CORE_DEVICE_IOREQUEST,
device_id, device_id,
FileId, FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_CLOSE, IRP_MJ_CLOSE,
0, 32); 0, 32);
} }
@ -1057,12 +1129,12 @@ int devredir_rmdir_or_file(void *fusep, tui32 device_id, char *path, int mode)
int rval; int rval;
IRP *irp; IRP *irp;
if ((irp = dev_redir_irp_new()) == NULL) if ((irp = devredir_irp_new()) == NULL)
return -1; return -1;
irp->completion_id = g_completion_id++; irp->CompletionId = g_completion_id++;
irp->completion_type = CID_RMDIR_OR_FILE; irp->completion_type = CID_RMDIR_OR_FILE;
irp->device_id = device_id; irp->DeviceId = device_id;
strcpy(irp->pathname, path); strcpy(irp->pathname, path);
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
@ -1079,7 +1151,7 @@ int devredir_rmdir_or_file(void *fusep, tui32 device_id, char *path, int mode)
rval = dev_redir_send_drive_create_request(device_id, path, rval = dev_redir_send_drive_create_request(device_id, path,
DesiredAccess, CreateOptions, DesiredAccess, CreateOptions,
CreateDisposition, CreateDisposition,
irp->completion_id); irp->CompletionId);
return rval; return rval;
} }
@ -1099,7 +1171,7 @@ int dev_redir_file_read(void *fusep, tui32 DeviceId, tui32 FileId,
xstream_new(s, 1024); xstream_new(s, 1024);
if ((irp = dev_redir_irp_find_by_fileid(FileId)) == NULL) if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
{ {
log_error("no IRP found with FileId = %d", FileId); log_error("no IRP found with FileId = %d", FileId);
xfuse_devredir_cb_read_file(fusep, NULL, 0); xfuse_devredir_cb_read_file(fusep, NULL, 0);
@ -1108,12 +1180,12 @@ int dev_redir_file_read(void *fusep, tui32 DeviceId, tui32 FileId,
irp->completion_type = CID_READ; irp->completion_type = CID_READ;
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
dev_redir_insert_dev_io_req_header(s, devredir_insert_DeviceIoRequest(s,
DeviceId, DeviceId,
FileId, FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_READ, IRP_MJ_READ,
0); 0);
xstream_wr_u32_le(s, Length); xstream_wr_u32_le(s, Length);
xstream_wr_u64_le(s, Offset); xstream_wr_u64_le(s, Offset);
@ -1139,7 +1211,7 @@ int dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId,
xstream_new(s, 1024 + Length); xstream_new(s, 1024 + Length);
if ((irp = dev_redir_irp_find_by_fileid(FileId)) == NULL) if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
{ {
log_error("no IRP found with FileId = %d", FileId); log_error("no IRP found with FileId = %d", FileId);
xfuse_devredir_cb_write_file(fusep, NULL, 0); xfuse_devredir_cb_write_file(fusep, NULL, 0);
@ -1148,12 +1220,12 @@ int dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId,
irp->completion_type = CID_WRITE; irp->completion_type = CID_WRITE;
dev_redir_fuse_data_enqueue(irp, fusep); dev_redir_fuse_data_enqueue(irp, fusep);
dev_redir_insert_dev_io_req_header(s, devredir_insert_DeviceIoRequest(s,
DeviceId, DeviceId,
FileId, FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_WRITE, IRP_MJ_WRITE,
0); 0);
xstream_wr_u32_le(s, Length); xstream_wr_u32_le(s, Length);
xstream_wr_u64_le(s, Offset); xstream_wr_u64_le(s, Offset);
@ -1249,187 +1321,16 @@ int dev_redir_fuse_data_enqueue(IRP *irp, void *vp)
return 0; return 0;
} }
/******************************************************************************
** IRP stuff **
******************************************************************************/
/**
* Create a new IRP and append to linked list
*
* @return new IRP or NULL on error
*****************************************************************************/
IRP * dev_redir_irp_new()
{
IRP *irp;
IRP *irp_last;
log_debug("=== entered");
/* create new IRP */
if ((irp = calloc(1, sizeof(IRP))) == NULL)
{
log_error("system out of memory!");
return NULL;
}
/* insert at end of linked list */
if ((irp_last = dev_redir_irp_get_last()) == NULL)
{
/* list is empty, this is the first entry */
g_irp_head = irp;
}
else
{
irp_last->next = irp;
irp->prev = irp_last;
}
return irp;
}
/**
* Delete specified IRP from linked list
*
* @return 0 on success, -1 on failure
*****************************************************************************/
int dev_redir_irp_delete(IRP *irp)
{
IRP *lirp = g_irp_head;
log_debug("=== entered; completion_id=%d type=%d",
irp->completion_id, irp->completion_type);
if ((irp == NULL) || (lirp == NULL))
return -1;
dev_redir_irp_dump(); // LK_TODO
while (lirp)
{
if (lirp == irp)
break;
lirp = lirp->next;
}
if (lirp == NULL)
return -1; /* did not find specified irp */
if (lirp->prev == NULL)
{
/* we are at head of linked list */
if (lirp->next == NULL)
{
/* only one element in list */
free(lirp);
g_irp_head = NULL;
dev_redir_irp_dump(); // LK_TODO
return 0;
}
lirp->next->prev = NULL;
g_irp_head = lirp->next;
free(lirp);
}
else if (lirp->next == NULL)
{
/* we are at tail of linked list */
lirp->prev->next = NULL;
free(lirp);
}
else
{
/* we are in between */
lirp->prev->next = lirp->next;
lirp->next->prev = lirp->prev;
free(lirp);
}
dev_redir_irp_dump(); // LK_TODO
return 0;
}
/**
* Return IRP containing specified completion_id
*****************************************************************************/
IRP *dev_redir_irp_find(tui32 completion_id)
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->completion_id == completion_id)
return irp;
irp = irp->next;
}
return NULL;
}
IRP * dev_redir_irp_find_by_fileid(tui32 FileId)
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->FileId == FileId)
return irp;
irp = irp->next;
}
return NULL;
}
/**
* Return last IRP in linked list
*****************************************************************************/
IRP * dev_redir_irp_get_last()
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->next == NULL)
break;
irp = irp->next;
}
return irp;
}
void dev_redir_irp_dump()
{
IRP *irp = g_irp_head;
log_debug("------- dumping IRPs --------");
while (irp)
{
log_debug(" completion_id=%d\tcompletion_type=%d\tFileId=%d",
irp->completion_id, irp->completion_type, irp->FileId);
irp = irp->next;
}
log_debug("------- dumping IRPs done ---");
}
/****************************************************************************** /******************************************************************************
** miscellaneous stuff ** ** miscellaneous stuff **
******************************************************************************/ ******************************************************************************/
void dev_redir_insert_dev_io_req_header(struct stream *s, void devredir_insert_DeviceIoRequest(struct stream *s,
tui32 DeviceId, tui32 DeviceId,
tui32 FileId, tui32 FileId,
tui32 CompletionId, tui32 CompletionId,
tui32 MajorFunction, tui32 MajorFunction,
tui32 MinorFunction) tui32 MinorFunction)
{ {
/* setup DR_DEVICE_IOREQUEST header */ /* setup DR_DEVICE_IOREQUEST header */
xstream_wr_u16_le(s, RDPDR_CTYP_CORE); xstream_wr_u16_le(s, RDPDR_CTYP_CORE);
@ -1492,7 +1393,7 @@ int dev_redir_string_ends_with(char *string, char c)
return (string[len - 1] == c) ? 1 : 0; return (string[len - 1] == c) ? 1 : 0;
} }
void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component, void devredir_insert_RDPDR_header(struct stream *s, tui16 Component,
tui16 PacketId) tui16 PacketId)
{ {
xstream_wr_u16_le(s, Component); xstream_wr_u16_le(s, Component);
@ -1512,16 +1413,16 @@ void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus)
xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus);
free(fuse_data); free(fuse_data);
} }
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
return; return;
} }
xstream_new(s, 1024); xstream_new(s, 1024);
irp->completion_type = CID_RMDIR_OR_FILE_RESP; irp->completion_type = CID_RMDIR_OR_FILE_RESP;
dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId, devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_SET_INFORMATION, 0); IRP_MJ_SET_INFORMATION, 0);
xstream_wr_u32_le(s, FileDispositionInformation); xstream_wr_u32_le(s, FileDispositionInformation);
xstream_wr_u32_le(s, 0); /* length is zero */ xstream_wr_u32_le(s, 0); /* length is zero */
@ -1548,16 +1449,16 @@ void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus)
if (IoStatus != NT_STATUS_SUCCESS) if (IoStatus != NT_STATUS_SUCCESS)
{ {
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
return; return;
} }
irp->completion_type = CID_CLOSE; irp->completion_type = CID_CLOSE;
dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
PAKID_CORE_DEVICE_IOREQUEST, PAKID_CORE_DEVICE_IOREQUEST,
irp->device_id, irp->DeviceId,
irp->FileId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_CLOSE, 0, 32); IRP_MJ_CLOSE, 0, 32);
} }
@ -1579,16 +1480,16 @@ void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus)
xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus);
free(fuse_data); free(fuse_data);
} }
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
return; return;
} }
xstream_new(s, 1024); xstream_new(s, 1024);
irp->completion_type = CID_RENAME_FILE_RESP; irp->completion_type = CID_RENAME_FILE_RESP;
dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId, devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_SET_INFORMATION, 0); IRP_MJ_SET_INFORMATION, 0);
flen = strlen(irp->gen_buf) * 2 + 2; flen = strlen(irp->gen_buf) * 2 + 2;
sblen = 6 + flen; sblen = 6 + flen;
@ -1627,15 +1528,15 @@ void devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus)
if (IoStatus != NT_STATUS_SUCCESS) if (IoStatus != NT_STATUS_SUCCESS)
{ {
dev_redir_irp_delete(irp); devredir_irp_delete(irp);
return; return;
} }
irp->completion_type = CID_CLOSE; irp->completion_type = CID_CLOSE;
dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
PAKID_CORE_DEVICE_IOREQUEST, PAKID_CORE_DEVICE_IOREQUEST,
irp->device_id, irp->DeviceId,
irp->FileId, irp->FileId,
irp->completion_id, irp->CompletionId,
IRP_MJ_CLOSE, 0, 32); IRP_MJ_CLOSE, 0, 32);
} }

@ -23,59 +23,14 @@
#if !defined(DEVREDIR_H) #if !defined(DEVREDIR_H)
#define DEVREDIR_H #define DEVREDIR_H
#include <stdio.h> #include "irp.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "arch.h"
#include "parse.h"
#include "os_calls.h"
#include "log.h"
#include "chansrv_fuse.h"
#define USE_SHORT_NAMES_IN_DIR_LISTING #define USE_SHORT_NAMES_IN_DIR_LISTING
typedef struct fuse_data FUSE_DATA;
struct fuse_data
{
void *data_ptr;
FUSE_DATA *next;
};
/* An I/O Resource Packet to track dev_dir I/O calls */
typedef struct irp IRP;
struct irp
{
tui32 completion_id; /* unique number */
char completion_type; /* describes I/O type */
tui32 FileId; /* RDP client provided unique number */
char pathname[256]; /* absolute pathname */
char gen_buf[1024]; /* for general use */
int type;
tui32 device_id; /* identifies remote device */
FUSE_DATA *fd_head; /* point to first FUSE opaque object */
FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
IRP *next; /* point to next IRP */
IRP *prev; /* point to previous IRP */
};
void *dev_redir_fuse_data_peek(IRP *irp); void *dev_redir_fuse_data_peek(IRP *irp);
void *dev_redir_fuse_data_dequeue(IRP *irp); void *dev_redir_fuse_data_dequeue(IRP *irp);
int dev_redir_fuse_data_enqueue(IRP *irp, void *vp); int dev_redir_fuse_data_enqueue(IRP *irp, void *vp);
IRP * dev_redir_irp_new();
IRP * dev_redir_irp_find(tui32 completion_id);
IRP * dev_redir_irp_find_by_fileid(tui32 FileId);
IRP * dev_redir_irp_get_last();
int dev_redir_irp_delete(IRP *irp);
void dev_redir_irp_dump();
int APP_CC dev_redir_init(void); int APP_CC dev_redir_init(void);
int APP_CC dev_redir_deinit(void); int APP_CC dev_redir_deinit(void);
@ -88,7 +43,7 @@ int APP_CC dev_redir_check_wait_objs(void);
void dev_redir_send_server_core_cap_req(); void dev_redir_send_server_core_cap_req();
void dev_redir_send_server_clientID_confirm(); void dev_redir_send_server_clientID_confirm();
void dev_redir_send_server_user_logged_on(); void dev_redir_send_server_user_logged_on();
void dev_redir_send_server_device_announce_resp(tui32 device_id); void devredir_send_server_device_announce_resp(tui32 device_id);
void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
tui32 InitialQuery, char *Path); tui32 InitialQuery, char *Path);
@ -107,7 +62,7 @@ int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
tui32 MinorFunc, tui32 MinorFunc,
int pad_len); int pad_len);
void dev_redir_proc_client_devlist_announce_req(struct stream *s); void devredir_proc_client_devlist_announce_req(struct stream *s);
void dev_redir_proc_client_core_cap_resp(struct stream *s); void dev_redir_proc_client_core_cap_resp(struct stream *s);
void dev_redir_proc_device_iocompletion(struct stream *s); void dev_redir_proc_device_iocompletion(struct stream *s);
@ -118,20 +73,20 @@ void dev_redir_proc_query_dir_response(IRP *irp,
tui32 IoStatus); tui32 IoStatus);
/* misc stuff */ /* misc stuff */
void dev_redir_insert_dev_io_req_header(struct stream *s, void devredir_insert_DeviceIoRequest(struct stream *s,
tui32 DeviceId, tui32 DeviceId,
tui32 FileId, tui32 FileId,
tui32 CompletionId, tui32 CompletionId,
tui32 MajorFunction, tui32 MajorFunction,
tui32 MinorFunction); tui32 MinorFunction);
void devredir_cvt_slash(char *path); void devredir_cvt_slash(char *path);
void devredir_cvt_to_unicode(char *unicode, char *path); void devredir_cvt_to_unicode(char *unicode, char *path);
void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); void devredir_cvt_from_unicode_len(char *path, char *unicode, int len);
int dev_redir_string_ends_with(char *string, char c); int dev_redir_string_ends_with(char *string, char c);
void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component, void devredir_insert_RDPDR_header(struct stream *s, tui16 Component,
tui16 PacketId); tui16 PacketId);
void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus); void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus);
void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus); void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus);
@ -149,42 +104,6 @@ int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id);
int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId, int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset); tui32 Length, tui64 Offset);
/* module based logging */
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_ERROR
#endif
#define log_error(_params...) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ERROR: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
int send_channel_data(int chan_id, char *data, int size); int send_channel_data(int chan_id, char *data, int size);
/* /*

@ -0,0 +1,231 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@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.
*
*/
/*
* manage I/O for redirected file system and devices
*/
#include "parse.h"
#include "os_calls.h"
#include "irp.h"
/* module based logging */
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_DEBUG
#endif
#define log_error(_params...) \
{ \
g_write("[%10.10u]: IRP %s: %d : ERROR: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: IRP %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: IRP %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
IRP *g_irp_head = NULL;
/**
* Create a new IRP and append to linked list
*
* @return new IRP or NULL on error
*****************************************************************************/
IRP * devredir_irp_new()
{
IRP *irp;
IRP *irp_last;
log_debug("entered");
/* create new IRP */
if ((irp = g_malloc(sizeof(IRP), 1)) == NULL)
{
log_error("system out of memory!");
return NULL;
}
/* insert at end of linked list */
if ((irp_last = devredir_irp_get_last()) == NULL)
{
/* list is empty, this is the first entry */
g_irp_head = irp;
}
else
{
irp_last->next = irp;
irp->prev = irp_last;
}
return irp;
}
/**
* Delete specified IRP from linked list
*
* @return 0 on success, -1 on failure
*****************************************************************************/
int devredir_irp_delete(IRP *irp)
{
IRP *lirp = g_irp_head;
log_debug("=== entered; completion_id=%d type=%d",
irp->CompletionId, irp->completion_type);
if ((irp == NULL) || (lirp == NULL))
return -1;
devredir_irp_dump(); // LK_TODO
while (lirp)
{
if (lirp == irp)
break;
lirp = lirp->next;
}
if (lirp == NULL)
return -1; /* did not find specified irp */
if (lirp->prev == NULL)
{
/* we are at head of linked list */
if (lirp->next == NULL)
{
/* only one element in list */
g_free(lirp);
g_irp_head = NULL;
devredir_irp_dump(); // LK_TODO
return 0;
}
lirp->next->prev = NULL;
g_irp_head = lirp->next;
g_free(lirp);
}
else if (lirp->next == NULL)
{
/* we are at tail of linked list */
lirp->prev->next = NULL;
g_free(lirp);
}
else
{
/* we are in between */
lirp->prev->next = lirp->next;
lirp->next->prev = lirp->prev;
g_free(lirp);
}
devredir_irp_dump(); // LK_TODO
return 0;
}
/**
* Return IRP containing specified completion_id
*****************************************************************************/
IRP *devredir_irp_find(tui32 completion_id)
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->CompletionId == completion_id)
return irp;
irp = irp->next;
}
return NULL;
}
IRP * devredir_irp_find_by_fileid(tui32 FileId)
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->FileId == FileId)
return irp;
irp = irp->next;
}
return NULL;
}
/**
* Return last IRP in linked list
*****************************************************************************/
IRP * devredir_irp_get_last()
{
IRP *irp = g_irp_head;
while (irp)
{
if (irp->next == NULL)
break;
irp = irp->next;
}
return irp;
}
void devredir_irp_dump()
{
IRP *irp = g_irp_head;
log_debug("------- dumping IRPs --------");
while (irp)
{
log_debug(" completion_id=%d\tcompletion_type=%d\tFileId=%d",
irp->CompletionId, irp->completion_type, irp->FileId);
irp = irp->next;
}
log_debug("------- dumping IRPs done ---");
}

@ -0,0 +1,64 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@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.
*
*/
/*
* manage I/O for redirected file system and devices
*/
#ifndef __IRP_H
#define __IRP_H
typedef struct fuse_data FUSE_DATA;
struct fuse_data
{
void *data_ptr;
FUSE_DATA *next;
};
/* An I/O Resource Packet to track I/O calls */
typedef struct irp IRP;
struct irp
{
tui32 CompletionId; /* unique number */
tui32 DeviceId; /* identifies remote device */
tui32 FileId; /* RDP client provided unique number */
char completion_type; /* describes I/O type */
char pathname[256]; /* absolute pathname */
char gen_buf[1024]; /* for general use */
int type;
FUSE_DATA *fd_head; /* point to first FUSE opaque object */
FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
IRP *next; /* point to next IRP */
IRP *prev; /* point to previous IRP */
int scard_index; /* used to smart card to locate dev */
void (*callback)(struct stream *s, IRP *irp, tui32 DeviceId,
tui32 CompletionId, tui32 IoStatus);
};
IRP * devredir_irp_new();
int devredir_irp_delete(IRP *irp);
IRP * devredir_irp_find(tui32 completion_id);
IRP * devredir_irp_find_by_fileid(tui32 FileId);
IRP * devredir_irp_get_last();
void devredir_irp_dump();
#endif /* end ifndef __IRP_H */

@ -0,0 +1,528 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@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
*/
#include "os_calls.h"
#include "smartcard.h"
#include "log.h"
#include "irp.h"
#include "devredir.h"
/*
* TODO
*
* o need to query client for build number and determine whether we should use
* SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN
*
* o need to call scard_release_resources()
*
* o why is win 7 sending SCARD_IOCTL_ACCESS_STARTED_EVENT first
* 0000 00 01 00 00 04 00 00 00 e0 00 09 00 00 00 00 00 ................
* 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
* 0020 28 b7 9d 02
*/
/*
* Notes:
*
* XP and Server 2003 use version SCREDIR_VERSION_XP functions 5 - 58
* Vista and Server 2008 use version SCREDIR_VERSION_LONGHORN functions 5 - 64
* if TS Client's build number is >= 4,034 use SCREDIR_VERSION_LONGHORN
*/
/* module based logging */
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
#define LOG_LEVEL LOG_DEBUG
#endif
#define log_error(_params...) \
{ \
g_write("[%10.10u]: SMART_CARD %s: %d : ERROR: ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
}
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: SMART_CARD %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: SMART_CARD %s: %d : ", \
g_time3(), __func__, __LINE__); \
g_writeln (_params); \
} \
}
/* [MS-RDPESC] 3.1.4 */
#define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */
#define SCARD_IOCTL_RELEASE_CONTEXT 0x00090018 /* ReleaseContext */
#define SCARD_IOCTL_IS_VALID_CONTEXT 0x0009001C /* IsValidContext */
#define SCARD_IOCTL_LIST_READER_GROUPS 0x00090020 /* ListReaderGroups */
#define SCARD_IOCTL_LIST_READERS_A 0x00090028 /* ListReaders ASCII */
#define SCARD_IOCTL_LIST_READERS_W 0x0009002C /* ListReaders Wide */
#define SCARD_IOCTL_INTRODUCE_READER_GROUP 0x00090050 /* IntroduceReaderGroup */
#define SCARD_IOCTL_FORGET_READER_GROUP 0x00090058 /* ForgetReader */
#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_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */
#define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */
#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */
#define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */
#define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */
#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_TRANSMIT 0x000900D0 /* Transmit */
#define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */
#define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */
#define SCARD_IOCTL_SETATTRIB 0x000900DC /* SetAttrib */
#define SCARD_IOCTL_ACCESS_STARTED_EVENT 0x000900E0 /* SCardAccessStartedEvent */
#define SCARD_IOCTL_LOCATE_CARDS_BY_ATR 0x000900E8 /* LocateCardsByATR */
/* scope used in EstablishContextCall */
#define SCARD_SCOPE_USER 0x00000000
#define SCARD_SCOPE_TERMINAL 0x00000001
#define SCARD_SCOPE_SYSTEM 0x00000002
#define MAX_SMARTCARDS 16
/* stores info about a smart card */
typedef struct smartcard
{
tui32 DeviceId;
char Context[16]; /* opaque context; save as passed to us */
int Context_len; /* Context len in bytes */
} SMARTCARD;
SMARTCARD *smartcards[MAX_SMARTCARDS];
int g_smartcards_inited = 0;
extern tui32 g_completion_id;
extern int g_rdpdr_chan_id; /* in chansrv.c */
/* forward declarations specific to this file */
static void scard_send_EstablishContext(IRP *irp);
static void scard_send_ListReaders(IRP *irp, int wide);
static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl);
static int scard_add_new_device(tui32 device_id);
static int scard_get_free_slot();
static void scard_release_resources();
/******************************************************************************
** non static functions **
******************************************************************************/
void scard_device_announce(tui32 device_id)
{
IRP *irp;
log_debug("entered: device_id=%d", device_id);
if (!g_smartcards_inited)
{
g_memset(&smartcards, 0, sizeof(smartcards));
g_smartcards_inited = 1;
}
if ((irp = devredir_irp_new()) == NULL)
{
log_error("system out of memory");
return;
}
irp->scard_index = scard_add_new_device(device_id);
if (irp->scard_index < 0)
{
log_debug("NOT adding smartcard with DeviceId=%d to list", device_id);
devredir_irp_delete(irp);
return;
}
log_debug("added smartcard with DeviceId=%d to list", device_id);
irp->CompletionId = g_completion_id++;
irp->DeviceId = device_id;
irp->callback = scard_handle_EstablishContext_Return;
scard_send_EstablishContext(irp);
log_debug("leaving");
}
/******************************************************************************
** callbacks into this module **
******************************************************************************/
void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp,
tui32 DeviceId, tui32 CompletionId,
tui32 IoStatus)
{
tui32 len;
int tmp;
SMARTCARD *sc;
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 establish context - device not usable");
/* LK_TODO delete irp and smartcard entry */
return;
}
sc = smartcards[irp->scard_index];
/* get OutputBufferLen */
xstream_rd_u32_le(s, len);
/* LK_TODO */
g_hexdump(s->p, len);
xstream_rd_u32_le(s, tmp); /* should be len 8, LE, V1 */
xstream_rd_u32_le(s, tmp); /* marshalling flag */
xstream_rd_u32_le(s, tmp); /* ?? */
xstream_rd_u32_le(s, tmp); /* ?? */
xstream_rd_u32_le(s, tmp); /* ?? */
xstream_rd_u32_le(s, tmp); /* ?? */
xstream_rd_u32_le(s, tmp); /* ?? */
xstream_rd_u32_le(s, len); /* len of context in bytes */
sc->Context_len = len;
xstream_copyout(sc->Context, s, len);
if (LOG_LEVEL == LOG_DEBUG)
{
log_debug("dumping context (%d bytes)", sc->Context_len);
g_hexdump(sc->Context, sc->Context_len);
}
irp->callback = scard_handle_ListReaders_Return;
scard_send_ListReaders(irp, 1);
/* LK_TODO need to delete IRP */
log_debug("leaving");
}
void scard_handle_ListReaders_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 list readers - device not usable");
/* LK_TODO delete irp and smartcard entry */
return;
}
/* get OutputBufferLen */
xstream_rd_u32_le(s, len);
/* LK_TODO */
log_debug("dumping %d bytes", len);
g_hexdump(s->p, len);
log_debug("leaving");
}
/******************************************************************************
** static functions local to this file **
******************************************************************************/
/**
*
*****************************************************************************/
static void scard_send_EstablishContext(IRP *irp)
{
struct stream *s;
int bytes;
if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_ESTABLISH_CONTEXT)) == NULL)
return;
xstream_wr_u32_le(s, 0x08); /* len */
xstream_wr_u32_le(s, 0); /* unused */
xstream_wr_u32_le(s, SCARD_SCOPE_SYSTEM); /* Ioctl specific data */
xstream_wr_u32_le(s, 0); /* don't know what this is, */
/* but Win7 is sending it */
/* 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);
}
/**
*
*****************************************************************************/
static void scard_send_ListReaders(IRP *irp, int wide)
{
/* see [MS-RDPESC] 2.2.2.4 */
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 > 0) ? SCARD_IOCTL_LIST_READERS_W :
SCARD_IOCTL_LIST_READERS_A;
if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL)
return;
xstream_wr_u32_le(s, 72); /* number of bytes to follow */
xstream_seek(s, 0x1c); /* freerdp does not use this */
/* insert context */
xstream_wr_u32_le(s, sc->Context_len);
xstream_copyin(s, sc->Context, sc->Context_len);
xstream_wr_u32_le(s, 36); /* length of mszGroups */
xstream_wr_u16_le(s, 0x0053);
xstream_wr_u16_le(s, 0x0043);
xstream_wr_u16_le(s, 0x0061);
xstream_wr_u16_le(s, 0x0072);
xstream_wr_u16_le(s, 0x0064);
xstream_wr_u16_le(s, 0x0024);
xstream_wr_u16_le(s, 0x0041);
xstream_wr_u16_le(s, 0x006c);
xstream_wr_u16_le(s, 0x006c);
xstream_wr_u16_le(s, 0x0052);
xstream_wr_u16_le(s, 0x0065);
xstream_wr_u16_le(s, 0x0061);
xstream_wr_u16_le(s, 0x0064);
xstream_wr_u16_le(s, 0x0065);
xstream_wr_u16_le(s, 0x0072);
xstream_wr_u16_le(s, 0x0073);
xstream_wr_u32_le(s, 0x00);
/* 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);
/*
scard_device_control: dumping 120 bytes of data
0000 00 08 00 00 58 00 00 00 2c 00 09 00 00 00 00 00 ....X...,.......
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H.......
0030 04 00 00 00 00 00 02 00 24 00 00 00 04 00 02 00 ........$.......
0040 00 00 00 00 ff ff ff ff 04 00 00 00 84 db 03 01 ................
0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$.
0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e.
0070 72 00 73 00 00 00 00 00 r.s.....
scard_device_control: output_len=2048 input_len=88 ioctl_code=0x9002c
*/
/*
scard_device_control: dumping 120 bytes of data
0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................
0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H.......
0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd......
0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'..............
0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$.
0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e.
0070 72 00 73 00 00 00 00 00 r.s.....
scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014
*/
}
/**
* Crate a new stream and insert specified IOCTL
*
* @param irp information about the I/O
* @param ioctl the IOCTL code
*
* @return stream with IOCTL inserted in it, NULL on error
*****************************************************************************/
static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl)
{
/*
* format of device control request
*
* DeviceIoRequest
* u16 RDPDR_CTYP_CORE
* u16 PAKID_CORE_DEVICE_IOREQUEST
* u32 DeviceId
* u32 FileId
* u32 CompletionId
* u32 MajorFunction
* u32 MinorFunction
*
* u32 OutputBufferLength SHOULD be 2048
* u32 InputBufferLength
* u32 IoControlCode
* 20 bytes padding
* xx bytes InputBuffer (variable)
*/
struct stream *s;
xstream_new(s, 1024 * 3);
if (s == NULL)
{
log_error("system out of memory");
return s;
}
devredir_insert_DeviceIoRequest(s,
irp->DeviceId,
irp->FileId,
irp->CompletionId,
IRP_MJ_DEVICE_CONTROL,
0);
xstream_wr_u32_le(s, 2048); /* OutputBufferLength */
xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */
xstream_wr_u32_le(s, ioctl); /* Ioctl Code */
xstream_seek(s, 20); /* padding */
/* [MS-RPCE] 2.2.6.1 */
xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */
xstream_wr_u32_le(s, 0xcccccccc); /* filler */
return s;
}
/**
* Create a new smart card device entry and insert it into smartcards[]
*
* @param device_id DeviceId of new card
*
* @return index into smartcards[] on success, -1 on failure
*****************************************************************************/
static int scard_add_new_device(tui32 device_id)
{
int index;
SMARTCARD *sc;
if ((index = scard_get_free_slot()) < 0)
return -1;
if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL)
{
log_error("system out of memory");
return -1;
}
sc->DeviceId = device_id;
smartcards[index] = sc;
return index;
}
/**
* Find first unused entry in smartcards
*
* @return index of first unused entry in smartcards or -1 if smartcards is full
*****************************************************************************/
static int scard_get_free_slot()
{
int i;
for (i = 0; i < MAX_SMARTCARDS; i++)
{
if (smartcards[i] == NULL)
{
log_debug("found free slot at index %d", i);
return i;
}
}
log_error("too many smart card devices; rejecting this one");
return -1;
}
/**
* Release resources prior to shutting down
*****************************************************************************/
static void scard_release_resources()
{
int i;
for (i = 0; i < MAX_SMARTCARDS; i++)
{
if (smartcards[i] != NULL)
{
g_free(smartcards[i]);
smartcards[i] = NULL;
}
}
}
/**
*
*****************************************************************************/

@ -0,0 +1,42 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@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
*/
#ifndef _SMARTCARD_C
#define _SMARTCARD_C
#include "parse.h"
#include "irp.h"
/* forward declarations */
void scard_device_announce(tui32 device_id);
/* callbacks into this module */
void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp,
tui32 DeviceId, tui32 CompletionId,
tui32 IoStatus);
void scard_handle_ListReaders_Return(struct stream *s, IRP *irp,
tui32 DeviceId, tui32 CompletionId,
tui32 IoStatus);
#endif /* end #ifndef _SMARTCARD_C */
Loading…
Cancel
Save