From 89b7cd269e7313fb06ea53d388272cbc57a3b3e0 Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Wed, 15 May 2013 17:06:05 -0700 Subject: [PATCH] smartcard: developer checkin for smartcard support --- common/parse.h | 10 +- sesman/chansrv/Makefile.am | 4 +- sesman/chansrv/chansrv_fuse.c | 2 +- sesman/chansrv/devredir.c | 427 +++++++++++---------------- sesman/chansrv/devredir.h | 103 +------ sesman/chansrv/irp.c | 231 +++++++++++++++ sesman/chansrv/irp.h | 64 +++++ sesman/chansrv/smartcard.c | 528 ++++++++++++++++++++++++++++++++++ sesman/chansrv/smartcard.h | 42 +++ 9 files changed, 1049 insertions(+), 362 deletions(-) create mode 100644 sesman/chansrv/irp.c create mode 100644 sesman/chansrv/irp.h create mode 100644 sesman/chansrv/smartcard.c create mode 100644 sesman/chansrv/smartcard.h diff --git a/common/parse.h b/common/parse.h index ddaa87a6..49c2fa23 100644 --- a/common/parse.h +++ b/common/parse.h @@ -368,18 +368,18 @@ do \ } while (0) /* copy data into stream */ -#define xstream_copyin(_s, _dest, _len) \ +#define xstream_copyin(_s, _dest, _len) \ do \ { \ - g_memcpy((_s)->p, (_dest), (_len)); \ + g_memcpy((_s)->p, (_dest), (_len)); \ (_s)->p += (_len); \ } while (0) /* copy data out of stream */ -#define xstream_copyout(_dest, _s, _len) \ -{ \ +#define xstream_copyout(_dest, _s, _len) \ do \ - g_memcpy((_dest), (_s)->p, (_len)); \ +{ \ + g_memcpy((_dest), (_s)->p, (_len)); \ (_s)->p += (_len); \ } while (0) diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 4272eb0e..d200509a 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -35,10 +35,12 @@ xrdp_chansrv_SOURCES = \ clipboard.c \ clipboard_file.c \ devredir.c \ + smartcard.c \ rail.c \ xcommon.c \ drdynvc.c \ - chansrv_fuse.c + chansrv_fuse.c \ + irp.c xrdp_chansrv_LDFLAGS = \ $(EXTRA_FLAGS) diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 0d762d6a..4f461bcf 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -116,7 +116,7 @@ void xfuse_devredir_cb_file_close(void *vp) {} #define LOG_ERROR 0 #define LOG_INFO 1 #define LOG_DEBUG 2 -#define LOG_LEVEL LOG_ERROR +#define LOG_LEVEL LOG_DEBUG #define log_error(_params...) \ { \ diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 0d4932bd..f14c17dc 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -34,7 +34,57 @@ * o mark local funcs with static */ +#include +#include +#include +#include +#include +#include +#include + +#include "arch.h" +#include "parse.h" +#include "os_calls.h" +#include "log.h" +#include "chansrv_fuse.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 */ 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_smartcard_redir_supported = 0; int g_drive_redir_version = 1; -char g_preferred_dos_name_for_filesystem[9]; char g_full_name_for_filesystem[1024]; tui32 g_completion_id = 1; tui32 g_clientID; /* unique client ID - announced by client */ tui32 g_device_id; /* unique device ID - announced by client */ tui16 g_client_rdp_version; /* returned by client */ -IRP *g_irp_head = NULL; struct stream *g_input_stream = NULL; 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; case PAKID_CORE_DEVICELIST_ANNOUNCE: - dev_redir_proc_client_devlist_announce_req(ls); + devredir_proc_client_devlist_announce_req(ls); break; case PAKID_CORE_DEVICE_IOCOMPLETION: @@ -347,7 +395,7 @@ void dev_redir_send_server_user_logged_on() 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; int bytes; @@ -389,14 +437,14 @@ int dev_redir_send_drive_create_request(tui32 device_id, char *path, xstream_new(s, 1024 + len); - dev_redir_insert_dev_io_req_header(s, - device_id, - 0, - completion_id, - IRP_MJ_CREATE, - 0); + devredir_insert_DeviceIoRequest(s, + device_id, + 0, + completion_id, + IRP_MJ_CREATE, + 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 low unused */ 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, CreateOptions); /* CreateOptions */ 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); /* send to client */ @@ -432,8 +480,8 @@ int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, xstream_new(s, 1024); - dev_redir_insert_dev_io_req_header(s, DeviceId, FileId, CompletionId, - MajorFunction, MinorFunc); + devredir_insert_DeviceIoRequest(s, DeviceId, FileId, CompletionId, + MajorFunction, MinorFunc); if (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); irp->completion_type = CID_DIRECTORY_CONTROL; - dev_redir_insert_dev_io_req_header(s, - device_id, - irp->FileId, - irp->completion_id, - IRP_MJ_DIRECTORY_CONTROL, - IRP_MN_QUERY_DIRECTORY); + devredir_insert_DeviceIoRequest(s, + device_id, + irp->FileId, + irp->CompletionId, + IRP_MJ_DIRECTORY_CONTROL, + IRP_MN_QUERY_DIRECTORY); #ifdef USE_SHORT_NAMES_IN_DIR_LISTING 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 j; tui32 device_count; tui32 device_type; tui32 device_data_len; + char preferred_dos_name[9]; /* get number of devices being announced */ 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++) { xstream_rd_u32_le(s, device_type); - xstream_rd_u32_le(s, g_device_id); /* LK_TODO need to support */ - /* multiple drives */ + xstream_rd_u32_le(s, g_device_id); switch (device_type) { @@ -599,14 +647,11 @@ void dev_redir_proc_client_devlist_announce_req(struct stream *s) /* get preferred DOS name */ 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 */ - g_preferred_dos_name_for_filesystem[8] = 0; - - /* LK_TODO need to check for invalid chars in DOS name */ - /* see section 2.2.1.3 of the protocol documentation */ + preferred_dos_name[8] = 0; /* get 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 " "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); - 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; */ /* think of this as the mount point for this share */ - xfuse_create_share(g_device_id, - g_preferred_dos_name_for_filesystem); + xfuse_create_share(g_device_id, preferred_dos_name); + 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; /* we don't yet support these devices */ case RDPDR_DTYP_SERIAL: case RDPDR_DTYP_PARALLEL: case RDPDR_DTYP_PRINT: - case RDPDR_DTYP_SMARTCARD: log_debug("unsupported dev: 0x%x", device_type); break; } @@ -658,12 +721,19 @@ void dev_redir_proc_device_iocompletion(struct stream *s) 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); return; } + /* if callback has been set, call it */ + if (irp->callback) + { + (*irp->callback)(s, irp, DeviceId, CompletionId, IoStatus); + goto done; + } + switch (irp->completion_type) { case CID_CREATE_DIR_REQ: @@ -679,7 +749,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s) IoStatus); free(fuse_data); } - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); return; } @@ -698,7 +768,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s) xfuse_devredir_cb_open_file(fuse_data->data_ptr, DeviceId, irp->FileId); if (irp->type == S_IFDIR) - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); break; case CID_READ: @@ -718,15 +788,15 @@ void dev_redir_proc_device_iocompletion(struct stream *s) case CID_CLOSE: log_debug("got CID_CLOSE"); log_debug("deleting irp with completion_id=%d comp_type=%d", - irp->completion_id, irp->completion_type); - dev_redir_irp_delete(irp); + irp->CompletionId, irp->completion_type); + devredir_irp_delete(irp); break; case CID_FILE_CLOSE: log_debug("got CID_FILE_CLOSE"); fuse_data = dev_redir_fuse_data_dequeue(irp); xfuse_devredir_cb_file_close(fuse_data->data_ptr); - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); break; case CID_DIRECTORY_CONTROL: @@ -767,6 +837,8 @@ void dev_redir_proc_device_iocompletion(struct stream *s) break; } +done: + if (fuse_data) free(fuse_data); @@ -815,7 +887,7 @@ void dev_redir_proc_query_dir_response(IRP *irp, PAKID_CORE_DEVICE_IOREQUEST, DeviceId, irp->FileId, - irp->completion_id, + irp->CompletionId, IRP_MJ_CLOSE, 0, 32); free(fuse_data); return; @@ -908,15 +980,15 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path) log_debug("fusep=%p", fusep); - if ((irp = dev_redir_irp_new()) == NULL) + if ((irp = devredir_irp_new()) == NULL) return -1; /* cvt / to windows compatible \ */ devredir_cvt_slash(path); - irp->completion_id = g_completion_id++; + irp->CompletionId = g_completion_id++; irp->completion_type = CID_CREATE_DIR_REQ; - irp->device_id = device_id; + irp->DeviceId = device_id; strcpy(irp->pathname, path); 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, DesiredAccess, CreateOptions, CreateDisposition, - irp->completion_id); + irp->CompletionId); 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); - if ((irp = dev_redir_irp_new()) == NULL) + if ((irp = devredir_irp_new()) == NULL) return -1; 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_id = g_completion_id++; - irp->device_id = device_id; + irp->CompletionId = g_completion_id++; + irp->DeviceId = device_id; strcpy(irp->pathname, path); 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, DesiredAccess, CreateOptions, CreateDisposition, - irp->completion_id); + irp->CompletionId); return rval; } @@ -1021,26 +1093,26 @@ int devredir_file_close(void *fusep, tui32 device_id, tui32 FileId) log_debug("entered"); #if 0 - if ((irp = dev_redir_irp_new()) == NULL) + if ((irp = devredir_irp_new()) == NULL) return -1; - irp->completion_id = g_completion_id++; + irp->CompletionId = g_completion_id++; #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); return -1; } #endif irp->completion_type = CID_FILE_CLOSE; - irp->device_id = device_id; + irp->DeviceId = device_id; dev_redir_fuse_data_enqueue(irp, fusep); return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, PAKID_CORE_DEVICE_IOREQUEST, device_id, FileId, - irp->completion_id, + irp->CompletionId, IRP_MJ_CLOSE, 0, 32); } @@ -1057,12 +1129,12 @@ int devredir_rmdir_or_file(void *fusep, tui32 device_id, char *path, int mode) int rval; IRP *irp; - if ((irp = dev_redir_irp_new()) == NULL) + if ((irp = devredir_irp_new()) == NULL) return -1; - irp->completion_id = g_completion_id++; + irp->CompletionId = g_completion_id++; irp->completion_type = CID_RMDIR_OR_FILE; - irp->device_id = device_id; + irp->DeviceId = device_id; strcpy(irp->pathname, path); 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, DesiredAccess, CreateOptions, CreateDisposition, - irp->completion_id); + irp->CompletionId); return rval; } @@ -1099,7 +1171,7 @@ int dev_redir_file_read(void *fusep, tui32 DeviceId, tui32 FileId, 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); 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; dev_redir_fuse_data_enqueue(irp, fusep); - dev_redir_insert_dev_io_req_header(s, - DeviceId, - FileId, - irp->completion_id, - IRP_MJ_READ, - 0); + devredir_insert_DeviceIoRequest(s, + DeviceId, + FileId, + irp->CompletionId, + IRP_MJ_READ, + 0); xstream_wr_u32_le(s, Length); 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); - 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); 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; dev_redir_fuse_data_enqueue(irp, fusep); - dev_redir_insert_dev_io_req_header(s, - DeviceId, - FileId, - irp->completion_id, - IRP_MJ_WRITE, - 0); + devredir_insert_DeviceIoRequest(s, + DeviceId, + FileId, + irp->CompletionId, + IRP_MJ_WRITE, + 0); xstream_wr_u32_le(s, Length); xstream_wr_u64_le(s, Offset); @@ -1249,187 +1321,16 @@ int dev_redir_fuse_data_enqueue(IRP *irp, void *vp) 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 ** ******************************************************************************/ -void dev_redir_insert_dev_io_req_header(struct stream *s, - tui32 DeviceId, - tui32 FileId, - tui32 CompletionId, - tui32 MajorFunction, - tui32 MinorFunction) +void devredir_insert_DeviceIoRequest(struct stream *s, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunction) { /* setup DR_DEVICE_IOREQUEST header */ 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; } -void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component, +void devredir_insert_RDPDR_header(struct stream *s, tui16 Component, tui16 PacketId) { 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); free(fuse_data); } - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); return; } xstream_new(s, 1024); irp->completion_type = CID_RMDIR_OR_FILE_RESP; - dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId, - irp->completion_id, - IRP_MJ_SET_INFORMATION, 0); + devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, + irp->CompletionId, + IRP_MJ_SET_INFORMATION, 0); xstream_wr_u32_le(s, FileDispositionInformation); 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) { - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); return; } irp->completion_type = CID_CLOSE; dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, PAKID_CORE_DEVICE_IOREQUEST, - irp->device_id, + irp->DeviceId, irp->FileId, - irp->completion_id, + irp->CompletionId, 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); free(fuse_data); } - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); return; } xstream_new(s, 1024); irp->completion_type = CID_RENAME_FILE_RESP; - dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId, - irp->completion_id, - IRP_MJ_SET_INFORMATION, 0); + devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, + irp->CompletionId, + IRP_MJ_SET_INFORMATION, 0); flen = strlen(irp->gen_buf) * 2 + 2; sblen = 6 + flen; @@ -1627,15 +1528,15 @@ void devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus) if (IoStatus != NT_STATUS_SUCCESS) { - dev_redir_irp_delete(irp); + devredir_irp_delete(irp); return; } irp->completion_type = CID_CLOSE; dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, PAKID_CORE_DEVICE_IOREQUEST, - irp->device_id, + irp->DeviceId, irp->FileId, - irp->completion_id, + irp->CompletionId, IRP_MJ_CLOSE, 0, 32); } diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 5bc85ede..d56b4457 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -23,59 +23,14 @@ #if !defined(DEVREDIR_H) #define DEVREDIR_H -#include -#include -#include -#include -#include -#include -#include - -#include "arch.h" -#include "parse.h" -#include "os_calls.h" -#include "log.h" -#include "chansrv_fuse.h" +#include "irp.h" #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_dequeue(IRP *irp); 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_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_clientID_confirm(); 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, tui32 InitialQuery, char *Path); @@ -107,7 +62,7 @@ int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, tui32 MinorFunc, 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_device_iocompletion(struct stream *s); @@ -118,20 +73,20 @@ void dev_redir_proc_query_dir_response(IRP *irp, tui32 IoStatus); /* misc stuff */ -void dev_redir_insert_dev_io_req_header(struct stream *s, - tui32 DeviceId, - tui32 FileId, - tui32 CompletionId, - tui32 MajorFunction, - tui32 MinorFunction); +void devredir_insert_DeviceIoRequest(struct stream *s, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunction); void devredir_cvt_slash(char *path); void devredir_cvt_to_unicode(char *unicode, char *path); void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); int dev_redir_string_ends_with(char *string, char c); -void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component, - tui16 PacketId); +void devredir_insert_RDPDR_header(struct stream *s, tui16 Component, + tui16 PacketId); void devredir_proc_cid_rmdir_or_file(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, 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); /* diff --git a/sesman/chansrv/irp.c b/sesman/chansrv/irp.c new file mode 100644 index 00000000..9faaabf5 --- /dev/null +++ b/sesman/chansrv/irp.c @@ -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 ---"); +} diff --git a/sesman/chansrv/irp.h b/sesman/chansrv/irp.h new file mode 100644 index 00000000..ccab5801 --- /dev/null +++ b/sesman/chansrv/irp.h @@ -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 */ diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c new file mode 100644 index 00000000..3fdb6723 --- /dev/null +++ b/sesman/chansrv/smartcard.c @@ -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; + } + } +} + +/** + * + *****************************************************************************/ diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h new file mode 100644 index 00000000..88f31369 --- /dev/null +++ b/sesman/chansrv/smartcard.h @@ -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 */