diff options
Diffstat (limited to 'sesman')
-rw-r--r-- | sesman/auth.h | 10 | ||||
-rw-r--r-- | sesman/chansrv/Makefile.am | 8 | ||||
-rw-r--r-- | sesman/chansrv/chansrv.c | 270 | ||||
-rw-r--r-- | sesman/chansrv/chansrv.h | 9 | ||||
-rw-r--r-- | sesman/chansrv/chansrv_fuse.c | 218 | ||||
-rw-r--r-- | sesman/chansrv/clipboard.c | 65 | ||||
-rw-r--r-- | sesman/chansrv/devredir.c | 23 | ||||
-rw-r--r-- | sesman/chansrv/fifo.c | 255 | ||||
-rw-r--r-- | sesman/chansrv/fifo.h | 35 | ||||
-rw-r--r-- | sesman/chansrv/irp.h | 1 | ||||
-rw-r--r-- | sesman/chansrv/mlog.h | 112 | ||||
-rw-r--r-- | sesman/chansrv/pcsc/Makefile | 12 | ||||
-rw-r--r-- | sesman/chansrv/pcsc/xrdp_pcsc.c | 929 | ||||
-rw-r--r-- | sesman/chansrv/rail.c | 1354 | ||||
-rw-r--r-- | sesman/chansrv/rail.h | 2 | ||||
-rw-r--r-- | sesman/chansrv/smartcard.c | 2227 | ||||
-rw-r--r-- | sesman/chansrv/smartcard.h | 125 | ||||
-rw-r--r-- | sesman/chansrv/smartcard_pcsc.c | 845 | ||||
-rw-r--r-- | sesman/chansrv/smartcard_pcsc.h | 31 | ||||
-rw-r--r-- | sesman/chansrv/sound.c | 3 | ||||
-rw-r--r-- | sesman/chansrv/xcommon.c | 10 | ||||
-rw-r--r-- | sesman/config.c | 10 | ||||
-rw-r--r-- | sesman/sesman.ini | 5 | ||||
-rw-r--r-- | sesman/session.c | 154 | ||||
-rw-r--r-- | sesman/verify_user_kerberos.c | 8 | ||||
-rw-r--r-- | sesman/verify_user_pam.c | 20 | ||||
-rw-r--r-- | sesman/verify_user_pam_userpass.c | 8 |
27 files changed, 6168 insertions, 581 deletions
diff --git a/sesman/auth.h b/sesman/auth.h index 39acc0b8..e06b9eb3 100644 --- a/sesman/auth.h +++ b/sesman/auth.h @@ -57,6 +57,16 @@ auth_start_session(long in_val, int in_display); * */ int DEFAULT_CC +auth_stop_session(long in_val); + +/** + * + * @brief FIXME + * @param in_val + * @return 0 on success, 1 on failure + * + */ +int DEFAULT_CC auth_end(long in_val); /** diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 7cecdb1e..2d73f05c 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -8,7 +8,8 @@ EXTRA_DIST = \ drdynvc.h \ rail.h \ sound.h \ - xcommon.h + xcommon.h \ + mlog.h EXTRA_DEFINES = EXTRA_INCLUDES = @@ -51,7 +52,8 @@ xrdp_chansrv_SOURCES = \ xcommon.c \ drdynvc.c \ chansrv_fuse.c \ - irp.c + irp.c \ + fifo.c xrdp_chansrv_LDFLAGS = \ $(EXTRA_FLAGS) @@ -59,5 +61,5 @@ xrdp_chansrv_LDFLAGS = \ xrdp_chansrv_LDADD = \ -L/usr/X11R6/lib \ $(top_builddir)/common/libcommon.la \ - -lX11 -lXfixes \ + -lX11 -lXfixes -lXrandr \ $(EXTRA_LIBS) diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 388d0273..01c6a43d 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -72,10 +72,156 @@ tbus g_exec_mutex; tbus g_exec_sem; int g_exec_pid = 0; +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x))) + /* each time we create a DVC we need a unique DVC channel id */ /* this variable gets bumped up once per DVC we create */ tui32 g_dvc_chan_id = 100; +struct timeout_obj +{ + tui32 mstime; + void *data; + void (*callback)(void *data); + struct timeout_obj *next; +}; + +static struct timeout_obj *g_timeout_head = 0; +static struct timeout_obj *g_timeout_tail = 0; + +/*****************************************************************************/ +int APP_CC +add_timeout(int msoffset, void (*callback)(void *data), void *data) +{ + struct timeout_obj *tobj; + tui32 now; + + LOG(10, ("add_timeout:")); + now = g_time3(); + tobj = g_malloc(sizeof(struct timeout_obj), 1); + tobj->mstime = now + msoffset; + tobj->callback = callback; + tobj->data = data; + if (g_timeout_tail == 0) + { + g_timeout_head = tobj; + g_timeout_tail = tobj; + } + else + { + g_timeout_tail->next = tobj; + g_timeout_tail = tobj; + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +get_timeout(int *timeout) +{ + struct timeout_obj *tobj; + tui32 now; + int ltimeout; + + LOG(10, ("get_timeout:")); + ltimeout = *timeout; + if (ltimeout < 1) + { + ltimeout = 0; + } + tobj = g_timeout_head; + if (tobj != 0) + { + now = g_time3(); + while (tobj != 0) + { + LOG(10, (" now %u tobj->mstime %u", now, tobj->mstime)); + if (now < tobj->mstime) + { + ltimeout = tobj->mstime - now; + } + tobj = tobj->next; + } + } + if (ltimeout > 0) + { + LOG(10, (" ltimeout %d", ltimeout)); + if (*timeout < 1) + { + *timeout = ltimeout; + } + else + { + if (*timeout > ltimeout) + { + *timeout = ltimeout; + } + } + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +check_timeout(void) +{ + struct timeout_obj *tobj; + struct timeout_obj *last_tobj; + struct timeout_obj *temp_tobj; + int count; + tui32 now; + + LOG(10, ("check_timeout:")); + count = 0; + tobj = g_timeout_head; + if (tobj != 0) + { + last_tobj = 0; + while (tobj != 0) + { + count++; + now = g_time3(); + if (now >= tobj->mstime) + { + tobj->callback(tobj->data); + if (last_tobj == 0) + { + g_timeout_head = tobj->next; + if (g_timeout_head == 0) + { + g_timeout_tail = 0; + } + } + else + { + last_tobj->next = tobj->next; + if (g_timeout_tail == tobj) + { + g_timeout_tail = last_tobj; + } + } + temp_tobj = tobj; + tobj = tobj->next; + g_free(temp_tobj); + } + else + { + last_tobj = tobj; + tobj = tobj->next; + } + } + } + LOG(10, (" count %d", count)); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +g_is_term(void) +{ + return g_is_wait_obj_set(g_term_event); +} + /*****************************************************************************/ /* add data to chan_item, on its way to the client */ /* returns error */ @@ -149,11 +295,11 @@ send_data_from_chan_item(struct chan_item *chan_item) out_uint32_le(s, cod->s->size); out_uint8a(s, cod->s->p, size); s_mark_end(s); - LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_data_from_chan_item: -- " "size %d chan_flags 0x%8.8x", size, chan_flags)); g_sent = 1; - error = trans_force_write(g_con_trans); + error = trans_write_copy(g_con_trans); if (error != 0) { return 1; @@ -230,6 +376,31 @@ send_channel_data(int chan_id, char *data, int size) /*****************************************************************************/ /* returns error */ +int APP_CC +send_rail_drawing_orders(char* data, int size) +{ + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_rail_drawing_orders: size %d", size)); + + struct stream* s; + int error; + + s = trans_get_out_s(g_con_trans, 8192); + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + size); /* size */ + out_uint32_le(s, 10); /* msg id */ + out_uint32_le(s, 8 + size); /* size */ + out_uint8a(s, data, size); + s_mark_end(s); + error = trans_force_write(g_con_trans); + if (error != 0) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ static int APP_CC send_init_response_message(void) { @@ -248,7 +419,7 @@ send_init_response_message(void) out_uint32_le(s, 2); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -271,7 +442,7 @@ send_channel_setup_response_message(void) out_uint32_le(s, 4); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -294,7 +465,7 @@ send_channel_data_response_message(void) out_uint32_le(s, 6); /* msg id */ out_uint32_le(s, 8); /* size */ s_mark_end(s); - return trans_force_write(g_con_trans); + return trans_write_copy(g_con_trans); } /*****************************************************************************/ @@ -493,7 +664,7 @@ process_message_channel_data(struct stream *s) if (chan_flags & 2) /* last */ { s_mark_end(ls); - trans_force_write(g_api_con_trans); + trans_write_copy(g_api_con_trans); } } } @@ -844,13 +1015,15 @@ setup_listen(void) if (g_use_unix_socket) { - g_lis_trans = trans_create(2, 8192, 8192); + g_lis_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); + g_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + g_display_num); } else { - g_lis_trans = trans_create(1, 8192, 8192); + g_lis_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + g_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "%d", 7200 + g_display_num); } @@ -875,6 +1048,7 @@ setup_api_listen(void) int error = 0; g_api_lis_trans = trans_create(TRANS_MODE_UNIX, 8192 * 4, 8192 * 4); + g_api_lis_trans->is_term = g_is_term; g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num); g_api_lis_trans->trans_conn_in = my_api_trans_conn_in; error = trans_listen(g_api_lis_trans, port); @@ -894,7 +1068,9 @@ THREAD_RV THREAD_CC channel_thread_loop(void *in_val) { tbus objs[32]; + tbus wobjs[32]; int num_objs; + int num_wobjs; int timeout; int error; THREAD_RV rv; @@ -908,13 +1084,15 @@ channel_thread_loop(void *in_val) { timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) + while (g_obj_wait(objs, num_objs, wobjs, num_wobjs, timeout) == 0) { + check_timeout(); if (g_is_wait_obj_set(g_term_event)) { LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); @@ -987,16 +1165,19 @@ channel_thread_loop(void *in_val) xfuse_check_wait_objs(); timeout = -1; num_objs = 0; + num_wobjs = 0; objs[num_objs] = g_term_event; num_objs++; trans_get_wait_objs(g_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_con_trans, objs, &num_objs); + trans_get_wait_objs_rw(g_con_trans, objs, &num_objs, + wobjs, &num_wobjs); trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); trans_get_wait_objs(g_api_con_trans, objs, &num_objs); xcommon_get_wait_objs(objs, &num_objs, &timeout); sound_get_wait_objs(objs, &num_objs, &timeout); dev_redir_get_wait_objs(objs, &num_objs, &timeout); xfuse_get_wait_objs(objs, &num_objs, &timeout); + get_timeout(&timeout); } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ } @@ -1034,7 +1215,7 @@ child_signal_handler(int sig) { int i1; - LOG(10, ("child_signal_handler:")); + LOG(0, ("child_signal_handler:")); do { @@ -1051,6 +1232,14 @@ child_signal_handler(int sig) while (i1 >= 0); } +void DEFAULT_CC +segfault_signal_handler(int sig) +{ + LOG(0, ("segfault_signal_handler: entered.......")); + xfuse_deinit(); + exit(0); +} + /*****************************************************************************/ static int APP_CC get_display_num_from_display(char *display_text) @@ -1164,6 +1353,47 @@ read_ini(void) } /*****************************************************************************/ +static char* APP_CC +get_log_path() +{ + char* log_path = 0; + + log_path = g_getenv("CHANSRV_LOG_PATH"); + if (log_path == 0) + { + log_path = g_getenv("HOME"); + } + return log_path; +} + +/*****************************************************************************/ +static unsigned int APP_CC +get_log_level(const char* level_str, unsigned int default_level) +{ + static const char* levels[] = { + "LOG_LEVEL_ALWAYS", + "LOG_LEVEL_ERROR", + "LOG_LEVEL_WARNING", + "LOG_LEVEL_INFO", + "LOG_LEVEL_DEBUG" + }; + unsigned int i; + + if (level_str == NULL || level_str[0] == 0) + { + return default_level; + } + for (i = 0; i < ARRAYSIZE(levels); ++i) + { + if (g_strcasecmp(levels[i], level_str) == 0) + { + return i; + } + } + return default_level; +} + +/*****************************************************************************/ static int APP_CC run_exec(void) { @@ -1197,19 +1427,19 @@ main(int argc, char **argv) tbus waiters[4]; int pid = 0; char text[256]; - char *home_text; + char* log_path; char *display_text; char log_file[256]; enum logReturns error; struct log_config logconfig; + unsigned int log_level; g_init("xrdp-chansrv"); /* os_calls */ - home_text = g_getenv("HOME"); - - if (home_text == 0) + log_path = get_log_path(); + if (log_path == 0) { - g_writeln("error reading HOME environment variable"); + g_writeln("error reading CHANSRV_LOG_PATH and HOME environment variable"); g_deinit(); return 1; } @@ -1217,10 +1447,12 @@ main(int argc, char **argv) read_ini(); pid = g_getpid(); + log_level = get_log_level(g_getenv("CHANSRV_LOG_LEVEL"), LOG_LEVEL_ERROR); + /* starting logging subsystem */ g_memset(&logconfig, 0, sizeof(struct log_config)); logconfig.program_name = "XRDP-Chansrv"; - g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", home_text); + g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", log_path); g_writeln("chansrv::main: using log file [%s]", log_file); if (g_file_exist(log_file)) @@ -1230,7 +1462,7 @@ main(int argc, char **argv) logconfig.log_file = log_file; logconfig.fd = -1; - logconfig.log_level = LOG_LEVEL_ERROR; + logconfig.log_level = log_level; logconfig.enable_syslog = 0; logconfig.syslog_level = 0; error = log_start_from_param(&logconfig); @@ -1262,6 +1494,8 @@ main(int argc, char **argv) g_signal_user_interrupt(term_signal_handler); /* SIGINT */ g_signal_pipe(nil_signal_handler); /* SIGPIPE */ g_signal_child_stop(child_signal_handler); /* SIGCHLD */ + g_signal_segfault(segfault_signal_handler); + display_text = g_getenv("DISPLAY"); LOGM((LOG_LEVEL_INFO, "main: DISPLAY env var set to %s", display_text)); get_display_num_from_display(display_text); diff --git a/sesman/chansrv/chansrv.h b/sesman/chansrv/chansrv.h index bca30ca4..a3e8ed51 100644 --- a/sesman/chansrv/chansrv.h +++ b/sesman/chansrv/chansrv.h @@ -1,8 +1,8 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 - * Copyright (C) Laxmikant Rashinkar 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 + * Copyright (C) Laxmikant Rashinkar 2009-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,8 +54,13 @@ struct xrdp_api_data int is_connected; }; +int DEFAULT_CC +g_is_term(void); + int APP_CC send_channel_data(int chan_id, char *data, int size); +int APP_CC send_rail_drawing_orders(char* data, int size); int APP_CC main_cleanup(void); +int APP_CC add_timeout(int msoffset, void (*callback)(void* data), void* data); int APP_CC find_empty_slot_in_dvc_channels(); struct xrdp_api_data * APP_CC struct_from_dvc_chan_id(tui32 dvc_chan_id); int remove_struct_with_chan_id(tui32 dvc_chan_id); diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 572679eb..2eb78ea0 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -102,6 +102,7 @@ void xfuse_devredir_cb_file_close(void *vp) {} #include "os_calls.h" #include "chansrv_fuse.h" #include "list.h" +#include "fifo.h" #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -223,6 +224,16 @@ struct dir_info int index; }; +/* queue FUSE opendir commands so we run only one at a time */ +struct opendir_req +{ + fuse_req_t req; + fuse_ino_t ino; + struct fuse_file_info *fi; +}; + +FIFO g_fifo_opendir; + static struct list *g_req_list = 0; static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */ static char *g_mount_point = 0; /* our FUSE mount point */ @@ -338,19 +349,22 @@ static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, static void xfuse_cb_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi); -/* clipboard calls */ -int clipboard_request_file_data(int stream_id, int lindex, int offset, - int request_bytes); - static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); +static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); +/* clipboard calls */ +int clipboard_request_file_data(int stream_id, int lindex, int offset, + int request_bytes); + /* misc calls */ static void xfuse_mark_as_stale(int pinode); static void xfuse_delete_stale_entries(int pinode); @@ -403,6 +417,9 @@ int xfuse_init() if (xfuse_init_xrdp_fs()) return -1; + /* setup FIFOs */ + fifo_init(&g_fifo_opendir, 30); + /* setup FUSE callbacks */ g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops)); g_xfuse_ops.lookup = xfuse_cb_lookup; @@ -424,6 +441,8 @@ int xfuse_init() fuse_opt_add_arg(&args, "xrdp-chansrv"); fuse_opt_add_arg(&args, g_fuse_root_path); + //fuse_opt_add_arg(&args, "-s"); /* single threaded mode */ + //fuse_opt_add_arg(&args, "-d"); /* debug mode */ if (xfuse_init_lib(&args)) { @@ -444,6 +463,7 @@ int xfuse_init() int xfuse_deinit() { xfuse_deinit_xrdp_fs(); + fifo_deinit(&g_fifo_opendir); if (g_ch != 0) { @@ -901,12 +921,11 @@ static int xfuse_deinit_xrdp_fs() static int xfuse_is_inode_valid(int ino) { - /* our lowest ino is FIRST_INODE */ - if (ino < FIRST_INODE) + /* is ino present in our table? */ + if ((ino < FIRST_INODE) || (ino >= g_xrdp_fs.next_node)) return 0; - /* is ino present in our table? */ - if (ino >= g_xrdp_fs.next_node) + if (g_xrdp_fs.inode_table[ino] == NULL) return 0; return 1; @@ -989,6 +1008,11 @@ static void xfuse_dump_fs() log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE); +#if 0 + log_debug("not dumping xrdp fs"); + return; +#endif + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) @@ -1229,6 +1253,9 @@ static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode) if ((xinode == NULL) || (xinode->mode & S_IFDIR)) return -1; + log_always("deleting: inode=%d name=%s", xinode->inode, xinode->name); + log_debug("deleting: inode=%d name=%s", xinode->inode, xinode->name); + g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; g_xrdp_fs.inode_table[xinode->inode] = NULL; free(xinode); @@ -1281,6 +1308,12 @@ static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode) if ((xinode == NULL) || (xinode->mode & S_IFREG)) return -1; + log_always("recursively deleting dir with inode=%d name=%s", + xinode->inode, xinode->name); + + log_debug("recursively deleting dir with inode=%d name=%s", + xinode->inode, xinode->name); + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { if ((xip = g_xrdp_fs.inode_table[i]) == NULL) @@ -1342,60 +1375,6 @@ static void xfuse_update_xrdpfs_size() g_xrdp_fs.inode_table = vp; } -/* LK_TODO do we still need this function */ -#if 0 -static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) -{ - XRDP_INODE *xinode; - XRDP_INODE *xinode1; - struct dirbuf b; - int first_time = 1; - int i; - - memset(&b, 0, sizeof(struct dirbuf)); - - for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) - { - if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) - continue; - - /* match parent inode */ - if (xinode->parent_inode != ino) - continue; - - if (first_time) - { - first_time = 0; - if (ino == 1) - { - xfuse_dirbuf_add(req, &b, ".", 1); - xfuse_dirbuf_add(req, &b, "..", 1); - } - else - { - xinode1 = g_xrdp_fs.inode_table[ino]; - xfuse_dirbuf_add(req, &b, ".", ino); - xfuse_dirbuf_add(req, &b, "..", xinode1->parent_inode); - } - } - - xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode); - } - - if (!first_time) - { - if (off < b.size) - fuse_reply_buf(req, b.p + off, min(b.size - off, size)); - else - fuse_reply_buf(req, NULL, 0); - } - - if (b.p) - free(b.p); -} -#endif - /****************************************************************************** ** ** ** callbacks for devredir ** @@ -1464,8 +1443,9 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) { - XFUSE_INFO *fip; - struct dir_info *di; + XFUSE_INFO *fip; + struct dir_info *di; + struct opendir_req *odreq; log_debug("vp=%p IoStatus=0x%x", vp, IoStatus); @@ -1473,7 +1453,7 @@ void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) if (fip == NULL) { log_debug("fip is NULL"); - return; + goto done; } if (IoStatus != 0) @@ -1506,6 +1486,22 @@ done: if (fip) free(fip); + + /* remove current request */ + g_free(fifo_remove(&g_fifo_opendir)); + + while (1) + { + /* process next request */ + odreq = fifo_peek(&g_fifo_opendir); + if (!odreq) + return; + + if (xfuse_proc_opendir_req(odreq->req, odreq->ino, odreq->fi)) + g_free(fifo_remove(&g_fifo_opendir)); /* req failed */ + else + break; /* req has been queued */ + } } void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, @@ -1903,15 +1899,19 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, } xino = g_xrdp_fs.inode_table[ino]; + if (!xino) + { + log_debug("****** invalid ino=%d", (int) ino); + fuse_reply_err(req, EBADF); + return; + } memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = ino; stbuf.st_mode = xino->mode; stbuf.st_nlink = xino->nlink; stbuf.st_size = xino->size; - fuse_reply_attr(req, &stbuf, 1.0); - log_debug("exiting"); } /** @@ -1977,8 +1977,7 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, int i; int first_time; - log_debug("req=%p inode=%d name=%s size=%d offset=%d", req, ino, - g_xrdp_fs.inode_table[ino]->name, size, off); + log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off); /* do we have a valid inode? */ if (!xfuse_is_inode_valid(ino)) @@ -2014,6 +2013,12 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, { first_time = 0; ti = g_xrdp_fs.inode_table[ino]; + if (!ti) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_buf(req, NULL, 0); + return; + } xfuse_dirbuf_add1(req, &b, ".", ino); xfuse_dirbuf_add1(req, &b, "..", ti->parent_inode); } @@ -2451,6 +2456,12 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, /* if ino points to a dir, fail the open request */ xinode = g_xrdp_fs.inode_table[ino]; + if (!xinode) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + return; + } if (xinode->mode & S_IFDIR) { log_debug("reading a dir not allowed!"); @@ -2491,8 +2502,6 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, fip->name[1023] = 0; fip->reply_type = RT_FUSE_REPLY_OPEN; - /* LK_TODO need to handle open permissions */ - /* we want path minus 'root node of the share' */ if ((cptr = strchr(full_path, '/')) == NULL) { @@ -2532,6 +2541,12 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct } XRDP_INODE *xinode = g_xrdp_fs.inode_table[ino]; + if (!xinode) + { + log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, 0); + return; + } if (xinode->is_loc_resource) { /* specified file is a local resource */ @@ -2748,7 +2763,12 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, return; } - xinode = g_xrdp_fs.inode_table[ino]; + if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) + { + log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + return; + } if (to_set & FUSE_SET_ATTR_MODE) { @@ -2813,9 +2833,40 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */ } +/** + * Get dir listing + *****************************************************************************/ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct opendir_req *odreq; + + /* save request */ + odreq = malloc(sizeof(struct opendir_req)); + odreq->req = req; + odreq->ino = ino; + odreq->fi = fi; + + if (fifo_is_empty(&g_fifo_opendir)) + { + fifo_insert(&g_fifo_opendir, odreq); + xfuse_proc_opendir_req(req, ino, fi); + } + else + { + /* place req in FIFO; xfuse_devredir_cb_enum_dir_done() will handle it */ + fifo_insert(&g_fifo_opendir, odreq); + } +} + +/** + * Process the next opendir req + * + * @return 0 of the request was sent for remote lookup, -1 otherwise + *****************************************************************************/ +static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ struct dir_info *di; XRDP_INODE *xinode; XFUSE_INFO *fip; @@ -2823,19 +2874,26 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, char full_path[4096]; char *cptr; - log_debug("inode=%d name=%s", ino, g_xrdp_fs.inode_table[ino]->name); + log_debug("inode=%d", ino); if (!xfuse_is_inode_valid(ino)) { log_error("inode %d is not valid", ino); fuse_reply_err(req, EBADF); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } if (ino == 1) goto done; /* special case; enumerate top level dir */ - xinode = g_xrdp_fs.inode_table[ino]; + if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) + { + log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino); + fuse_reply_err(req, EBADF); + g_free(fifo_remove(&g_fifo_opendir)); + return -1; + } if (xinode->is_loc_resource) goto done; @@ -2846,7 +2904,8 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, if (xinode->is_synced) { xfuse_enum_dir(req, ino, size, off, fi); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } else { @@ -2867,7 +2926,8 @@ do_remote_lookup: { log_error("system out of memory"); fuse_reply_err(req, ENOMEM); - return; + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } fip->req = req; @@ -2900,7 +2960,7 @@ do_remote_lookup: } } - return; + return 0; done: @@ -2908,6 +2968,8 @@ done: di->index = FIRST_INODE; fi->fh = (long) di; fuse_reply_open(req, fi); + g_free(fifo_remove(&g_fifo_opendir)); + return -1; } /** diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index c2062605..25775f3b 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -277,6 +277,39 @@ static int g_num_formatIds = 0; static int g_file_format_id = -1; +static char g_last_atom_name[256] = ""; + +/*****************************************************************************/ +static char* APP_CC +get_atom_text(Atom atom) +{ + char* name; + int failed; + + failed = 0; + /* sanity check */ + if ((atom < 1) || (atom > 512)) + { + failed = 1; + } + if (!failed) + { + name = XGetAtomName(g_display, atom); + if (name == 0) + { + failed = 1; + } + } + if (failed) + { + g_snprintf(g_last_atom_name, 255, "unknown atom 0x%8.8x", (int)atom); + return g_last_atom_name; + } + g_strncpy(g_last_atom_name, name, 255); + XFree(name); + return g_last_atom_name; +} + /*****************************************************************************/ /* this is one way to get the current time from the x server */ static Time APP_CC @@ -895,8 +928,8 @@ clipboard_provide_selection_c2s(XSelectionRequestEvent *req, Atom type) g_clip_c2s.property = req->property; g_clip_c2s.window = req->requestor; log_debug("clipboard_provide_selection_c2s: start INCR property %s " - "type %s", XGetAtomName(g_display, req->property), - XGetAtomName(g_display, type)); + "type %s", get_atom_text(req->property), + get_atom_text(type)); val1[0] = g_clip_c2s.total_bytes; val1[1] = 0; XChangeProperty(g_display, req->requestor, req->property, @@ -1697,7 +1730,7 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom *type, int *fmt, Atom ltype; log_debug("clipboard_get_window_property:"); - log_debug(" prop %d name %s", prop, XGetAtomName(g_display, prop)); + log_debug(" prop %d name %s", prop, get_atom_text(prop)); lxdata = 0; ltype = 0; XGetWindowProperty(g_display, wnd, prop, 0, 0, 0, @@ -1837,7 +1870,7 @@ clipboard_event_selection_notify(XEvent *xevent) { log_debug("clipboard_event_selection_notify: wnd %p prop %s", lxevent->requestor, - XGetAtomName(g_display, lxevent->property)); + get_atom_text(lxevent->property)); rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, &type, &fmt, &n_items, &data, &data_size); @@ -1855,8 +1888,8 @@ clipboard_event_selection_notify(XEvent *xevent) PropertyNotify */ log_debug("clipboard_event_selection_notify: type is INCR " "data_size %d property name %s type %s", data_size, - XGetAtomName(g_display, lxevent->property), - XGetAtomName(g_display, lxevent->type)); + get_atom_text(lxevent->property), + get_atom_text(lxevent->type)); g_clip_s2c.incr_in_progress = 1; g_clip_s2c.property = lxevent->property; g_clip_s2c.type = lxevent->target; @@ -1882,10 +1915,10 @@ clipboard_event_selection_notify(XEvent *xevent) for (index = 0; index < n_items; index++) { atom = atoms[index]; - log_debug("clipboard_event_selection_notify: %d %s %d", - atom, XGetAtomName(g_display, atom), XA_STRING); + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: %d %s %d", + atom, get_atom_text(atom), XA_STRING)); log_debug("clipboard_event_selection_notify: 0x%x %s", - atom, XGetAtomName(g_display, atom)); + atom, get_atom_text(atom)); if (atom == g_utf8_atom) { got_utf8 = 1; @@ -2091,7 +2124,6 @@ static int APP_CC clipboard_event_selection_request(XEvent *xevent) { XSelectionRequestEvent *lxev; - XEvent xev; Atom atom_buf[10]; Atom type; int atom_count; @@ -2105,7 +2137,7 @@ clipboard_event_selection_request(XEvent *xevent) log_debug("clipboard_event_selection_request: g_wnd %d, " ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", g_wnd, lxev->requestor, lxev->owner, lxev->selection, - XGetAtomName(g_display, lxev->selection), + get_atom_text(lxev->selection), lxev->target, lxev->property); if (lxev->property == None) @@ -2164,8 +2196,7 @@ clipboard_event_selection_request(XEvent *xevent) "g_multiple_atom"); xdata = 0; - if (clipboard_get_window_property(xev.xselection.requestor, - xev.xselection.property, + if (clipboard_get_window_property(lxev->requestor, lxev->property, &type, &fmt, &n_items, &xdata, &xdata_size) == 0) { @@ -2235,9 +2266,9 @@ clipboard_event_selection_request(XEvent *xevent) else { log_debug("clipboard_event_selection_request: unknown " - "target %s", XGetAtomName(g_display, lxev->target)); - log_error("clipboard_event_selection_request: unknown " - "target %s", XGetAtomName(g_display, lxev->target)); + "target %s", get_atom_text(lxev->target)); + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: unknown " + "target %s", get_atom_text(lxev->target))); } clipboard_refuse_selection(lxev); @@ -2293,7 +2324,7 @@ clipboard_event_property_notify(XEvent *xevent) log_debug("clipboard_event_property_notify: PropertyNotify .window %d " ".state %d .atom %d %s", xevent->xproperty.window, xevent->xproperty.state, xevent->xproperty.atom, - XGetAtomName(g_display, xevent->xproperty.atom)); + get_atom_text(xevent->xproperty.atom)); if (g_clip_c2s.incr_in_progress && (xevent->xproperty.window == g_clip_c2s.window) && diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 418c29e7..cdcc9e94 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -68,7 +68,7 @@ #define log_info(_params...) \ { \ - if (LOG_INFO <= LOG_LEVEL) \ + if (LOG_INFO <= LOG_LEVEL) \ { \ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ g_time3(), __func__, __LINE__); \ @@ -78,7 +78,7 @@ #define log_debug(_params...) \ { \ - if (LOG_DEBUG <= LOG_LEVEL) \ + if (LOG_DEBUG <= LOG_LEVEL) \ { \ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ g_time3(), __func__, __LINE__); \ @@ -587,53 +587,50 @@ void dev_redir_proc_client_core_cap_resp(struct stream *s) tui16 cap_type; tui16 cap_len; tui32 cap_version; + char* holdp; xstream_rd_u16_le(s, num_caps); xstream_seek(s, 2); /* padding */ for (i = 0; i < num_caps; i++) { + holdp = s->p; xstream_rd_u16_le(s, cap_type); xstream_rd_u16_le(s, cap_len); xstream_rd_u32_le(s, cap_version); - /* remove header length and version */ - cap_len -= 8; - switch (cap_type) { case CAP_GENERAL_TYPE: log_debug("got CAP_GENERAL_TYPE"); - xstream_seek(s, cap_len); break; case CAP_PRINTER_TYPE: log_debug("got CAP_PRINTER_TYPE"); g_is_printer_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_PORT_TYPE: log_debug("got CAP_PORT_TYPE"); g_is_port_redir_supported = 1; - xstream_seek(s, cap_len); break; case CAP_DRIVE_TYPE: log_debug("got CAP_DRIVE_TYPE"); g_is_drive_redir_supported = 1; if (cap_version == 2) + { g_drive_redir_version = 2; - xstream_seek(s, cap_len); + } break; case CAP_SMARTCARD_TYPE: log_debug("got CAP_SMARTCARD_TYPE"); g_is_smartcard_redir_supported = 1; scard_init(); - xstream_seek(s, cap_len); break; } + s->p = holdp + cap_len; } } @@ -1101,7 +1098,11 @@ dev_redir_file_open(void *fusep, tui32 device_id, char *path, #if 1 /* without the 0x00000010 rdesktop opens files in */ /* O_RDONLY instead of O_RDWR mode */ - DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; + if (mode & O_RDWR) + DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; + else + DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; + CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; // WAS 1 #else diff --git a/sesman/chansrv/fifo.c b/sesman/chansrv/fifo.c new file mode 100644 index 00000000..630df3cd --- /dev/null +++ b/sesman/chansrv/fifo.c @@ -0,0 +1,255 @@ +/** + * 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. + */ + + /* FIFO implementation to store a pointer to a user struct */ + +/* module based logging */ +#define MODULE_NAME "FIFO " +#define LOCAL_DEBUG + +#include "fifo.h" +#include "mlog.h" + +/** + * Initialize a FIFO that grows as required + * + * @param fp pointer to a FIFO + * @param num_entries initial size + * + * @return 0 on success, -1 on failure + *****************************************************************************/ +int +fifo_init(FIFO* fp, int num_entries) +{ + log_debug_high("entered"); + + /* validate params */ + if (!fp) + { + log_debug_high("invalid parameters"); + return -1; + } + + if (num_entries < 1) + num_entries = 10; + + fp->rd_ptr = 0; + fp->wr_ptr = 0; + fp->user_data = (long *) g_malloc(sizeof(long) * num_entries); + + if (fp->user_data) + { + fp->entries = num_entries; + log_debug_low("FIFO created; rd_ptr=%d wr_ptr=%d entries=%d", + fp->rd_ptr, fp->wr_ptr, fp->entries); + return 0; + } + else + { + log_error("FIFO create error; system out of memory"); + fp->entries = 0; + return -1; + } +} + +/** + * Deinit FIFO and release resources + * + * @param fp FIFO to deinit + * + * @return 0 on success, -1 on error + *****************************************************************************/ +int +fifo_deinit(FIFO* fp) +{ + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return -1; + } + + if (fp->user_data) + { + g_free(fp->user_data); + fp->user_data = 0; + } + + fp->rd_ptr = 0; + fp->wr_ptr = 0; + fp->entries = 0; +} + +/** + * Check if FIFO is empty + * + * @param fp FIFO + * + * @return 1 if FIFO is empty, 0 otherwise + *****************************************************************************/ +int +fifo_is_empty(FIFO* fp) +{ + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return 0; + } + + return (fp->rd_ptr == fp->wr_ptr) ? 1 : 0; +} + +/** + * Insert an item at the end + * + * @param fp FIFO + * @param data data to insert into FIFO + * + * @param 0 on success, -1 on error + *****************************************************************************/ + +int +fifo_insert(FIFO* fp, void* data) +{ + long* lp; + int next_val; /* next value for wr_ptr */ + int i; + + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return -1; + } + + next_val = fp->wr_ptr + 1; + if (next_val >= fp->entries) + next_val = 0; + + if (next_val == fp->rd_ptr) + { + /* FIFO is full, expand it by 10 entries */ + lp = (long *) g_malloc(sizeof(long) * (fp->entries + 10)); + if (!lp) + { + log_debug_low("FIFO full; cannot expand, no memory"); + return -1; + } + + log_debug_low("FIFO full, expanding by 10 entries"); + + /* copy old data new location */ + for (i = 0; i < (fp->entries - 1); i++) + { + lp[i] = fp->user_data[fp->rd_ptr++]; + if (fp->rd_ptr >= fp->entries) + fp->rd_ptr = 0; + } + + /* update pointers */ + fp->rd_ptr = 0; + fp->wr_ptr = fp->entries - 1; + next_val = fp->entries; + fp->entries += 10; + + /* free old data */ + g_free(fp->user_data); + fp->user_data = lp; + } + + log_debug_low("inserting data at index %d", fp->wr_ptr); + + fp->user_data[fp->wr_ptr] = (long) data; + fp->wr_ptr = next_val; + + return 0; +} + +/** + * Remove an item from the head + * + * @param fp FIFO + * + * @param data on success, NULL on error + *****************************************************************************/ +void* +fifo_remove(FIFO* fp) +{ + long data; + + log_debug_high("entered"); + + if (!fp) + { + log_debug_high("FIFO is null"); + return 0; + } + + if (fp->rd_ptr == fp->wr_ptr) + { + log_debug_high("FIFO is empty"); + return 0; + } + + log_debug_low("removing data at index %d", fp->rd_ptr); + + data = fp->user_data[fp->rd_ptr++]; + + if (fp->rd_ptr >= fp->entries) + { + log_debug_high("FIFO rd_ptr wrapped around"); + fp->rd_ptr = 0; + } + + return (void *) data; +} + +/** + * Return item from head, but do not remove it + * + * @param fp FIFO + * + * @param data on success, NULL on error + *****************************************************************************/ +void* +fifo_peek(FIFO* fp) +{ + long data; + + log_debug_high("entered\n"); + + if (!fp) + { + log_debug_high("FIFO is null\n"); + return 0; + } + + if (fp->rd_ptr == fp->wr_ptr) + { + log_debug_high("FIFO is empty\n"); + return 0; + } + + log_debug_low("peeking data at index %d\n", fp->rd_ptr); + + return (void *) fp->user_data[fp->rd_ptr]; +} diff --git a/sesman/chansrv/fifo.h b/sesman/chansrv/fifo.h new file mode 100644 index 00000000..0a23592c --- /dev/null +++ b/sesman/chansrv/fifo.h @@ -0,0 +1,35 @@ +/** + * 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. + */ + + /* FIFO implementation to store a pointer to a user struct */ + +typedef struct fifo +{ + long* user_data; + int rd_ptr; + int wr_ptr; + int entries; +} FIFO; + +int fifo_init(FIFO* fp, int num_entries); +int fifo_deinit(FIFO* fp); +int fifo_is_empty(FIFO* fp); +int fifo_insert(FIFO* fp, void* data); +void* fifo_remove(FIFO* fp); +void* fifo_peek(FIFO* fp); + diff --git a/sesman/chansrv/irp.h b/sesman/chansrv/irp.h index e1a65d83..a13ea8e5 100644 --- a/sesman/chansrv/irp.h +++ b/sesman/chansrv/irp.h @@ -52,6 +52,7 @@ struct irp void (*callback)(struct stream *s, IRP *irp, tui32 DeviceId, tui32 CompletionId, tui32 IoStatus); + void *user_data; }; IRP * APP_CC devredir_irp_new(void); diff --git a/sesman/chansrv/mlog.h b/sesman/chansrv/mlog.h new file mode 100644 index 00000000..866c9692 --- /dev/null +++ b/sesman/chansrv/mlog.h @@ -0,0 +1,112 @@ +/** + * 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. + */ + + /* module based logging */ + +#ifndef _MLOG_H +#define _MLOG_H + +/* + * Note1: to enable debug messages, in your .c file, #define LOCAL_DEBUG + * BEFORE including this file + * + * Note2: in your .c file, #define MODULE_NAME, 8 chars long, to print each + * log entry with your module name + */ + +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG_LOW 2 +#define LOG_DEBUG_HIGH 3 +#define LOG_LEVEL LOG_ERROR + +/* + * print always + */ + +#define log_error(_params...) \ +do \ +{ \ + g_write("[%10.10u]: %s %s: %d: ERROR: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ +} \ +while(0) + +#define log_always(_params...) \ +do \ +{ \ + g_write("[%10.10u]: %s %s: %d: ALWAYS: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ +} \ +while(0) + +/* + * print conditionally + */ + +#ifdef LOCAL_DEBUG +#define log_info(_params...) \ +do \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: INFO: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_info(_params...) +#endif + +#ifdef LOCAL_DEBUG +#define log_debug_low(_params...) \ +do \ +{ \ + if (LOG_DEBUG_LOW <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_debug_low(_params...) +#endif + +#ifdef LOCAL_DEBUG +#define log_debug_high(_params...) \ +do \ +{ \ + if (LOG_DEBUG_HIGH <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \ + MODULE_NAME, __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} \ +while(0) +#else +#define log_debug_high(_params...) +#endif + +#endif /* #ifndef _MLOG_H */ diff --git a/sesman/chansrv/pcsc/Makefile b/sesman/chansrv/pcsc/Makefile new file mode 100644 index 00000000..483151f2 --- /dev/null +++ b/sesman/chansrv/pcsc/Makefile @@ -0,0 +1,12 @@ + +OBJS = xrdp_pcsc.o + +CFLAGS = -Wall -O2 -fPIC + +all: libpcsclite.so + +libpcsclite.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -o libpcsclite.so $(OBJS) + +clean: + rm -f $(OBJS) libpcsclite.so diff --git a/sesman/chansrv/pcsc/xrdp_pcsc.c b/sesman/chansrv/pcsc/xrdp_pcsc.c new file mode 100644 index 00000000..c10a1627 --- /dev/null +++ b/sesman/chansrv/pcsc/xrdp_pcsc.c @@ -0,0 +1,929 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> + +#define PCSC_API + +typedef unsigned char BYTE; +typedef BYTE *LPBYTE; +typedef unsigned int LONG; +typedef unsigned int DWORD; +typedef DWORD *LPDWORD; +typedef const void *LPCVOID; +typedef const char *LPCSTR; +typedef char *LPSTR; +typedef void *LPVOID; +typedef const BYTE *LPCBYTE; + +typedef LONG SCARDCONTEXT; +typedef SCARDCONTEXT *LPSCARDCONTEXT; + +typedef LONG SCARDHANDLE; +typedef SCARDHANDLE *LPSCARDHANDLE; + +#define MAX_ATR_SIZE 33 + +typedef struct _SCARD_READERSTATE +{ + const char *szReader; + void *pvUserData; + DWORD dwCurrentState; + DWORD dwEventState; + DWORD cbAtr; + unsigned char rgbAtr[MAX_ATR_SIZE]; +} SCARD_READERSTATE, *LPSCARD_READERSTATE; + +typedef struct _SCARD_IO_REQUEST +{ + unsigned long dwProtocol; + unsigned long cbPciLength; +} SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; + +#define LLOG_LEVEL 5 +#define LLOGLN(_level, _args) \ + do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + +#define SCARD_ESTABLISH_CONTEXT 0x01 +#define SCARD_RELEASE_CONTEXT 0x02 +#define SCARD_LIST_READERS 0x03 +#define SCARD_CONNECT 0x04 +#define SCARD_RECONNECT 0x05 +#define SCARD_DISCONNECT 0x06 +#define SCARD_BEGIN_TRANSACTION 0x07 +#define SCARD_END_TRANSACTION 0x08 +#define SCARD_TRANSMIT 0x09 +#define SCARD_CONTROL 0x0A +#define SCARD_STATUS 0x0B +#define SCARD_GET_STATUS_CHANGE 0x0C +#define SCARD_CANCEL 0x0D +#define SCARD_CANCEL_TRANSACTION 0x0E +#define SCARD_GET_ATTRIB 0x0F +#define SCARD_SET_ATTRIB 0x10 + +#define SCARD_S_SUCCESS 0x00000000 +#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001) + +#define SET_UINT32(_data, _offset, _val) do { \ + (((BYTE*)(_data)) + (_offset))[0] = ((_val) >> 0) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[1] = ((_val) >> 8) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[2] = ((_val) >> 16) & 0xff; \ + (((BYTE*)(_data)) + (_offset))[3] = ((_val) >> 24) & 0xff; } while (0) + +#define GET_UINT32(_data, _offset) \ + ((((BYTE*)(_data)) + (_offset))[0] << 0) | \ + ((((BYTE*)(_data)) + (_offset))[1] << 8) | \ + ((((BYTE*)(_data)) + (_offset))[2] << 16) | \ + ((((BYTE*)(_data)) + (_offset))[3] << 24) + +#define LMIN(_val1, _val2) (_val1) < (_val2) ? (_val1) : (_val2) +#define LMAX(_val1, _val2) (_val1) > (_val2) ? (_val1) : (_val2) + +static int g_sck = -1; /* unix domain socket */ + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* for pcsc_stringify_error */ +static char g_error_str[512]; + +/*****************************************************************************/ +static int +get_display_num_from_display(const char *display_text) +{ + int rv; + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + char host[256]; + char disp[256]; + char scre[256]; + + memset(host, 0, 256); + memset(disp, 0, 256); + memset(scre, 0, 256); + + index = 0; + host_index = 0; + disp_index = 0; + scre_index = 0; + mode = 0; + + while (display_text[index] != 0) + { + if (display_text[index] == ':') + { + mode = 1; + } + else if (display_text[index] == '.') + { + mode = 2; + } + else if (mode == 0) + { + host[host_index] = display_text[index]; + host_index++; + } + else if (mode == 1) + { + disp[disp_index] = display_text[index]; + disp_index++; + } + else if (mode == 2) + { + scre[scre_index] = display_text[index]; + scre_index++; + } + index++; + } + host[host_index] = 0; + disp[disp_index] = 0; + scre[scre_index] = 0; + LLOGLN(0, ("get_display_num_from_display: host [%s] disp [%s] scre [%s]", + host, disp, scre)); + rv = atoi(disp); + return rv; +} + +/*****************************************************************************/ +static int +connect_to_chansrv(void) +{ + int bytes; + int dis; + int error; + char *xrdp_session; + char *xrdp_display; + char *home_str; + struct sockaddr_un saddr; + struct sockaddr *psaddr; + + if (g_sck != -1) + { + /* already connected */ + return 0; + } + xrdp_session = getenv("XRDP_SESSION"); + if (xrdp_session == NULL) + { + /* XRDP_SESSION must be set */ + LLOGLN(0, ("connect_to_chansrv: error, not xrdp session")); + return 1; + } + xrdp_display = getenv("DISPLAY"); + if (xrdp_display == NULL) + { + /* DISPLAY must be set */ + LLOGLN(0, ("connect_to_chansrv: error, display not set")); + return 1; + } + home_str = getenv("HOME"); + if (home_str == NULL) + { + /* HOME must be set */ + LLOGLN(0, ("connect_to_chansrv: error, home not set")); + return 1; + } + dis = get_display_num_from_display(xrdp_display); + if (dis < 10) + { + /* DISPLAY must be > 9 */ + LLOGLN(0, ("connect_to_chansrv: error, display not > 9 %d", dis)); + return 1; + } + g_sck = socket(PF_LOCAL, SOCK_STREAM, 0); + if (g_sck == -1) + { + LLOGLN(0, ("connect_to_chansrv: error, socket failed")); + return 1; + } + memset(&saddr, 0, sizeof(struct sockaddr_un)); + saddr.sun_family = AF_UNIX; + bytes = sizeof(saddr.sun_path); + snprintf(saddr.sun_path, bytes, "%s/.pcsc%d/pcscd.comm", home_str, dis); + saddr.sun_path[bytes - 1] = 0; + LLOGLN(0, ("connect_to_chansrv: connecting to %s", saddr.sun_path)); + psaddr = (struct sockaddr *) &saddr; + bytes = sizeof(struct sockaddr_un); + error = connect(g_sck, psaddr, bytes); + if (error == 0) + { + } + else + { + perror("connect_to_chansrv"); + close(g_sck); + g_sck = -1; + LLOGLN(0, ("connect_to_chansrv: error, open %s", saddr.sun_path)); + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +send_message(int code, char *data, int bytes) +{ + char header[8]; + + SET_UINT32(header, 0, bytes); + SET_UINT32(header, 4, code); + if (send(g_sck, header, 8, 0) != 8) + { + return 1; + } + if (send(g_sck, data, bytes, 0) != bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +static int +get_message(int *code, char *data, int *bytes) +{ + char header[8]; + int max_bytes; + + if (recv(g_sck, header, 8, 0) != 8) + { + return 1; + } + max_bytes = *bytes; + *bytes = GET_UINT32(header, 0); + *code = GET_UINT32(header, 4); + if (*bytes > max_bytes) + { + return 1; + } + if (recv(g_sck, data, *bytes, 0) != *bytes) + { + return 1; + } + return 0; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, + LPSCARDCONTEXT phContext) +{ + char msg[256]; + DWORD context; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardEstablishContext:")); + if (g_sck == -1) + { + if (connect_to_chansrv() != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, can not connect " + "to chansrv")); + return SCARD_F_INTERNAL_ERROR; + } + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, dwScope); + if (send_message(SCARD_ESTABLISH_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEstablishContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_ESTABLISH_CONTEXT) || (bytes != 8)) + { + LLOGLN(0, ("SCardEstablishContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + context = GET_UINT32(msg, 0); + status = GET_UINT32(msg, 4); + LLOGLN(10, ("SCardEstablishContext: got context 0x%8.8x", context)); + *phContext = context; + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReleaseContext(SCARDCONTEXT hContext) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardReleaseContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReleaseContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_RELEASE_CONTEXT, msg, 4) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardReleaseContext: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_RELEASE_CONTEXT) || (bytes != 4)) + { + LLOGLN(0, ("SCardReleaseContext: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardIsValidContext(SCARDCONTEXT hContext) +{ + LLOGLN(0, ("SCardIsValidContext:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardIsValidContext: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, + DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, + LPDWORD pdwActiveProtocol) +{ + char msg[256]; + int code; + int bytes; + int status; + int offset; + + LLOGLN(0, ("SCardConnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardConnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + offset = 0; + SET_UINT32(msg, offset, hContext); + offset += 4; + bytes = strlen(szReader); + if (bytes > 99) + { + LLOGLN(0, ("SCardConnect: error, name too long")); + return SCARD_F_INTERNAL_ERROR; + } + memcpy(msg + offset, szReader, bytes); + memset(msg + bytes, 0, 100 - bytes); + offset += 100; + SET_UINT32(msg, offset, dwShareMode); + offset += 4; + SET_UINT32(msg, offset, dwPreferredProtocols); + offset += 4; + if (send_message(SCARD_CONNECT, msg, offset) != 0) + { + LLOGLN(0, ("SCardConnect: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardConnect: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_CONNECT) + { + LLOGLN(0, ("SCardConnect: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + *phCard = GET_UINT32(msg, 0); + *pdwActiveProtocol = GET_UINT32(msg, 4); + status = GET_UINT32(msg, 8); + LLOGLN(10, ("SCardReleaseContext: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, + DWORD dwPreferredProtocols, DWORD dwInitialization, + LPDWORD pdwActiveProtocol) +{ + LLOGLN(0, ("SCardReconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardReconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + LLOGLN(0, ("SCardDisconnect:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardDisconnect: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardBeginTransaction(SCARDHANDLE hCard) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardBeginTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardBeginTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + if (send_message(SCARD_BEGIN_TRANSACTION, msg, 4) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardBeginTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_BEGIN_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardBeginTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardBeginTransaction: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition) +{ + char msg[256]; + int code; + int bytes; + int status; + + LLOGLN(0, ("SCardEndTransaction:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardEndTransaction: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, dwDisposition); + if (send_message(SCARD_BEGIN_TRANSACTION, msg, 8) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, send_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 256; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardEndTransaction: error, get_message")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if ((code != SCARD_BEGIN_TRANSACTION) || (bytes != 4)) + { + LLOGLN(0, ("SCardEndTransaction: error, bad code")); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + status = GET_UINT32(msg, 0); + LLOGLN(10, ("SCardEndTransaction: got status 0x%8.8x", status)); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, + LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, + LPDWORD pcbAtrLen) +{ + LLOGLN(0, ("SCardStatus:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardStatus: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, + LPSCARD_READERSTATE rgReaderStates, DWORD cReaders) +{ + char *msg; + int bytes; + int code; + int index; + int offset; + int str_len; + int status; + + LLOGLN(0, ("SCardGetStatusChange:")); + LLOGLN(10, (" dwTimeout %d cReaders %d", dwTimeout, cReaders)); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetStatusChange: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hContext); + SET_UINT32(msg, 4, dwTimeout); + SET_UINT32(msg, 8, cReaders); + offset = 12; + for (index = 0; index < cReaders; index++) + { + str_len = strlen(rgReaderStates[index].szReader); + str_len = LMIN(str_len, 99); + memset(msg + offset, 0, 100); + memcpy(msg + offset, rgReaderStates[index].szReader, str_len); + offset += 100; + LLOGLN(10, (" in dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwCurrentState); + offset += 4; + LLOGLN(10, (" in dwEventState %d", rgReaderStates[index].dwEventState)); + SET_UINT32(msg, offset, rgReaderStates[index].dwEventState); + offset += 4; + LLOGLN(10, (" in cbAtr %d", rgReaderStates[index].cbAtr)); + SET_UINT32(msg, offset, rgReaderStates[index].cbAtr); + offset += 4; + memset(msg + offset, 0, 36); + memcpy(msg + offset, rgReaderStates[index].rgbAtr, 33); + offset += 36; + } + pthread_mutex_lock(&g_mutex); + if (send_message(SCARD_GET_STATUS_CHANGE, msg, offset) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardGetStatusChange: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_GET_STATUS_CHANGE) + { + LLOGLN(0, ("SCardGetStatusChange: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + cReaders = GET_UINT32(msg, 0); + offset = 4; + LLOGLN(10, ("SCardGetStatusChange: got back cReaders %d", cReaders)); + for (index = 0; index < cReaders; index++) + { + rgReaderStates[index].dwCurrentState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwCurrentState %d", rgReaderStates[index].dwCurrentState)); + rgReaderStates[index].dwEventState = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out dwEventState %d", rgReaderStates[index].dwEventState)); + rgReaderStates[index].cbAtr = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, (" out cbAtr %d", rgReaderStates[index].cbAtr)); + memcpy(rgReaderStates[index].rgbAtr, msg + offset, 33); + offset += 36; + } + status = GET_UINT32(msg, offset); + offset += 4; + free(msg); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, + DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, + LPDWORD lpBytesReturned) +{ + LLOGLN(0, ("SCardControl:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardControl: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + LLOGLN(0, ("SCardControl: dwControlCode %d", dwControlCode)); + LLOGLN(0, ("SCardControl: cbSendLength %d", cbSendLength)); + LLOGLN(0, ("SCardControl: cbRecvLength %d", cbRecvLength)); + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, + SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, + LPDWORD pcbRecvLength) +{ + char *msg; + int bytes; + int code; + int offset; + int status; + + LLOGLN(0, ("SCardTransmit:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardTransmit: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + LLOGLN(0, ("SCardTransmit: cbSendLength %d", cbSendLength)); + + msg = (char *) malloc(8192); + SET_UINT32(msg, 0, hCard); + SET_UINT32(msg, 4, pioSendPci->dwProtocol); + SET_UINT32(msg, 8, pioSendPci->cbPciLength); + SET_UINT32(msg, 12, cbSendLength); + offset = 16; + memcpy(msg + 16, pbSendBuffer, cbSendLength); + offset += cbSendLength; + SET_UINT32(msg, offset, *pcbRecvLength); + offset += 4; + pthread_mutex_lock(&g_mutex); + + if (send_message(SCARD_TRANSMIT, msg, offset) != 0) + { + LLOGLN(0, ("SCardTransmit: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardTransmit: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_TRANSMIT) + { + LLOGLN(0, ("SCardTransmit: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, + LPDWORD pcchGroups) +{ + LLOGLN(0, ("SCardListReaderGroups:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaderGroups: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, + LPDWORD pcchReaders) +{ + char* msg; + char* reader_names; + int reader_names_index; + int code; + int bytes; + int num_readers; + int status; + int offset; + int index; + char reader[100]; + + LLOGLN(0, ("SCardListReaders:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardListReaders: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + msg = (char *) malloc(8192); + pthread_mutex_lock(&g_mutex); + SET_UINT32(msg, 0, hContext); + if (send_message(SCARD_LIST_READERS, msg, 4) != 0) + { + LLOGLN(0, ("SCardListReaders: error, send_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + bytes = 8192; + if (get_message(&code, msg, &bytes) != 0) + { + LLOGLN(0, ("SCardListReaders: error, get_message")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + if (code != SCARD_LIST_READERS) + { + LLOGLN(0, ("SCardListReaders: error, bad code")); + free(msg); + pthread_mutex_unlock(&g_mutex); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_unlock(&g_mutex); + offset = 0; + num_readers = GET_UINT32(msg, offset); + offset += 4; + LLOGLN(10, ("hi - mszReaders %p pcchReaders %p num_readers %d", mszReaders, pcchReaders, num_readers)); + reader_names = (char *) malloc(8192); + reader_names_index = 0; + for (index = 0; index < num_readers; index++) + { + memcpy(reader, msg + offset, 100); + bytes = strlen(reader); + memcpy(reader_names + reader_names_index, reader, bytes); + reader_names_index += bytes; + reader_names[reader_names_index] = 0; + reader_names_index++; + offset += 100; + LLOGLN(10, ("SCardListReaders: readername %s", reader)); + } + reader_names[reader_names_index] = 0; + reader_names_index++; + status = GET_UINT32(msg, offset); + offset += 4; + if (pcchReaders != 0) + { + *pcchReaders = reader_names_index; + } + if (mszReaders != 0) + { + memcpy(mszReaders, reader_names, reader_names_index); + } + free(msg); + free(reader_names); + return status; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem) +{ + LLOGLN(0, ("SCardFreeMemory:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardFreeMemory: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardCancel(SCARDCONTEXT hContext) +{ + LLOGLN(0, ("SCardCancel:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardCancel: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, + LPDWORD pcbAttrLen) +{ + LLOGLN(0, ("SCardGetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardGetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +PCSC_API LONG +SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, + DWORD cbAttrLen) +{ + LLOGLN(0, ("SCardSetAttrib:")); + if (g_sck == -1) + { + LLOGLN(0, ("SCardSetAttrib: error, not connected")); + return SCARD_F_INTERNAL_ERROR; + } + pthread_mutex_lock(&g_mutex); + pthread_mutex_unlock(&g_mutex); + return SCARD_S_SUCCESS; +} + +/*****************************************************************************/ +char * +pcsc_stringify_error(const long code) +{ + switch (code) + { + case SCARD_S_SUCCESS: + snprintf(g_error_str, 511, "Command successful."); + break; + case SCARD_F_INTERNAL_ERROR: + snprintf(g_error_str, 511, "Internal error."); + break; + default: + snprintf(g_error_str, 511, "error 0x%8.8x", (int)code); + break; + } + g_error_str[511] = 0; + return g_error_str; +} diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index cfa3c5de..fb1075c6 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -19,15 +19,24 @@ /* window manager info http://www.freedesktop.org/wiki/Specifications/wm-spec + + rail + [MS-RDPERP]: Remote Desktop Protocol: + Remote Programs Virtual Channel Extension + http://msdn.microsoft.com/en-us/library/cc242568(v=prot.20).aspx */ #include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> +#include <X11/cursorfont.h> #include "chansrv.h" #include "rail.h" #include "xcommon.h" #include "log.h" #include "os_calls.h" #include "thread_calls.h" +#include "list.h" extern int g_rail_chan_id; /* in chansrv.c */ extern int g_display_num; /* in chansrv.c */ @@ -41,11 +50,43 @@ extern Screen *g_screen; /* in xcommon.c */ extern Window g_root_window; /* in xcommon.c */ extern Atom g_wm_delete_window_atom; /* in xcommon.c */ extern Atom g_wm_protocols_atom; /* in xcommon.c */ +extern Atom g_utf8_string; /* in xcommon.c */ +extern Atom g_net_wm_name; /* in xcommon.c */ +extern Atom g_wm_state; /* in xcommon.c */ + +static Atom g_rwd_atom = 0; int g_rail_up = 0; /* for rail_is_another_wm_running */ static int g_rail_running = 1; +/* list of valid rail windows */ +static struct list* g_window_list = 0; + +static int g_got_focus = 0; +static int g_focus_counter = 0; +static Window g_focus_win = 0; + +static int g_xrr_event_base = 0; /* non zero means we got extension */ + +static Cursor g_default_cursor = 0; + +/* used in valid field of struct rail_window_data */ +#define RWD_X (1 << 0) +#define RWD_Y (1 << 1) +#define RWD_WIDTH (1 << 2) +#define RWD_HEIGHT (1 << 3) +#define RWD_TITLE (1 << 4) + +struct rail_window_data +{ + int valid; /* bits for which fields are valid */ + int x; + int y; + int width; + int height; + int title_crc; /* crc of title for compare */ +}; /* Indicates a Client Execute PDU from client to server. */ #define TS_RAIL_ORDER_EXEC 0x0001 @@ -101,6 +142,133 @@ static int g_rail_running = 1; /* Perform the default action of the window's system menu. */ #define SC_DEFAULT 0xF160 +/* for tooltips */ +#define RAIL_STYLE_TOOLTIP (0x80000000) +#define RAIL_EXT_STYLE_TOOLTIP (0x00000080 | 0x00000008) + +/* for normal desktop windows */ +#define RAIL_STYLE_NORMAL (0x00C00000 | 0x00080000 | 0x00040000 | 0x00010000 | 0x00020000) +#define RAIL_EXT_STYLE_NORMAL (0x00040000) + +/* for dialogs */ +#define RAIL_STYLE_DIALOG (0x80000000) +#define RAIL_EXT_STYLE_DIALOG (0x00040000) + +static int APP_CC rail_win_get_state(Window win); +static int APP_CC rail_create_window(Window window_id, Window owner_id); +static int APP_CC rail_win_set_state(Window win, unsigned long state); +static int APP_CC rail_show_window(Window window_id, int show_state); +static int APP_CC rail_win_send_text(Window win); + +/*****************************************************************************/ +static int APP_CC +rail_send_key_esc(int window_id) +{ + XEvent event; + + g_memset(&event, 0, sizeof(event)); + event.type = KeyPress; + event.xkey.same_screen = True; + event.xkey.root = g_root_window; + event.xkey.window = window_id; + event.xkey.keycode = 9; + XSendEvent(g_display, window_id, True, 0xfff, &event); + event.type = KeyRelease; + XSendEvent(g_display, window_id, True, 0xfff, &event); + return 0; +} + +/*****************************************************************************/ +static struct rail_window_data* APP_CC +rail_get_window_data(Window window) +{ + int bytes; + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_return; + unsigned long bytes_after_return; + unsigned char* prop_return; + struct rail_window_data* rv; + + LOG(10, ("chansrv::rail_get_window_data:")); + rv = 0; + actual_type_return = 0; + actual_format_return = 0; + nitems_return = 0; + prop_return = 0; + bytes = sizeof(struct rail_window_data); + XGetWindowProperty(g_display, window, g_rwd_atom, 0, bytes, 0, + XA_STRING, &actual_type_return, + &actual_format_return, &nitems_return, + &bytes_after_return, &prop_return); + if (prop_return == 0) + { + return 0; + } + if (nitems_return == bytes) + { + rv = (struct rail_window_data*)prop_return; + } + return rv; +} + +/*****************************************************************************/ +static int APP_CC +rail_set_window_data(Window window, struct rail_window_data* rwd) +{ + int bytes; + + bytes = sizeof(struct rail_window_data); + XChangeProperty(g_display, window, g_rwd_atom, XA_STRING, 8, + PropModeReplace, (unsigned char*)rwd, bytes); + return 0; +} + +/*****************************************************************************/ +/* get the rail window data, if not exist, try to create it and return */ +static struct rail_window_data* APP_CC +rail_get_window_data_safe(Window window) +{ + struct rail_window_data* rv; + + rv = rail_get_window_data(window); + if (rv != 0) + { + return rv; + } + rv = g_malloc(sizeof(struct rail_window_data), 1); + rail_set_window_data(window, rv); + g_free(rv); + return rail_get_window_data(window); +} + +/******************************************************************************/ +static int APP_CC +is_window_valid_child_of_root(unsigned int window_id) +{ + int found; + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window *children; + + found = 0; + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + + for (i = 0; i < nchild; i++) + { + if (window_id == children[i]) + { + found = 1; + break; + } + } + + XFree(children); + return found; +} + /*****************************************************************************/ static int APP_CC rail_send_init(void) @@ -163,6 +331,11 @@ rail_is_another_wm_running(void) int APP_CC rail_init(void) { + int dummy; + int ver_maj; + int ver_min; + Status st; + LOG(10, ("chansrv::rail_init:")); xcommon_init(); @@ -171,9 +344,34 @@ rail_init(void) log_message(LOG_LEVEL_ERROR, "rail_init: another window manager " "is running"); } - + list_delete(g_window_list); + g_window_list = list_create(); rail_send_init(); g_rail_up = 1; + g_rwd_atom = XInternAtom(g_display, "XRDP_RAIL_WINDOW_DATA", 0); + + if (!XRRQueryExtension(g_display, &g_xrr_event_base, &dummy)) + { + g_xrr_event_base = 0; + log_message(LOG_LEVEL_ERROR, "rail_init: RandR extension not found"); + } + + if (g_xrr_event_base > 0) + { + LOG(0, ("rail_init: found RandR entension")); + st = XRRQueryVersion(g_display, &ver_maj, &ver_min); + if (st) + { + LOG(0, ("rail_init: RandR version major %d minor %d", ver_maj, ver_min)); + } + XRRSelectInput(g_display, g_root_window, RRScreenChangeNotifyMask); + } + + if (g_default_cursor == 0) + { + g_default_cursor = XCreateFontCursor(g_display, XC_left_ptr); + XDefineCursor(g_display, g_root_window, g_default_cursor); + } return 0; } @@ -183,6 +381,8 @@ rail_deinit(void) { if (g_rail_up) { + list_delete(g_window_list); + g_window_list = 0; /* no longer window manager */ XSelectInput(g_display, g_root_window, 0); g_rail_up = 0; @@ -270,26 +470,173 @@ rail_process_exec(struct stream *s, int size) return 0; } +/******************************************************************************/ +static int APP_CC +rail_win_popdown(void) +{ + int rv = 0; + int i; + unsigned int nchild; + Window r; + Window p; + Window* children; + XWindowAttributes window_attributes; + + /* + * Check the tree of current existing X windows and dismiss + * the managed rail popups by simulating a esc key, so + * that the requested window can be closed properly. + */ + + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + for (i = nchild - 1; i >= 0; i--) + { + XGetWindowAttributes(g_display, children[i], &window_attributes); + if (window_attributes.override_redirect && + window_attributes.map_state == IsViewable && + list_index_of(g_window_list, children[i]) >= 0) + { + LOG(10, (" dismiss pop up 0x%8.8x", children[i])); + rail_send_key_esc(children[i]); + rv = 1; + } + } + + XFree(children); + return rv; +} + +/******************************************************************************/ +static int APP_CC +rail_close_window(int window_id) +{ + XEvent ce; + + LOG(0, ("chansrv::rail_close_window:")); + + rail_win_popdown(); + + g_memset(&ce, 0, sizeof(ce)); + ce.xclient.type = ClientMessage; + ce.xclient.message_type = g_wm_protocols_atom; + ce.xclient.display = g_display; + ce.xclient.window = window_id; + ce.xclient.format = 32; + ce.xclient.data.l[0] = g_wm_delete_window_atom; + ce.xclient.data.l[1] = CurrentTime; + XSendEvent(g_display, window_id, False, NoEventMask, &ce); + + return 0; +} + +/*****************************************************************************/ +void DEFAULT_CC +my_timoeut(void* data) +{ + LOG(10, ("my_timoeut: g_got_focus %d", g_got_focus)); + if (g_focus_counter == (int)(long)data) + { + LOG(10, ("my_timoeut: g_focus_counter %d", g_focus_counter)); + rail_win_popdown(); + } +} + /*****************************************************************************/ static int APP_CC rail_process_activate(struct stream *s, int size) { int window_id; int enabled; + int index; + XWindowAttributes window_attributes; + Window transient_for = 0; LOG(10, ("chansrv::rail_process_activate:")); in_uint32_le(s, window_id); in_uint8(s, enabled); + + index = list_index_of(g_window_list, window_id); + if (index < 0) + { + LOG(10, ("chansrv::rail_process_activate: window 0x%8.8x not in list", + window_id)); + return 0; + } + + g_focus_counter++; + g_got_focus = enabled; LOG(10, (" window_id 0x%8.8x enabled %d", window_id, enabled)); + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (enabled) { + if (g_focus_win == window_id) + { + /* In case that window is unmapped upon minimization and not yet mapped*/ + XMapWindow(g_display, window_id); + } + else + { + rail_win_popdown(); + if (window_attributes.map_state != IsViewable) + { + /* In case that window is unmapped upon minimization and not yet mapped */ + XMapWindow(g_display, window_id); + } + XGetTransientForHint(g_display, window_id, &transient_for); + if (transient_for > 0) + { + /* Owner window should be raised up as well */ + XRaiseWindow(g_display, transient_for); + } + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + } LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); XRaiseWindow(g_display, window_id); LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + } else { + XWindowAttributes window_attributes; + XGetWindowAttributes(g_display, window_id, &window_attributes); + + LOG(10, (" window attributes: override_redirect %d", + window_attributes.override_redirect)); + add_timeout(200, my_timoeut, (void*)(long)g_focus_counter); } + return 0; +} +/*****************************************************************************/ +static int APP_CC +rail_restore_windows(void) +{ + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window* children; + + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + for (i = 0; i < nchild; i++) + { + XWindowAttributes window_attributes; + XGetWindowAttributes(g_display, children[i], &window_attributes); + if (!window_attributes.override_redirect) + { + if (window_attributes.map_state == IsViewable) + { + rail_win_set_state(children[i], 0x0); /* WithdrawnState */ + rail_create_window(children[i], g_root_window); + rail_win_set_state(children[i], 0x1); /* NormalState */ + rail_win_send_text(children[i]); + } + } + } + XFree(children); return 0; } @@ -302,25 +649,173 @@ rail_process_system_param(struct stream *s, int size) LOG(10, ("chansrv::rail_process_system_param:")); in_uint32_le(s, system_param); LOG(10, (" system_param 0x%8.8x", system_param)); + /* + * Ask client to re-create the existing rail windows. This is supposed + * to be done after handshake and client is initialised properly, we + * consider client is ready when it sends "SET_WORKAREA" sysparam. + */ + if (system_param == 0x0000002F) /*SPI_SET_WORK_AREA*/ + { + LOG(10, (" restore rail windows")); + rail_restore_windows(); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_get_property(Display* display, Window target, Atom type, Atom property, + unsigned char** data, unsigned long* count) +{ + Atom atom_return; + int size; + unsigned long nitems, bytes_left; + char* prop_name; + + int ret = XGetWindowProperty(display, target, property, + 0l, 1l, False, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if ((ret != Success || nitems < 1) && atom_return == None) + { + prop_name = XGetAtomName(g_display, property); + LOG(10, (" rail_get_property %s: failed", prop_name)); + XFree(prop_name); + return 1; + } + + if (bytes_left != 0) + { + XFree(*data); + unsigned long remain = ((size / 8) * nitems) + bytes_left; + ret = XGetWindowProperty(g_display, target, + property, 0l, remain, False, + atom_return, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success) + { + return 1; + } + } + + *count = nitems; return 0; } +/*****************************************************************************/ +static int APP_CC +rail_win_get_state(Window win) +{ + unsigned long nitems = 0; + int rv = -1; + char* data = 0; + + rail_get_property(g_display, win, g_wm_state, g_wm_state, + (unsigned char **)&data, + &nitems); + + if (data || nitems > 0) + { + rv = *(unsigned long *)data; + XFree(data); + LOG(10, (" rail_win_get_state: %d", rv)); + } + + return rv; +} + +/*****************************************************************************/ +static int APP_CC +rail_win_set_state(Window win, unsigned long state) +{ + int old_state; + unsigned long data[2] = { state, None }; + + LOG(10, (" rail_win_set_state: %d", state)); + /* check whether WM_STATE exists */ + old_state = rail_win_get_state(win); + if (old_state == -1) + { + /* create WM_STATE property */ + XChangeProperty(g_display, win, g_wm_state, g_wm_state, 32, PropModeAppend, + (unsigned char *)data, 2); + LOG(10, (" rail_win_set_state: create WM_STATE property")); + } + else + { + XChangeProperty(g_display, win, g_wm_state, g_wm_state, 32, PropModeReplace, + (unsigned char *)data, 2); + } + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_win_get_text(Window win, char **data) +{ + int ret = 0; + int i = 0; + unsigned long nitems = 0; + + ret = rail_get_property(g_display, win, g_utf8_string, g_net_wm_name, + (unsigned char **)data, &nitems); + if (ret != 0) + { + /* _NET_WM_NAME isn't set, use WM_NAME (XFetchName) instead */ + XFetchName(g_display, win, data); + } + + if (data) + { + char *ptr = *data; + for (; ptr != NULL; i++) + { + if (ptr[i] == '\0') + { + break; + } + } + } + + return i; +} + /******************************************************************************/ static int APP_CC -rail_close_window(int window_id) +rail_minmax_window(int window_id, int max) { - XEvent ce; + LOG(10, ("chansrv::rail_minmax_window 0x%8.8x:", window_id)); + if (max) + { + + } else { + XUnmapWindow(g_display, window_id); + /* change window state to IconicState (3) */ + rail_win_set_state(window_id, 0x3); + /* + * TODO dismiss popups opened so far + */ + } + return 0; +} - LOG(0, ("chansrv::rail_close_window:")); - g_memset(&ce, 0, sizeof(ce)); - ce.xclient.type = ClientMessage; - ce.xclient.message_type = g_wm_protocols_atom; - ce.xclient.display = g_display; - ce.xclient.window = window_id; - ce.xclient.format = 32; - ce.xclient.data.l[0] = g_wm_delete_window_atom; - ce.xclient.data.l[1] = CurrentTime; - XSendEvent(g_display, window_id, False, NoEventMask, &ce); +/*****************************************************************************/ +static int APP_CC +rail_restore_window(int window_id) +{ + XWindowAttributes window_attributes; + + LOG(10, ("chansrv::rail_restore_window 0x%8.8x:", window_id)); + XGetWindowAttributes(g_display, window_id, &window_attributes); + if (window_attributes.map_state != IsViewable) + { + XMapWindow(g_display, window_id); + } + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + return 0; } @@ -330,11 +825,20 @@ rail_process_system_command(struct stream *s, int size) { int window_id; int command; + int index; LOG(10, ("chansrv::rail_process_system_command:")); in_uint32_le(s, window_id); in_uint16_le(s, command); + index = list_index_of(g_window_list, window_id); + if (index < 0) + { + LOG(10, ("chansrv::rail_process_system_command: window 0x%8.8x not in list", + window_id)); + return 0; + } + switch (command) { case SC_SIZE: @@ -345,6 +849,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_MINIMIZE: LOG(10, (" window_id 0x%8.8x SC_MINIMIZE", window_id)); + rail_minmax_window(window_id, 0); break; case SC_MAXIMIZE: LOG(10, (" window_id 0x%8.8x SC_MAXIMIZE", window_id)); @@ -358,6 +863,7 @@ rail_process_system_command(struct stream *s, int size) break; case SC_RESTORE: LOG(10, (" window_id 0x%8.8x SC_RESTORE", window_id)); + rail_restore_window(window_id); break; case SC_DEFAULT: LOG(10, (" window_id 0x%8.8x SC_DEFAULT", window_id)); @@ -409,16 +915,30 @@ rail_process_window_move(struct stream *s, int size) int top; int right; int bottom; + tsi16 si16; + struct rail_window_data* rwd; LOG(10, ("chansrv::rail_process_window_move:")); in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); - in_uint16_le(s, right); - in_uint16_le(s, bottom); + in_uint16_le(s, si16); + left = si16; + in_uint16_le(s, si16); + top = si16; + in_uint16_le(s, si16); + right = si16; + in_uint16_le(s, si16); + bottom = si16; LOG(10, (" window_id 0x%8.8x left %d top %d right %d bottom %d width %d height %d", window_id, left, top, right, bottom, right - left, bottom - top)); XMoveResizeWindow(g_display, window_id, left, top, right - left, bottom - top); + rwd = (struct rail_window_data*) + g_malloc(sizeof(struct rail_window_data), 1); + rwd->x = left; + rwd->y = top; + rwd->width = right - left; + rwd->height = bottom - top; + rail_set_window_data(window_id, rwd); + g_free(rwd); return 0; } @@ -431,13 +951,16 @@ rail_process_local_move_size(struct stream *s, int size) int move_size_type; int pos_x; int pos_y; + tsi16 si16; LOG(10, ("chansrv::rail_process_local_move_size:")); in_uint32_le(s, window_id); in_uint16_le(s, is_move_size_start); in_uint16_le(s, move_size_type); - in_uint16_le(s, pos_x); - in_uint16_le(s, pos_y); + in_uint16_le(s, si16); + pos_x = si16; + in_uint16_le(s, si16); + pos_y = si16; LOG(10, (" window_id 0x%8.8x is_move_size_start %d move_size_type %d " "pos_x %d pos_y %d", window_id, is_move_size_start, move_size_type, pos_x, pos_y)); @@ -472,11 +995,14 @@ rail_process_sys_menu(struct stream *s, int size) int window_id; int left; int top; + tsi16 si16; LOG(10, ("chansrv::rail_process_sys_menu:")); in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); + in_uint16_le(s, si16); + left = si16; + in_uint16_le(s, si16); + top = si16; LOG(10, (" window_id 0x%8.8x left %d top %d", window_id, left, top)); return 0; } @@ -588,14 +1114,646 @@ rail_data_in(struct stream *s, int chan_id, int chan_flags, int length, return 0; } +static int g_crc_seed = 0xffffffff; +static int g_crc_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#define CRC_START(in_crc) (in_crc) = g_crc_seed +#define CRC_PASS(in_pixel, in_crc) \ + (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) +#define CRC_END(in_crc) (in_crc) = ((in_crc) ^ g_crc_seed) + +/*****************************************************************************/ +static int +get_string_crc(const char* text) +{ + int index; + int crc; + + CRC_START(crc); + index = 0; + while (text[index] != 0) + { + CRC_PASS(text[index], crc); + index++; + } + CRC_END(crc); + return crc; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +static int APP_CC +rail_win_send_text(Window win) +{ + char* data = 0; + struct stream* s; + int len = 0; + int flags; + int crc; + struct rail_window_data* rwd; + + len = rail_win_get_text(win, &data); + rwd = rail_get_window_data_safe(win); + if (rwd != 0) + { + if (data != 0) + { + if (rwd->valid & RWD_TITLE) + { + crc = get_string_crc(data); + if (rwd->title_crc == crc) + { + LOG(10, ("chansrv::rail_win_send_text: skipping, title not changed")); + XFree(data); + XFree(rwd); + return 0; + } + } + } + } + else + { + LOG(0, ("chansrv::rail_win_send_text: error rail_get_window_data_safe failed")); + return 1; + } + if (data && len > 0) { + LOG(10, ("chansrv::rail_win_send_text: 0x%8.8x text %s length %d", + win, data, len)); + make_stream(s); + init_stream(s, 1024); + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_FIELD_TITLE; + out_uint32_le(s, 8); /* update title info */ + out_uint32_le(s, win); /* window id */ + out_uint32_le(s, flags); /* flags */ + out_uint32_le(s, len); /* title size */ + out_uint8a(s, data, len); /* title */ + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + /* update rail window data */ + rwd->valid |= RWD_TITLE; + crc = get_string_crc(data); + rwd->title_crc = crc; + rail_set_window_data(win, rwd); + } + if (data != 0) + { + XFree(data); + } + XFree(rwd); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_destroy_window(Window window_id) +{ + struct stream *s; + + LOG(10, ("chansrv::rail_destroy_window 0x%8.8x", window_id)); + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 4); /* destroy_window */ + out_uint32_le(s, window_id); + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_show_window(Window window_id, int show_state) +{ + int flags; + struct stream* s; + + LOG(10, ("chansrv::rail_show_window 0x%8.8x 0x%x", window_id, show_state)); + make_stream(s); + init_stream(s, 1024); + + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_FIELD_SHOW; + out_uint32_le(s, 6); /* show_window */ + out_uint32_le(s, window_id); /* window_id */ + out_uint32_le(s, flags); /* flags */ + out_uint32_le(s, show_state); /* show_state */ + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +rail_create_window(Window window_id, Window owner_id) +{ + int x; + int y; + tui32 width; + tui32 height; + tui32 border; + Window root; + tui32 depth; + char* title_bytes = 0; + int title_size = 0; + XWindowAttributes attributes; + int style; + int ext_style; + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + + int flags; + int index; + int crc; + Window transient_for = 0; + struct rail_window_data* rwd; + struct stream* s; + + LOG(10, ("chansrv::rail_create_window 0x%8.8x", window_id)); + + rwd = rail_get_window_data_safe(window_id); + if (rwd == 0) + { + LOG(0, ("chansrv::rail_create_window: error rail_get_window_data_safe failed")); + return 0; + } + XGetGeometry(g_display, window_id, &root, &x, &y, &width, &height, + &border, &depth); + XGetWindowAttributes(g_display, window_id, &attributes); + + LOG(10, (" x %d y %d width %d height %d border_width %d", x, y, width, + height, border)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + LOG(10, (" create new window")); + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_NEW; + list_add_item(g_window_list, window_id); + } + else + { + LOG(10, (" update existing window")); + flags = WINDOW_ORDER_TYPE_WINDOW; + } + + title_size = rail_win_get_text(window_id, &title_bytes); + + XGetTransientForHint(g_display, window_id, &transient_for); + + if (attributes.override_redirect) + { + style = RAIL_STYLE_TOOLTIP; + ext_style = RAIL_EXT_STYLE_TOOLTIP; + } + else if (transient_for > 0) + { + style = RAIL_STYLE_DIALOG; + ext_style = RAIL_EXT_STYLE_DIALOG; + owner_id = transient_for; + } + else + { + style = RAIL_STYLE_NORMAL; + ext_style = RAIL_EXT_STYLE_NORMAL; + } + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 2); /* create_window */ + out_uint32_le(s, window_id); /* window_id */ + out_uint32_le(s, owner_id); /* owner_window_id */ + flags |= WINDOW_ORDER_FIELD_OWNER; + out_uint32_le(s, style); /* style */ + out_uint32_le(s, ext_style); /* extended_style */ + flags |= WINDOW_ORDER_FIELD_STYLE; + out_uint32_le(s, 0x05); /* show_state */ + flags |= WINDOW_ORDER_FIELD_SHOW; + if (title_size > 0) + { + out_uint16_le(s, title_size); /* title_size */ + out_uint8a(s, title_bytes, title_size); /* title */ + rwd->valid |= RWD_TITLE; + crc = get_string_crc(title_bytes); + rwd->title_crc = crc; + } + else + { + out_uint16_le(s, 5); /* title_size */ + out_uint8a(s, "title", 5); /* title */ + rwd->valid |= RWD_TITLE; + rwd->title_crc = 0; + } + LOG(10, (" set title info %d", title_size)); + flags |= WINDOW_ORDER_FIELD_TITLE; + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, width); /* client_area_width */ + out_uint32_le(s, height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, x); /* window_offset_x */ + out_uint32_le(s, y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, width); /* window_width */ + out_uint32_le(s, height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, width); /* right */ + out_uint16_le(s, height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, x); /* visible_offset_x */ + out_uint32_le(s, y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, width); /* right */ + out_uint16_le(s, height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + XFree(title_bytes); + rail_set_window_data(window_id, rwd); + XFree(rwd); + return 0; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +int APP_CC +rail_configure_request_window(XConfigureRequestEvent* config) +{ + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + int flags; + int index; + int window_id; + int mask; + int resized = 0; + struct rail_window_data* rwd; + + struct stream* s; + + window_id = config->window; + mask = config->value_mask; + LOG(10, ("chansrv::rail_configure_request_window: mask %d", mask)); + if (mask & CWStackMode) + { + LOG(10, ("chansrv::rail_configure_request_window: CWStackMode " + "detail 0x%8.8x above 0x%8.8x", config->detail, config->above)); + if (config->detail == Above) + { + LOG(10, ("chansrv::rail_configure_request_window: bring to front " + "window_id 0x%8.8x", window_id)); + /* 0x05 - Show the window in its current size and position. */ + rail_show_window(window_id, 5); + } + } + rwd = rail_get_window_data(window_id); + if (rwd == 0) + { + rwd = (struct rail_window_data*)g_malloc(sizeof(struct rail_window_data), 1); + rwd->x = config->x; + rwd->y = config->y; + rwd->width = config->width; + rwd->height = config->height; + rwd->valid |= RWD_X | RWD_Y | RWD_WIDTH | RWD_HEIGHT; + rail_set_window_data(window_id, rwd); + g_free(rwd); + return 0; + } + if (!resized) + { + if (mask & CWX) + { + if (rwd->valid & RWD_X) + { + if (rwd->x != config->x) + { + resized = 1; + rwd->x = config->x; + } + } + else + { + resized = 1; + rwd->x = config->x; + rwd->valid |= RWD_X; + } + } + } + if (!resized) + { + if (mask & CWY) + { + if (rwd->valid & RWD_Y) + { + if (rwd->y != config->y) + { + resized = 1; + rwd->y = config->y; + } + } + else + { + resized = 1; + rwd->y = config->y; + rwd->valid |= RWD_Y; + } + } + } + if (!resized) + { + if (mask & CWWidth) + { + if (rwd->valid & RWD_WIDTH) + { + if (rwd->width != config->width) + { + resized = 1; + rwd->width = config->width; + } + } + else + { + resized = 1; + rwd->width = config->width; + rwd->valid |= RWD_WIDTH; + } + } + } + if (!resized) + { + if (mask & CWHeight) + { + if (rwd->valid & RWD_HEIGHT) + { + if (rwd->height != config->height) + { + resized = 1; + rwd->height = config->height; + } + } + else + { + resized = 1; + rwd->height = config->height; + rwd->valid |= RWD_HEIGHT; + } + } + } + if (resized) + { + rail_set_window_data(window_id, rwd); + XFree(rwd); + } + else + { + XFree(rwd); + return 0; + } + + LOG(10, ("chansrv::rail_configure_request_window: 0x%8.8x", window_id)); + + + LOG(10, (" x %d y %d width %d height %d border_width %d", config->x, + config->y, config->width, config->height, config->border_width)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + /* window isn't mapped yet */ + LOG(0, ("chansrv::rail_configure_request_window: window not mapped")); + return 0; + } + + flags = WINDOW_ORDER_TYPE_WINDOW; + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 10); /* configure_window */ + out_uint32_le(s, window_id); /* window_id */ + + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, config->width); /* client_area_width */ + out_uint32_le(s, config->height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, config->x); /* window_offset_x */ + out_uint32_le(s, config->y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, config->width); /* window_width */ + out_uint32_le(s, config->height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, config->x); /* visible_offset_x */ + out_uint32_le(s, config->y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns 0, event handled, 1 unhandled */ +int APP_CC +rail_configure_window(XConfigureEvent *config) +{ + int num_window_rects = 1; + int num_visibility_rects = 1; + int i = 0; + int flags; + int index; + int window_id; + + struct stream* s; + + window_id = config->window; + + LOG(10, ("chansrv::rail_configure_window 0x%8.8x", window_id)); + + + LOG(10, (" x %d y %d width %d height %d border_width %d", config->x, + config->y, config->width, config->height, config->border_width)); + + index = list_index_of(g_window_list, window_id); + if (index == -1) + { + /* window isn't mapped yet */ + return 0; + } + + flags = WINDOW_ORDER_TYPE_WINDOW; + + make_stream(s); + init_stream(s, 1024); + + out_uint32_le(s, 10); /* configure_window */ + out_uint32_le(s, window_id); /* window_id */ + + out_uint32_le(s, 0); /* client_offset_x */ + out_uint32_le(s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(s, config->width); /* client_area_width */ + out_uint32_le(s, config->height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(s, 0); /* rp_content */ + out_uint32_le(s, g_root_window); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(s, config->x); /* window_offset_x */ + out_uint32_le(s, config->y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(s, 0); /* window_client_delta_x */ + out_uint32_le(s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(s, config->width); /* window_width */ + out_uint32_le(s, config->height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(s, num_window_rects); /* num_window_rects */ + for (i = 0; i < num_window_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(s, config->x); /* visible_offset_x */ + out_uint32_le(s, config->y); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(s, num_visibility_rects); /* num_visibility_rects */ + for (i = 0; i < num_visibility_rects; i++) + { + out_uint16_le(s, 0); /* left */ + out_uint16_le(s, 0); /* top */ + out_uint16_le(s, config->width); /* right */ + out_uint16_le(s, config->height); /* bottom */ + } + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + out_uint32_le(s, flags); /*flags*/ + + s_mark_end(s); + send_rail_drawing_orders(s->data, (int)(s->end - s->data)); + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int +rail_desktop_resize(lxevent) +{ + LOG(0, ("rail_desktop_resize:")); + return 0; +} + /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC rail_xevent(void *xevent) { XEvent *lxevent; + XEvent lastevent; XWindowChanges xwc; int rv; + int index; + XWindowAttributes wnd_attributes; + char* prop_name; LOG(10, ("chansrv::rail_xevent:")); @@ -609,6 +1767,30 @@ rail_xevent(void *xevent) switch (lxevent->type) { + case PropertyNotify: + prop_name = XGetAtomName(g_display, lxevent->xproperty.atom); + LOG(10, (" got PropertyNotify window_id 0x%8.8x %s state new %d", + lxevent->xproperty.window, prop_name, + lxevent->xproperty.state == PropertyNewValue)); + + if (list_index_of(g_window_list, lxevent->xproperty.window) < 0) + { + break; + } + + if (g_strcmp(prop_name, "WM_NAME") == 0 || + g_strcmp(prop_name, "_NET_WM_NAME") == 0) + { + XGetWindowAttributes(g_display, lxevent->xproperty.window, &wnd_attributes); + if (wnd_attributes.map_state == IsViewable) + { + rail_win_send_text(lxevent->xproperty.window); + rv = 0; + } + } + XFree(prop_name); + break; + case ConfigureRequest: LOG(10, (" got ConfigureRequest window_id 0x%8.8x", lxevent->xconfigurerequest.window)); g_memset(&xwc, 0, sizeof(xwc)); @@ -623,31 +1805,118 @@ rail_xevent(void *xevent) lxevent->xconfigurerequest.window, lxevent->xconfigurerequest.value_mask, &xwc); + rail_configure_request_window(&(lxevent->xconfigurerequest)); rv = 0; break; + case CreateNotify: + LOG(10, (" got CreateNotify window 0x%8.8x parent 0x%8.8x", + lxevent->xcreatewindow.window, lxevent->xcreatewindow.parent)); + XSelectInput(g_display, lxevent->xcreatewindow.window, + PropertyChangeMask | StructureNotifyMask | + SubstructureNotifyMask | FocusChangeMask | + EnterWindowMask | LeaveWindowMask); + break; + + case DestroyNotify: + LOG(10, (" got DestroyNotify window 0x%8.8x event 0x%8.8x", + lxevent->xdestroywindow.window, lxevent->xdestroywindow.event)); + if (lxevent->xdestroywindow.window != lxevent->xdestroywindow.event) + { + break; + } + index = list_index_of(g_window_list, lxevent->xdestroywindow.window); + if (index >= 0) + { + rail_destroy_window(lxevent->xdestroywindow.window); + list_remove_item(g_window_list, index); + } + rv = 0; + break; + case MapRequest: - LOG(10, (" got MapRequest")); + LOG(10, (" got MapRequest window 0x%8.8x", lxevent->xmaprequest.window)); XMapWindow(g_display, lxevent->xmaprequest.window); - rv = 0; break; case MapNotify: - LOG(10, (" got MapNotify")); + LOG(10, (" got MapNotify window 0x%8.8x event 0x%8.8x", + lxevent->xmap.window, lxevent->xmap.event)); + if (lxevent->xmap.window != lxevent->xmap.event) + { + break; + } + + if (!is_window_valid_child_of_root(lxevent->xmap.window)) + { + break; + } + + XGetWindowAttributes(g_display, lxevent->xmap.window, &wnd_attributes); + if (wnd_attributes.map_state == IsViewable) + { + rail_create_window(lxevent->xmap.window, lxevent->xmap.event); + if (!wnd_attributes.override_redirect) + { + rail_win_set_state(lxevent->xmap.window, 0x1); /* NormalState */ + rail_win_send_text(lxevent->xmap.window); + } + rv = 0; + } break; case UnmapNotify: - LOG(10, (" got UnmapNotify")); + LOG(10, (" got UnmapNotify 0x%8.8x", lxevent->xunmap.event)); + if (lxevent->xunmap.window != lxevent->xunmap.event) + { + break; + } + if (is_window_valid_child_of_root(lxevent->xunmap.window)) + { + index = list_index_of(g_window_list, lxevent->xunmap.window); + LOG(10, (" window 0x%8.8x is unmapped", lxevent->xunmap.window)); + if (index >= 0) + { + rail_show_window(lxevent->xunmap.window, 0x0); + rv = 0; + } + } break; case ConfigureNotify: - LOG(10, (" got ConfigureNotify")); + LOG(10, (" got ConfigureNotify 0x%8.8x event 0x%8.8x", lxevent->xconfigure.window, + lxevent->xconfigure.event)); + rv = 0; + if (lxevent->xconfigure.event != lxevent->xconfigure.window || + lxevent->xconfigure.override_redirect) + { + break; + } + /* skip dup ConfigureNotify */ + while (XCheckTypedWindowEvent(g_display, + lxevent->xconfigure.window, + ConfigureNotify, &lastevent)) + { + if (lastevent.xconfigure.event == lastevent.xconfigure.window && + lxevent->xconfigure.override_redirect == 0) + { + lxevent = &lastevent; + } + } +#if 0 + rail_configure_window(&(lxevent->xconfigure)); +#endif break; case FocusIn: LOG(10, (" got FocusIn")); + g_focus_win = lxevent->xfocus.window; break; + case FocusOut: + LOG(10, (" got FocusOut")); + break; + case ButtonPress: LOG(10, (" got ButtonPress")); break; @@ -660,6 +1929,39 @@ rail_xevent(void *xevent) LOG(10, (" got LeaveNotify")); break; + case ReparentNotify: + LOG(10, (" got ReparentNotify window 0x%8.8x parent 0x%8.8x " + "event 0x%8.8x x %d y %d overrider redirect %d", + lxevent->xreparent.window, lxevent->xreparent.parent, + lxevent->xreparent.event, lxevent->xreparent.x, + lxevent->xreparent.y, lxevent->xreparent.override_redirect)); + + if (lxevent->xreparent.window != lxevent->xreparent.event) + { + break; + } + if (lxevent->xreparent.parent != g_root_window) + { + index = list_index_of(g_window_list, lxevent->xreparent.window); + if (index >= 0) + { + rail_destroy_window(lxevent->xreparent.window); + list_remove_item(g_window_list, index); + } + } + rv = 0; + break; + + default: + if (g_xrr_event_base > 0) + { + if (lxevent->type == g_xrr_event_base + RRScreenChangeNotify) + { + rail_desktop_resize(lxevent); + rv = 0; + break; + } + } } return rv; diff --git a/sesman/chansrv/rail.h b/sesman/chansrv/rail.h index 7dbcbc5a..3be3a15d 100644 --- a/sesman/chansrv/rail.h +++ b/sesman/chansrv/rail.h @@ -19,6 +19,7 @@ #ifndef _RAIL_H_ #define _RAIL_H_ +#include "../../common/rail.h" #include "arch.h" #include "parse.h" @@ -31,5 +32,6 @@ rail_data_in(struct stream* s, int chan_id, int chan_flags, int length, int total_length); int APP_CC rail_xevent(void* xevent); +int APP_CC rail_request_title(int window_id); #endif diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c index c370479e..2b07b90e 100644 --- a/sesman/chansrv/smartcard.c +++ b/sesman/chansrv/smartcard.c @@ -21,6 +21,7 @@ * smartcard redirection support */ +#include <string.h> #include "os_calls.h" #include "smartcard.h" #include "log.h" @@ -31,6 +32,8 @@ /* * TODO * + * o ensure that all wide calls are handled correctly + * * o need to query client for build number and determine whether we should use * SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN * @@ -60,13 +63,15 @@ #endif #define log_error(_params...) \ +do \ { \ g_write("[%10.10u]: SMART_CARD %s: %d : ERROR: ", \ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ -} +} while (0) #define log_info(_params...) \ +do \ { \ if (LOG_INFO <= LOG_LEVEL) \ { \ @@ -74,9 +79,10 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) #define log_debug(_params...) \ +do \ { \ if (LOG_DEBUG <= LOG_LEVEL) \ { \ @@ -84,7 +90,7 @@ g_time3(), __func__, __LINE__); \ g_writeln (_params); \ } \ -} +} while (0) /* [MS-RDPESC] 3.1.4 */ #define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */ @@ -98,16 +104,19 @@ #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_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup*/ +#define SCARD_IOCTL_GET_STATUS_CHANGE_A 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_GET_STATUS_CHANGE_W 0x000900A4 /* GetStatusChangeW */ #define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */ -#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_A 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_CONNECT_W 0x000900B0 /* ConnectW */ #define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */ #define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */ #define SCARD_IOCTL_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */ #define SCARD_IOCTL_END_TRANSACTION 0x000900C0 /* EndTransaction */ #define SCARD_IOCTL_STATE 0x000900C4 /* State */ -#define SCARD_IOCTL_STATUS 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_A 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_STATUS_W 0x000900CC /* StatusW */ #define SCARD_IOCTL_TRANSMIT 0x000900D0 /* Transmit */ #define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */ #define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */ @@ -120,191 +129,810 @@ #define SCARD_SCOPE_TERMINAL 0x00000001 #define SCARD_SCOPE_SYSTEM 0x00000002 +/* disposition - action to take on card */ +#define SCARD_LEAVE_CARD 0x00000000 +#define SCARD_RESET_CARD 0x00000001 +#define SCARD_UNPOWER_CARD 0x00000002 +#define SCARD_EJECT_CARD 0x00000003 + #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; +/* globals */ +SMARTCARD* smartcards[MAX_SMARTCARDS]; +int g_smartcards_inited = 0; +static tui32 g_device_id = 0; +static int g_scard_index = 0; +/* externs */ extern tui32 g_completion_id; -extern int g_rdpdr_chan_id; /* in chansrv.c */ +extern int g_rdpdr_chan_id; /* in chansrv.c */ + + +/****************************************************************************** +** static functions local to this file ** +******************************************************************************/ +static struct stream * APP_CC scard_make_new_ioctl(IRP *irp, tui32 ioctl); +static int APP_CC scard_add_new_device(tui32 device_id); +static int APP_CC scard_get_free_slot(void); +static void APP_CC scard_release_resources(void); +static void APP_CC scard_send_EstablishContext(IRP* irp, int scope); +static void APP_CC scard_send_ReleaseContext(IRP* irp, tui32 context); +static void APP_CC scard_send_IsContextValid(IRP* irp, tui32 context); +static void APP_CC scard_send_ListReaders(IRP* irp, tui32 context, int wide); + +static void APP_CC scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa); + +static void APP_CC scard_send_Connect(IRP* irp, tui32 context, int wide, + READER_STATE* rs); + +static void APP_CC scard_send_Reconnect(IRP* irp, tui32 context, + tui32 sc_handle, READER_STATE* rs); + +static void APP_CC scard_send_BeginTransaction(IRP* irp, tui32 sc_handle); +static void APP_CC scard_send_EndTransaction(IRP* irp, tui32 sc_handle, + tui32 dwDisposition); +static void APP_CC scard_send_Status(IRP* irp, int wide, tui32 sc_handle); + +static void APP_CC scard_send_Disconnect(IRP* irp, tui32 context, + tui32 sc_handle); + +static int APP_CC scard_send_Transmit(IRP* irp, tui32 sc_handle, + READER_STATE* rs); + +static int APP_CC scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, + READER_STATE* rs); + +static int APP_CC scard_send_Cancel(IRP* irp, tui32 context); + +static int APP_CC scard_send_GetAttrib(IRP* irp, tui32 sc_handle, + READER_STATE* rs); + +/****************************************************************************** +** local callbacks into this module ** +******************************************************************************/ + +static void APP_CC scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + + +static void APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_EndTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); -/* 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(void); -static void scard_release_resources(void); +static void APP_CC scard_handle_Status_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Disconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + + +static void APP_CC scard_handle_Transmit_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Control_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_Cancel_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +static void APP_CC scard_handle_GetAttrib_Return(struct stream *s, IRP *irp, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); /****************************************************************************** -** non static functions ** +** ** +** externally accessible functions, defined in smartcard.h ** +** ** ******************************************************************************/ +/** + *****************************************************************************/ void APP_CC scard_device_announce(tui32 device_id) { + log_debug("entered: device_id=%d", device_id); + + if (g_smartcards_inited) + return; + + g_memset(&smartcards, 0, sizeof(smartcards)); + g_smartcards_inited = 1; + g_device_id = device_id; + g_scard_index = scard_add_new_device(device_id); + + if (g_scard_index < 0) + log_debug("scard_add_new_device failed with DeviceId=%d", g_device_id); + else + log_debug("added smartcard with DeviceId=%d to list", g_device_id); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_get_wait_objs(tbus *objs, int *count, int *timeout) +{ + return scard_pcsc_get_wait_objs(objs, count, timeout); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_check_wait_objs(void) +{ + return scard_pcsc_check_wait_objs(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_init(void) +{ + log_debug("init"); + return scard_pcsc_init(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_deinit(void) +{ + log_debug("deinit"); + return scard_pcsc_deinit(); +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_send_establish_context(struct trans *con, int scope) +{ IRP *irp; - log_debug("entered: device_id=%d", device_id); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EstablishContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_EstablishContext(irp, scope); + + return 0; +} + +/** + * Release a previously established Smart Card context + *****************************************************************************/ +int APP_CC +scard_send_release_context(struct trans *con, tui32 context) +{ + IRP *irp; - if (!g_smartcards_inited) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - g_memset(&smartcards, 0, sizeof(smartcards)); - g_smartcards_inited = 1; + log_error("system out of memory"); + return 1; } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ReleaseContext_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_ReleaseContext(irp, context); + + return 0; +} + +/** + * Checks if a previously established context is still valid + *****************************************************************************/ +int APP_CC +scard_send_is_valid_context(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ if ((irp = devredir_irp_new()) == NULL) { log_error("system out of memory"); - return; + return 1; } - irp->scard_index = scard_add_new_device(device_id); - if (irp->scard_index < 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_IsContextValid_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_IsContextValid(irp, context); + + return 0; +} + +/** + * + *****************************************************************************/ +int APP_CC +scard_send_list_readers(struct trans *con, tui32 context, int wide) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("NOT adding smartcard with DeviceId=%d to list", device_id); - devredir_irp_delete(irp); - return; + log_error("system out of memory"); + return 1; } + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_ListReaders_Return; + irp->user_data = con; - log_debug("added smartcard with DeviceId=%d to list", device_id); + /* send IRP to client */ + scard_send_ListReaders(irp, context, wide); + return 0; +} + +/** + * Send get change in status command + * + * @param con connection to client + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs + *****************************************************************************/ +int APP_CC +scard_send_get_status_change(struct trans *con, tui32 context, int wide, + tui32 timeout, tui32 num_readers, + READER_STATE* rsa) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; irp->CompletionId = g_completion_id++; - irp->DeviceId = device_id; - irp->callback = scard_handle_EstablishContext_Return; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_GetStatusChange_Return; + irp->user_data = con; - scard_send_EstablishContext(irp); - log_debug("leaving"); + /* send IRP to client */ + scard_send_GetStatusChange(irp, context, wide, timeout, num_readers, rsa); + + return 0; } -/****************************************************************************** -** callbacks into this module ** -******************************************************************************/ +/** + * Open a connection to the smart card located in the reader + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs) +{ + IRP *irp; -void APP_CC -scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Connect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Connect(irp, context, wide, rs); + + return 0; +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +int APP_CC +scard_send_reconnect(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs) { - tui32 len; - int tmp; - SMARTCARD *sc; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Reconnect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Reconnect(irp, context, sc_handle, rs); + + return 0; +} + +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +int APP_CC +scard_send_begin_transaction(struct trans *con, tui32 sc_handle) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_BeginTransaction_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_BeginTransaction(irp, sc_handle); + + return 0; +} + +/** + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to establish context - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - sc = smartcards[irp->scard_index]; + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_EndTransaction_Return; + irp->user_data = con; - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + /* send IRP to client */ + scard_send_EndTransaction(irp, sc_handle, dwDisposition); - /* LK_TODO */ - g_hexdump(s->p, len); + return 0; +} - 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); +/** + * Get the status of a connection for a valid smart card reader handle + * + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +int APP_CC +scard_send_status(struct trans *con, int wide, tui32 sc_handle) +{ + IRP *irp; - if (LOG_LEVEL == LOG_DEBUG) + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_debug("dumping context (%d bytes)", sc->Context_len); - g_hexdump(sc->Context, sc->Context_len); + log_error("system out of memory"); + return 1; } - irp->callback = scard_handle_ListReaders_Return; - scard_send_ListReaders(irp, 1); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Status_Return; + irp->user_data = con; - /* LK_TODO need to delete IRP */ - log_debug("leaving"); + /* send IRP to client */ + scard_send_Status(irp, wide, sc_handle); + + return 0; } -void APP_CC -scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus) +/** + * Release a smart card reader handle that was acquired in ConnectA/ConnectW + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +int APP_CC +scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle) { - tui32 len; + IRP *irp; - log_debug("entered"); + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } - /* sanity check */ - if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Disconnect_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Disconnect(irp, context, sc_handle); + + return 0; +} + +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ +int APP_CC +scard_send_transmit(struct trans *con, tui32 sc_handle, READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("DeviceId/CompletionId do not match those in IRP"); - return; + log_error("system out of memory"); + return 1; } - if (IoStatus != 0) + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Transmit_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Transmit(irp, sc_handle, rs); + + return 0; +} + +/** + * Communicate directly with the smart card reader + *****************************************************************************/ +int APP_CC +scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) { - log_error("failed to list readers - device not usable"); - /* LK_TODO delete irp and smartcard entry */ - return; + log_error("system out of memory"); + return 1; } - /* get OutputBufferLen */ - xstream_rd_u32_le(s, len); + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Control_Return; + irp->user_data = con; - /* LK_TODO */ - log_debug("dumping %d bytes", len); - g_hexdump(s->p, len); + /* send IRP to client */ + scard_send_Control(irp, context, sc_handle, rs); - log_debug("leaving"); + return 0; +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ +int APP_CC +scard_send_cancel(struct trans *con, tui32 context) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_Cancel_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_Cancel(irp, context); + + return 0; +} + +/** + * Get reader attributes + *****************************************************************************/ +int APP_CC +scard_send_get_attrib(struct trans *con, tui32 sc_handle, READER_STATE* rs) +{ + IRP *irp; + + /* setup up IRP */ + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return 1; + } + + irp->scard_index = g_scard_index; + irp->CompletionId = g_completion_id++; + irp->DeviceId = g_device_id; + irp->callback = scard_handle_GetAttrib_Return; + irp->user_data = con; + + /* send IRP to client */ + scard_send_GetAttrib(irp, sc_handle, rs); + + return 0; } /****************************************************************************** +** ** ** static functions local to this file ** +** ** ******************************************************************************/ /** + * 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 * APP_CC +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 * 4); + 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 APP_CC +scard_add_new_device(tui32 device_id) +{ + int index; + SMARTCARD *sc; + + if ((index = scard_get_free_slot()) < 0) + { + log_error("scard_get_free_slot failed"); + 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 APP_CC +scard_get_free_slot(void) +{ + 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 APP_CC -scard_send_EstablishContext(IRP *irp) +scard_release_resources(void) +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] != NULL) + { + g_free(smartcards[i]); + smartcards[i] = NULL; + } + } +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_send_EstablishContext(IRP *irp, int scope) { struct stream *s; int bytes; if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_ESTABLISH_CONTEXT)) == NULL) + { + log_error("scard_make_new_ioctl failed"); 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 */ + xstream_wr_u32_le(s, 0x08); /* len */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, scope); /* 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 */ + /* InputBufferLength is number of bytes AFTER 20 byte padding */ *(s->data + 28) = bytes - 56; /* send to client */ @@ -313,11 +941,112 @@ scard_send_EstablishContext(IRP *irp) } /** - * + * Release a previously established Smart Card context + *****************************************************************************/ +static void APP_CC +scard_send_ReleaseContext(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.2 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RELEASE_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 4 bytes len - don't know what this is, zero for now + * 12 bytes unused + * u32 4 bytes context len + * 4 bytes context + */ + + xstream_wr_u32_le(s, 0); + xstream_seek(s, 12); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Checks if a previously established context is still valid *****************************************************************************/ +static void APP_CC +scard_send_IsContextValid(IRP* irp, tui32 context) +{ + /* see [MS-RDPESC] 3.1.4.3 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_IS_VALID_CONTEXT)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 16 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes context len + * u32 4 bytes context + */ + + xstream_wr_u32_le(s, 16); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * + *****************************************************************************/ static void APP_CC -scard_send_ListReaders(IRP *irp, int wide) +scard_send_ListReaders(IRP *irp, tui32 context, int wide) { /* see [MS-RDPESC] 2.2.2.4 */ @@ -332,18 +1061,18 @@ scard_send_ListReaders(IRP *irp, int wide) return; } - ioctl = (wide > 0) ? SCARD_IOCTL_LIST_READERS_W : - SCARD_IOCTL_LIST_READERS_A; + ioctl = (wide) ? 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 */ + xstream_seek(s, 28); /* 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, 4); + xstream_wr_u32_le(s, context); xstream_wr_u32_le(s, 36); /* length of mszGroups */ xstream_wr_u16_le(s, 0x0053); @@ -389,185 +1118,1265 @@ scard_send_ListReaders(IRP *irp, int wide) */ /* - 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 + 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 */ } +/*****************************************************************************/ +static int +align_s(struct stream *s, int bytes) +{ + int i32; + + i32 = (int) (s->p - s->data); + while ((i32 % bytes) != 0) + { + out_uint8s(s, 1); + i32 = (int) (s->p - s->data); + } + return 0; +} + /** - * Crate a new stream and insert specified IOCTL + * Get change in status * - * @param irp information about the I/O - * @param ioctl the IOCTL code + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param timeout timeout in milliseconds, -1 for infinity + * @param num_readers number of entries in rsa + * @param rsa array of READER_STATEs + *****************************************************************************/ +static void APP_CC +scard_send_GetStatusChange(IRP* irp, tui32 context, int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa) +{ + /* see [MS-RDPESC] 2.2.2.11 for ASCII */ + /* see [MS-RDPESC] 2.2.2.12 for Wide char */ + + SMARTCARD* sc; + READER_STATE* rs; + struct stream* s; + tui32 ioctl; + int bytes; + int i; + int len; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_GET_STATUS_CHANGE_W : + SCARD_IOCTL_GET_STATUS_CHANGE_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + xstream_seek(s, 16); /* unused */ + xstream_wr_u32_le(s, timeout); + xstream_wr_u32_le(s, num_readers); + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + xstream_wr_u32_le(s, 0); /* unused */ + + /* insert card reader state */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, rs->current_state); + xstream_wr_u32_le(s, rs->event_state); + xstream_wr_u32_le(s, rs->atr_len); + xstream_copyin(s, rs->atr, 33); + out_uint8s(s, 3); + } + + if (wide) + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + else + { + /* insert card reader names */ + for (i = 0; i < num_readers; i++) + { + rs = &rsa[i]; + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, num_chars); + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + align_s(s, 4); + } + } + + /* 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); +} + +/** + * Send connect command * - * @return stream with IOCTL inserted in it, NULL on error + * @param irp I/O resource pkt + * @param wide TRUE if unicode string + * @param rs reader state *****************************************************************************/ +static void APP_CC +scard_send_Connect(IRP* irp, tui32 context, int wide, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.13 for ASCII */ + /* see [MS-RDPESC] 2.2.2.14 for Wide char */ -static struct stream * APP_CC -scard_make_new_ioctl(IRP *irp, tui32 ioctl) + SMARTCARD* sc; + struct stream* s; + tui32 ioctl; + int bytes; + int len; + int num_chars; + int index; + twchar w_reader_name[100]; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 20 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocols + * xx bytes reader name + * u32 4 bytes context length (len) + * len bytes context + */ + + xstream_seek(s, 20); + xstream_wr_u32_le(s, rs->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); + + /* insert reader name */ + num_chars = g_mbstowcs(w_reader_name, rs->reader_name, 99); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, num_chars); + if (wide) + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u16_le(s, w_reader_name[index]); + } + } + else + { + for (index = 0; index < num_chars; index++) + { + xstream_wr_u8(s, w_reader_name[index]); + } + } + align_s(s, 4); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * The reconnect method re-establishes a smart card reader handle. On success, + * the handle is valid once again. + * + * @param con connection to client + * @param sc_handle handle to device + * @param rs reader state where following fields are set + * rs.shared_mode_flag + * rs.preferred_protocol + * rs.init_type + *****************************************************************************/ +static void APP_CC +scard_send_Reconnect(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) { + /* see [MS-RDPESC] 2.2.2.15 */ + /* see [MS-RDPESC] 3.1.4.36 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_RECONNECT)) == NULL) + return; + /* - * format of device control request + * command format * - * DeviceIoRequest - * u16 RDPDR_CTYP_CORE - * u16 PAKID_CORE_DEVICE_IOREQUEST - * u32 DeviceId - * u32 FileId - * u32 CompletionId - * u32 MajorFunction - * u32 MinorFunction + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwShareMode + * u32 4 bytes dwPreferredProtocols + * u32 4 bytes dwInitialization + * u32 4 bytes context length + * u32 4 bytes context + * u32 4 bytes handle length + * u32 4 bytes handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->dwShareMode); + xstream_wr_u32_le(s, rs->dwPreferredProtocols); + xstream_wr_u32_le(s, rs->init_type); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Lock smart card reader for exclusive access for specified smart + * card reader handle. + * + * @param con connection to client + *****************************************************************************/ +static void APP_CC +scard_send_BeginTransaction(IRP *irp, tui32 sc_handle) +{ + /* see [MS-RDPESC] 4.9 */ + + SMARTCARD *sc; + struct stream *s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_BEGIN_TRANSACTION)) == NULL) + return; + + /* + * command format * - * u32 OutputBufferLength SHOULD be 2048 - * u32 InputBufferLength - * u32 IoControlCode - * 20 bytes padding - * xx bytes InputBuffer (variable) + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 36 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle */ + xstream_seek(s, 36); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Release a smart card reader after being locked by a previously + * successful call to Begin Transaction + * + * @param con connection to client + * @param sc_handle handle to smartcard + *****************************************************************************/ +static void APP_CC +scard_send_EndTransaction(IRP *irp, tui32 sc_handle, tui32 dwDisposition) +{ + /* see [MS-RDPESC] 3.1.4.32 */ + + SMARTCARD *sc; struct stream *s; + int bytes; - xstream_new(s, 1024 * 3); - if (s == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return s; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - devredir_insert_DeviceIoRequest(s, - irp->DeviceId, - irp->FileId, - irp->CompletionId, - IRP_MJ_DEVICE_CONTROL, - 0); + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_END_TRANSACTION)) == NULL) + return; - 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 */ + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * 8 unused + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ - /* [MS-RPCE] 2.2.6.1 */ - xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ - xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + xstream_seek(s, 24); + xstream_wr_u32_le(s, dwDisposition); + xstream_seek(s, 8); - return s; + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Create a new smart card device entry and insert it into smartcards[] + * Get the status of a connection for a valid smart card reader handle * - * @param device_id DeviceId of new card + * @param con connection to client + * @param wide TRUE if unicode string + *****************************************************************************/ +static void APP_CC +scard_send_Status(IRP *irp, int wide, tui32 sc_handle) +{ + /* see [MS-RDPESC] 2.2.2.18 */ + + 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) ? SCARD_IOCTL_CONNECT_W : + SCARD_IOCTL_CONNECT_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 28 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes reader len + * u32 4 bytes ATR len + * 8 bytes unused + * u32 4 bytes len of sc_handle + * 4 bytes sc_handle + * 4 bytes unused + */ + + xstream_seek(s, 28); + xstream_wr_u32_le(s, -1); /* readerLen, see [MS-RDPESC] 4.11 */ + xstream_wr_u32_le(s, 36); /* atrLen, see [MS-RDPESC] 4.11 */ + xstream_seek(s, 8); + + /* insert sc_handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + xstream_wr_u32_le(s, 0); + + /* 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); +} + +/** + * Release a smart card reader handle that was acquired in ConnectA/ConnectW * - * @return index into smartcards[] on success, -1 on failure + * @param con connection to client + * @param sc_handle handle to smartcard *****************************************************************************/ +static void APP_CC +scard_send_Disconnect(IRP *irp, tui32 context, tui32 sc_handle) +{ + /* see [MS-RDPESC] 3.1.4.30 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_DISCONNECT)) == NULL) + return; + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes disposition + * u32 4 bytes context len + * 4 bytes context + * u32 4 bytes length of sc_handle + * 4 bytes sc_handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, SCARD_RESET_CARD); + + /* insert context */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* insert handle */ + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * The Transmit_Call structure is used to send data to the smart card + * associated with a valid context. + *****************************************************************************/ static int APP_CC -scard_add_new_device(tui32 device_id) +scard_send_Transmit(IRP* irp, tui32 sc_handle, READER_STATE* rs) { - int index; - SMARTCARD *sc; + /* see [MS-RDPESC] 2.2.2.19 */ - if ((index = scard_get_free_slot()) < 0) - return -1; + SMARTCARD* sc; + struct stream* s; + int bytes; - if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + if ((sc = smartcards[irp->scard_index]) == NULL) { - log_error("system out of memory"); - return -1; + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - sc->DeviceId = device_id; - smartcards[index] = sc; + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_TRANSMIT)) == NULL) + return; - return index; + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwProtocol + * u32 4 bytes cbPciLength + * u32 4 bytes map2 + * u32 4 byts cbSendLength + * u32 4 bytes map3 + * u32 4 bytes map4 + * u32 4 bytes map5 + * u32 4 bytes map6 + * u32 4 bytes cbRecvLength + * u32 4 bytes len of sc_handle + * u32 4 bytes sc_handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, rs->map0); + xstream_seek(s, 4); + xstream_wr_u32_le(s, rs->map1); + xstream_wr_u32_le(s, rs->dwProtocol); + xstream_wr_u32_le(s, rs->cbPciLength); + xstream_wr_u32_le(s, rs->map2); + xstream_wr_u32_le(s, rs->cbSendLength); + xstream_wr_u32_le(s, rs->map3); + xstream_wr_u32_le(s, rs->map4); + xstream_wr_u32_le(s, rs->map5); + xstream_wr_u32_le(s, rs->map6); + xstream_wr_u32_le(s, rs->cbRecvLength); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Find first unused entry in smartcards - * - * @return index of first unused entry in smartcards or -1 if smartcards - * is full + * Communicate directly with the smart card reader *****************************************************************************/ +static int APP_CC +scard_send_Control(IRP* irp, tui32 context, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.19 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_CONTROL)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 12 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes map0 + * 4 bytes unused + * u32 4 bytes map1 + * u32 4 bytes dwControlCode + * u32 4 bytes cbRecvLength + * u32 4 bytes map2 + * 4 bytes unused + * u32 4 bytes cbOutBufferSize + * u32 4 bytes context len + * u32 4 bytes context + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 12); + xstream_wr_u32_le(s, rs->map0); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->map1); + xstream_wr_u32_le(s, rs->dwControlCode); + xstream_wr_u32_le(s, rs->cbRecvLength); + xstream_wr_u32_le(s, rs->map2); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->cbOutBufferSize); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * Cancel any outstanding calls + *****************************************************************************/ static int APP_CC -scard_get_free_slot(void) +scard_send_Cancel(IRP* irp, tui32 context) { - int i; + /* see [MS-RDPESC] 3.1.4.27 */ - for (i = 0; i < MAX_SMARTCARDS; i++) + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) { - if (smartcards[i] == NULL) - { - log_debug("found free slot at index %d", i); - return i; - } + log_error("smartcards[%d] is NULL", irp->scard_index); + return; } - log_error("too many smart card devices; rejecting this one"); - return -1; + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_CANCEL)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 16 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes context len + * u32 4 bytes context + */ + + xstream_seek(s, 16); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, context); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); } /** - * Release resources prior to shutting down + * Get reader attributes *****************************************************************************/ +static int APP_CC +scard_send_GetAttrib(IRP* irp, tui32 sc_handle, READER_STATE* rs) +{ + /* see [MS-RDPESC] 2.2.2.21 */ + + SMARTCARD* sc; + struct stream* s; + int bytes; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_GETATTRIB)) == NULL) + return; + + /* + * command format + * + * ...... + * 20 bytes padding + * u32 4 bytes len 8, LE, v1 + * u32 4 bytes filler + * 24 bytes unused (s->p currently pointed here at unused[0]) + * u32 4 bytes dwAttribId + * 4 bytes unused + * u32 4 bytes dwAttrLen + * 8 bytes unused + * u32 4 bytes handle len + * u32 4 bytes handle + */ + + xstream_seek(s, 24); + xstream_wr_u32_le(s, rs->dwAttribId); + xstream_wr_u32_le(s, 0); + xstream_wr_u32_le(s, rs->dwAttrLen); + xstream_seek(s, 8); + xstream_wr_u32_le(s, 4); + xstream_wr_u32_le(s, sc_handle); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/****************************************************************************** +** ** +** local callbacks into this module ** +** ** +******************************************************************************/ + +/** + * + *****************************************************************************/ static void APP_CC -scard_release_resources(void) +scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - int i; + tui32 len; + struct trans *con; - for (i = 0; i < MAX_SMARTCARDS; i++) + log_debug("entered"); + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) { - if (smartcards[i] != NULL) - { - g_free(smartcards[i]); - smartcards[i] = NULL; - } + 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; } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_establish_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout) +static void +scard_handle_ReleaseContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_get_wait_objs(objs, count, timeout); + tui32 len; + struct trans *con; + + 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("ReleaseContext failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_release_context_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); +} + +static void APP_CC scard_handle_IsContextValid_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("Error checking context validity"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_check_wait_objs(void) +static void APP_CC +scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - return scard_pcsc_check_wait_objs(); + tui32 len; + struct trans *con; + + 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"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_list_readers_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_init(void) +static void +scard_handle_GetStatusChange_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("init") - return scard_pcsc_init(); + tui32 len; + struct trans *con; + + 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 get status change"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + con = (struct trans *) (irp->user_data); + scard_function_get_status_change_return(con, s, len); + devredir_irp_delete(irp); + log_debug("leaving"); } /** * *****************************************************************************/ -int APP_CC -scard_deinit(void) +static void +scard_handle_Connect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) { - log_debug("deinit") - return scard_pcsc_deinit(); + tui32 len; + struct trans *con; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to connect"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + con = (struct trans *) (irp->user_data); + scard_function_connect_return(con, s, len); + devredir_irp_delete(irp); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Reconnect_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to reconnect"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_BeginTransaction_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + struct trans *con; + + 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("BeginTransaction failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + con = (struct trans *) (irp->user_data); + scard_function_begin_transaction_return(con, s, len); + devredir_irp_delete(irp); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_EndTransaction_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("EndTransaction failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Status_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("StatusCall failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void +scard_handle_Disconnect_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("Disconnect failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Transmit_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("Transmit failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Control_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("Control failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_Cancel_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("Cancel_call failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); +} + +/** + * + *****************************************************************************/ +static void APP_CC +scard_handle_GetAttrib_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("GetAttrib_call failed"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + log_debug("leaving"); } diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h index a85b9f5f..14c5d6f2 100644 --- a/sesman/chansrv/smartcard.h +++ b/sesman/chansrv/smartcard.h @@ -26,26 +26,119 @@ #include "parse.h" #include "irp.h" +#include "trans.h" + +#define SCARD_SHARE_EXCLUSIVE 0x00000001 +#define SCARD_SHARE_SHARED 0x00000002 +#define SCARD_SHARE_DIRECT 0x00000003 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table A */ +#define SCARD_PROTOCOL_UNDEFINED 0x00000000 +#define SCARD_PROTOCOL_T0 0x00000001 +#define SCARD_PROTOCOL_T1 0x00000002 +#define SCARD_PROTOCOL_Tx 0x00000003 +#define SCARD_PROTOCOL_RAW 0x00010000 + +/* see [MS-RDPESC] 2.2.5 protocol identifier - Table B */ +#define SCARD_PROTOCOL_DEFAULT 0x80000000 +#define SCARD_PROTOCOL_OPTIMAL 0x00000000 + +/* initialization type */ +#define SCARD_LEAVE_CARD 0x00000000 /* do not do anything */ +#define SCARD_RESET_CARD 0x00000001 /* reset smart card */ +#define SCARD_UNPOWER_CARD 0x00000002 /* turn off and reset card */ + +typedef struct reader_state +{ + char reader_name[128]; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + + /* + * share mode flag, can be one of: + * SCARD_SHARE_EXCLUSIVE app not willing to share smartcard with other apps + * SCARD_SHARE_SHARED app willing to share smartcard with other apps + * SCARD_SHARE_DIRECT app demands direct control of smart card, hence + * it is not available to other readers + */ + tui32 dwShareMode; + + /* + * This field MUST have a value from Table A which is logically + * OR'ed with a value from Table B. + */ + tui32 dwPreferredProtocols; + + /* + * initialization type, must be one of the initialization type + * defined above + */ + tui32 init_type; + + /* required by scard_send_transmit(), scard_send_control() */ + tui32 map0; + tui32 map1; + tui32 map2; + tui32 map3; + tui32 map4; + tui32 map5; + tui32 map6; + + tui32 dwProtocol; + tui32 cbPciLength; + tui32 cbSendLength; + tui32 cbRecvLength; + tui32 dwControlCode; + tui32 cbOutBufferSize; + tui32 dwAttribId; + tui32 dwAttrLen; + +} READER_STATE; -/* forward declarations */ void scard_device_announce(tui32 device_id); +int APP_CC scard_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_check_wait_objs(void); +int APP_CC scard_init(void); +int APP_CC scard_deinit(void); +int APP_CC scard_send_establish_context(struct trans *con, int scope); +int APP_CC scard_send_release_context(struct trans *con, tui32 context); +int APP_CC scard_send_is_valid_context(struct trans *con, tui32 context); +int APP_CC scard_send_list_readers(struct trans *con, tui32 context, int wide); + +int APP_CC scard_send_get_status_change(struct trans *con, tui32 context, + int wide, tui32 timeout, + tui32 num_readers, READER_STATE* rsa); + +int APP_CC scard_send_connect(struct trans *con, tui32 context, int wide, + READER_STATE* rs); + +int APP_CC scard_send_reconnect(struct trans *con, tui32 context, + tui32 sc_handle, READER_STATE* rs); -/* callbacks into this module */ -void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_begin_transaction(struct trans *con, tui32 sc_handle); +int APP_CC scard_send_end_transaction(struct trans *con, tui32 sc_handle, + tui32 dwDisposition); +int APP_CC scard_send_status(struct trans *con, int wide, tui32 sc_handle); +int APP_CC scard_send_disconnect(struct trans *con, tui32 context, tui32 sc_handle); -void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, - tui32 DeviceId, tui32 CompletionId, - tui32 IoStatus); +int APP_CC scard_send_transmit(struct trans *con, tui32 sc_handle, + READER_STATE* rs); -int APP_CC -scard_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_check_wait_objs(void); -int APP_CC -scard_init(void); -int APP_CC -scard_deinit(void); +int APP_CC scard_send_control(struct trans *con, tui32 context, tui32 sc_handle, + READER_STATE* rs); +int APP_CC scard_send_cancel(struct trans *con, tui32 context); + +int APP_CC scard_send_get_attrib(struct trans *con, tui32 sc_handle, + READER_STATE* rs); + +/* + * Notes: + * SCardTransmit - partially done + * SCardControl - partially done + * SCardListReaderGroups - not supported + * SCardSetAttrib - not supported + */ #endif /* end #ifndef _SMARTCARD_C */ diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index a3a269d7..b010eee7 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -20,8 +20,12 @@ /* * smartcard redirection support, PCSC daemon standin * this will act like pcsc daemon + * pcsc lib and daemon write struct on unix domain socket for communication */ +#define JAY_TODO_CONTEXT 0 +#define JAY_TODO_WIDE 1 + #define PCSC_STANDIN 1 #include "os_calls.h" @@ -30,77 +34,35 @@ #include "irp.h" #include "devredir.h" #include "trans.h" +#include "chansrv.h" #if PCSC_STANDIN -/* module based logging */ -#define LOG_ERROR 0 -#define LOG_INFO 1 -#define LOG_DEBUG 2 -#define LOG_LEVEL LOG_ERROR - -#define log_error(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ERROR: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_always(_params...) \ -{ \ - g_write("[%10.10u]: PCSC %s: %d : ALWAYS: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} - -#define log_info(_params...) \ -{ \ - if (LOG_INFO <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define log_debug(_params...) \ -{ \ - if (LOG_DEBUG <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: PCSC %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} - -#define PCSCLITE_MSG_KEY_LEN 16 -#define PCSCLITE_MAX_MESSAGE_SIZE 2048 - -struct version_struct -{ - tsi32 major; /**< IPC major \ref PROTOCOL_VERSION_MAJOR */ - tsi32 minor; /**< IPC minor \ref PROTOCOL_VERSION_MINOR */ - tui32 rv; -}; -typedef struct version_struct version_struct; - -struct rxSharedSegment -{ - tui32 mtype; /** one of the \c pcsc_adm_commands */ - tui32 user_id; - tui32 group_id; - tui32 command; /** one of the \c pcsc_msg_commands */ - tui64 date; - tui8 key[PCSCLITE_MSG_KEY_LEN]; /* 16 bytes */ - union _u - { - tui8 data[PCSCLITE_MAX_MESSAGE_SIZE]; - struct version_struct veStr; - } u; -}; -typedef struct rxSharedSegment sharedSegmentMsg, *psharedSegmentMsg; - -#define RXSHAREDSEGMENT_BYTES 2088 +#define LLOG_LEVEL 11 +#define LLOGLN(_level, _args) \ + do \ + { \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("chansrv:smartcard_pcsc [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ + } \ + while (0) + +#define XRDP_PCSC_STATE_NONE 0 +#define XRDP_PCSC_STATE_GOT_EC (1 << 0) /* establish context */ +#define XRDP_PCSC_STATE_GOT_LR (1 << 1) /* list readers */ +#define XRDP_PCSC_STATE_GOT_RC (1 << 2) /* release context */ +#define XRDP_PCSC_STATE_GOT_GSC (1 << 3) /* get status change */ +#define XRDP_PCSC_STATE_GOT_C (1 << 4) /* connect */ +#define XRDP_PCSC_STATE_GOT_BT (1 << 5) /* begin transaction */ +#define XRDP_PCSC_STATE_GOT_ET (1 << 6) /* end transaction */ +#define XRDP_PCSC_STATE_GOT_TR (1 << 7) /* transmit */ +#define XRDP_PCSC_STATE_GOT_CO (1 << 8) /* control */ + +/* TODO: put this in con */ +static int g_xrdp_pcsc_state = XRDP_PCSC_STATE_NONE; extern int g_display_num; /* in chansrv.c */ @@ -115,15 +77,14 @@ static struct pcsc_client *g_tail = 0; static struct trans *g_lis = 0; static struct trans *g_con = 0; /* todo, remove this */ - -static char g_pcsc_directory[256] = ""; +static char g_pcsclite_ipc_dir[256] = ""; +static int g_pub_file_fd = 0; /*****************************************************************************/ int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) { - log_debug("scard_pcsc_get_wait_objs"); - + LLOGLN(0, ("scard_pcsc_get_wait_objs")); if (g_lis != 0) { trans_get_wait_objs(g_lis, objs, count); @@ -139,8 +100,7 @@ scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout) int APP_CC scard_pcsc_check_wait_objs(void) { - log_debug("scard_pcsc_check_wait_objs"); - + LLOGLN(0, ("scard_pcsc_check_wait_objs")); if (g_lis != 0) { trans_check_wait_objs(g_lis); @@ -155,34 +115,670 @@ scard_pcsc_check_wait_objs(void) /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_version(psharedSegmentMsg msg) +scard_process_establish_context(struct trans *con, struct stream *in_s) { + int dwScope; + + LLOGLN(0, ("scard_process_establish_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_EC; + in_uint32_le(in_s, dwScope); + LLOGLN(0, ("scard_process_establish_context: dwScope 0x%8.8x", dwScope)); + scard_send_establish_context(con, dwScope); return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -scard_process_msg(struct stream *s) +scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len) { - sharedSegmentMsg msg; - int rv; + int bytes; + tui32 context; + tui32 context_len; + struct stream *out_s; + + LLOGLN(0, ("scard_function_establish_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_EC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_EC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, context_len); + if (context_len != 4) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + in_uint32_le(in_s, context); + LLOGLN(0, ("scard_function_establish_context_return: context 0x%8.8x", context)); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, context); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x01); /* SCARD_ESTABLISH_CONTEXT 0x01 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_release_context(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(0, ("scard_process_release_context:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) + { + LLOGLN(0, ("scard_process_establish_context: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_RC; + in_uint32_le(in_s, hContext); + LLOGLN(0, ("scard_process_release_context: hContext 0x%8.8x", hContext)); + scard_send_release_context(con, hContext); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + struct stream *out_s; + tui32 context; + + LLOGLN(0, ("scard_function_release_context_return:")); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_RC) == 0) + { + LLOGLN(0, ("scard_function_release_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_RC; + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x02); /* SCARD_RELEASE_CONTEXT 0x02 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_list_readers(struct trans *con, struct stream *in_s) +{ + int hContext; + + LLOGLN(0, ("scard_process_list_readers:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) + { + LLOGLN(0, ("scard_process_list_readers: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_LR; + in_uint32_le(in_s, hContext); + LLOGLN(0, ("scard_process_list_readers: dwScope 0x%8.8x", hContext)); + scard_send_list_readers(con, hContext, 1); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int chr; + int readers; + int rn_index; + int index; + int bytes; + twchar reader_name[100]; + char lreader_name[16][100]; + + LLOGLN(10, ("scard_function_list_readers_return:")); + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_LR) == 0) + { + LLOGLN(10, ("scard_function_list_readers_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_LR; + + g_memset(reader_name, 0, sizeof(reader_name)); + g_memset(lreader_name, 0, sizeof(lreader_name)); + in_uint8s(in_s, 28); + len -= 28; + in_uint32_le(in_s, len); + g_writeln("len %d", len); + rn_index = 0; + readers = 0; + while (len > 0) + { + in_uint16_le(in_s, chr); + len -= 2; + if (chr == 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + g_writeln("1 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + reader_name[0] = 0; + rn_index = 0; + } + else + { + reader_name[rn_index] = chr; + rn_index++; + } + } + if (rn_index > 0) + { + if (reader_name[0] != 0) + { + g_wcstombs(lreader_name[readers], reader_name, 99); + g_writeln("2 %s", lreader_name[readers]); + g_memset(reader_name, 0, sizeof(reader_name)); + readers++; + } + } + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, readers); + for (index = 0; index < readers; index++) + { + g_writeln("3 - %s", lreader_name[index]); + out_uint8a(out_s, lreader_name[index], 100); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x03); /* SCARD_LIST_READERS 0x03 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_connect(struct trans *con, struct stream *in_s) +{ + int hContext; + char szReader[100]; + READER_STATE rs; + + LLOGLN(0, ("scard_process_connect:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) + { + LLOGLN(0, ("scard_process_connect: opps")); + return 1; + } + g_memset(&rs, 0, sizeof(rs)); + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_C; + in_uint32_le(in_s, hContext); + in_uint8a(in_s, szReader, 100); + in_uint32_le(in_s, rs.dwShareMode); + in_uint32_le(in_s, rs.dwPreferredProtocols); + LLOGLN(0, ("scard_process_connect: dwShareMode 0x%8.8x " + "dwPreferredProtocols 0x%8.8x", rs.dwShareMode, + rs.dwPreferredProtocols)); + scard_send_connect(con, hContext, 1, &rs); + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len) +{ + int dwActiveProtocol; + int hCard; + int bytes; + struct stream *out_s; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_C) == 0) + { + LLOGLN(0, ("scard_function_connect_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_C; + in_uint8s(in_s, 36); + in_uint32_le(in_s, dwActiveProtocol); + in_uint8s(in_s, 36); + in_uint32_le(in_s, hCard); + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, hCard); + out_uint32_le(out_s, dwActiveProtocol); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x04); /* SCARD_CONNECT 0x04 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_begin_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; + + LLOGLN(0, ("scard_process_begin_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) + { + LLOGLN(0, ("scard_process_begin_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_BT; + in_uint32_le(in_s, hCard); + LLOGLN(0, ("scard_process_begin_transaction: hCard 0x%8.8x", hCard)); + scard_send_begin_transaction(con, hCard); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_BT) == 0) + { + LLOGLN(0, ("scard_function_begin_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_BT; + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x07); /* SCARD_BEGIN_TRANSACTION 0x07 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_end_transaction(struct trans *con, struct stream *in_s) +{ + int hCard; + int dwDisposition; + + LLOGLN(0, ("scard_process_end_transaction:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) + { + LLOGLN(0, ("scard_process_end_transaction: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_ET; + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, dwDisposition); + LLOGLN(0, ("scard_process_end_transaction: hCard 0x%8.8x", hCard)); + scard_send_end_transaction(con, hCard, dwDisposition); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_end_transaction_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_ET) == 0) + { + LLOGLN(0, ("scard_function_end_transaction_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_ET; + + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x08); /* SCARD_END_TRANSACTION 0x08 */ + return trans_force_write(con); +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_transmit(struct trans *con, struct stream *in_s) +{ + int hCard; + READER_STATE rs; + + LLOGLN(0, ("scard_process_transmit:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) + { + LLOGLN(0, ("scard_process_transmit: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_TR; + LLOGLN(0, ("scard_process_transmit:")); + + // todo + g_memset(&rs, 0, sizeof(rs)); + + in_uint32_le(in_s, hCard); + in_uint32_le(in_s, rs.dwProtocol); + in_uint32_le(in_s, rs.cbPciLength); + in_uint32_le(in_s, rs.cbSendLength); + LLOGLN(0, ("scard_process_transmit: dwProtocol %d cbPciLength %d " + "cbSendLength %d", rs.dwProtocol, rs.cbPciLength, rs.cbSendLength)); + g_hexdump(in_s->p, rs.cbSendLength); + in_uint8s(in_s, rs.cbSendLength); + in_uint32_le(in_s, rs.cbRecvLength); + LLOGLN(0, ("scard_process_transmit: cbRecvLength %d", rs.cbRecvLength)); + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_transmit_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_TR) == 0) + { + LLOGLN(0, ("scard_function_transmit_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_TR; + + // todo - g_memset(&msg, 0, sizeof(msg)); - in_uint32_le(s, msg.mtype); - in_uint32_le(s, msg.user_id); - in_uint32_le(s, msg.group_id); - in_uint32_le(s, msg.command); - in_uint64_le(s, msg.date); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_control(struct trans *con, struct stream *in_s) +{ + LLOGLN(0, ("scard_process_control:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) + { + LLOGLN(0, ("scard_process_control: opps")); + return 1; + } + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_CO; + LLOGLN(0, ("scard_process_control:")); + + // todo + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_function_control_return(struct trans *con, + struct stream *in_s, + int len) +{ + struct stream *out_s; + int bytes; + + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_CO) == 0) + { + LLOGLN(0, ("scard_function_control_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_CO; + + // todo + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_get_status_change(struct trans *con, struct stream *in_s) +{ + int index; + int hContext; + int dwTimeout; + int cReaders; + READER_STATE *rsa; + + LLOGLN(0, ("scard_process_get_status_change:")); + if (g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) + { + LLOGLN(0, ("scard_process_get_status_change: opps")); + return 1; + } + in_uint32_le(in_s, hContext); + in_uint32_le(in_s, dwTimeout); + in_uint32_le(in_s, cReaders); + if ((cReaders < 0) || (cReaders > 16)) + { + LLOGLN(0, ("scard_process_get_status_change: bad cReaders %d", cReaders)); + return 1; + } + rsa = (READER_STATE *) g_malloc(sizeof(READER_STATE) * cReaders, 1); + + for (index = 0; index < cReaders; index++) + { + in_uint8a(in_s, rsa[index].reader_name, 100); + LLOGLN(10, ("scard_process_get_status_change: reader_name %s", + rsa[index].reader_name)); + in_uint32_le(in_s, rsa[index].current_state); + LLOGLN(10, ("scard_process_get_status_change: current_state %d", + rsa[index].current_state)); + in_uint32_le(in_s, rsa[index].event_state); + LLOGLN(10, ("scard_process_get_status_change: event_state %d", + rsa[index].event_state)); + in_uint32_le(in_s, rsa[index].atr_len); + LLOGLN(10, ("scard_process_get_status_change: atr_len %d", + rsa[index].atr_len)); + in_uint8a(in_s, rsa[index].atr, 36); + } - log_debug("scard_process_msg: mtype 0x%2.2x command 0x%2.2x", - msg.mtype, msg.command); + LLOGLN(0, ("scard_process_get_status_change: hContext 0x%8.8x dwTimeout " + "%d cReaders %d", hContext, dwTimeout, cReaders)); + g_xrdp_pcsc_state |= XRDP_PCSC_STATE_GOT_GSC; + + scard_send_get_status_change(con, hContext, 1, dwTimeout, cReaders, rsa); + + g_free(rsa); + + return 0; +} + +/*****************************************************************************/ +int APP_CC +scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len) +{ + int bytes; + int index; + int cReaders; + tui32 current_state; + tui32 event_state; + tui32 atr_len; /* number of bytes in atr[] */ + tui8 atr[36]; + struct stream *out_s; + + LLOGLN(0, ("scard_function_get_status_change_return:")); + g_hexdump(in_s->p, len); + if ((g_xrdp_pcsc_state & XRDP_PCSC_STATE_GOT_GSC) == 0) + { + LLOGLN(0, ("scard_function_establish_context_return: opps")); + return 1; + } + g_xrdp_pcsc_state &= ~XRDP_PCSC_STATE_GOT_GSC; + in_uint8s(in_s, 28); + in_uint32_le(in_s, cReaders); + if (cReaders > 0) + { + out_s = trans_get_out_s(con, 8192); + s_push_layer(out_s, iso_hdr, 8); + out_uint32_le(out_s, cReaders); + for (index = 0; index < cReaders; index++) + { + in_uint32_le(in_s, current_state); + out_uint32_le(out_s, current_state); + in_uint32_le(in_s, event_state); + out_uint32_le(out_s, event_state); + in_uint32_le(in_s, atr_len); + out_uint32_le(out_s, atr_len); + in_uint8a(in_s, atr, 36); + out_uint8a(out_s, atr, 36); + } + out_uint32_le(out_s, 0); /* SCARD_S_SUCCESS status */ + s_mark_end(out_s); + bytes = (int) (out_s->end - out_s->data); + s_pop_layer(out_s, iso_hdr); + out_uint32_le(out_s, bytes - 8); + out_uint32_le(out_s, 0x0C); /* SCARD_ESTABLISH_CONTEXT 0x0C */ + return trans_force_write(con); + } + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +scard_process_msg(struct trans *con, struct stream *in_s, int command) +{ + int rv; + + LLOGLN(0, ("scard_process_msg: command 0x%4.4x", command)); rv = 0; - switch (msg.mtype) + switch (command) { - case 0xF8: /* CMD_VERSION */ - rv = scard_process_version(&msg); + case 0x01: /* SCARD_ESTABLISH_CONTEXT */ + LLOGLN(0, ("scard_process_msg: SCARD_ESTABLISH_CONTEXT")); + rv = scard_process_establish_context(con, in_s); + break; + case 0x02: /* SCARD_RELEASE_CONTEXT */ + LLOGLN(0, ("scard_process_msg: SCARD_RELEASE_CONTEXT")); + rv = scard_process_release_context(con, in_s); + break; + + case 0x03: /* SCARD_LIST_READERS */ + LLOGLN(0, ("scard_process_msg: SCARD_LIST_READERS")); + rv = scard_process_list_readers(con, in_s); + break; + + case 0x04: /* SCARD_CONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_CONNECT")); + rv = scard_process_connect(con, in_s); + break; + + case 0x05: /* SCARD_RECONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_RECONNECT")); + break; + + case 0x06: /* SCARD_DISCONNECT */ + LLOGLN(0, ("scard_process_msg: SCARD_DISCONNECT")); + break; + + case 0x07: /* SCARD_BEGIN_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_BEGIN_TRANSACTION")); + rv = scard_process_begin_transaction(con, in_s); + break; + + case 0x08: /* SCARD_END_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_END_TRANSACTION")); + rv = scard_process_end_transaction(con, in_s); + break; + + case 0x09: /* SCARD_TRANSMIT */ + LLOGLN(0, ("scard_process_msg: SCARD_TRANSMIT")); + rv = scard_process_transmit(con, in_s); + break; + + case 0x0A: /* SCARD_CONTROL */ + LLOGLN(0, ("scard_process_msg: SCARD_CONTROL")); + rv = scard_process_control(con, in_s); + break; + + case 0x0B: /* SCARD_STATUS */ + LLOGLN(0, ("scard_process_msg: SCARD_STATUS")); + break; + + case 0x0C: /* SCARD_GET_STATUS_CHANGE */ + LLOGLN(0, ("scard_process_msg: SCARD_GET_STATUS_CHANGE")); + rv = scard_process_get_status_change(con, in_s); + break; + + case 0x0D: /* SCARD_CANCEL */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL")); + break; + + case 0x0E: /* SCARD_CANCEL_TRANSACTION */ + LLOGLN(0, ("scard_process_msg: SCARD_CANCEL_TRANSACTION")); + break; + + case 0x0F: /* SCARD_GET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_GET_ATTRIB")); + break; + + case 0x10: /* SCARD_SET_ATTRIB */ + LLOGLN(0, ("scard_process_msg: SCARD_SET_ATTRIB")); + break; + + default: + LLOGLN(0, ("scard_process_msg: unknown mtype 0x%4.4x", command)); + rv = 1; break; } return rv; @@ -196,22 +792,27 @@ my_pcsc_trans_data_in(struct trans *trans) struct stream *s; int id; int size; + int command; int error; - log_debug("my_pcsc_trans_data_in:"); - + LLOGLN(0, ("my_pcsc_trans_data_in:")); if (trans == 0) { return 0; } - if (trans != g_con) { return 1; } s = trans_get_in_s(trans); - g_hexdump(s->p, 64); - error = scard_process_msg(s); + in_uint32_le(s, size); + in_uint32_le(s, command); + LLOGLN(0, ("my_pcsc_trans_data_in: size %d command %d", size, command)); + error = trans_force_read(trans, size); + if (error == 0) + { + error = scard_process_msg(g_con, s, command); + } return error; } @@ -220,7 +821,7 @@ my_pcsc_trans_data_in(struct trans *trans) int DEFAULT_CC my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) { - log_debug("my_pcsc_trans_conn_in:"); + LLOGLN(0, ("my_pcsc_trans_conn_in:")); if (trans == 0) { @@ -239,11 +840,13 @@ my_pcsc_trans_conn_in(struct trans *trans, struct trans *new_trans) g_con = new_trans; g_con->trans_data_in = my_pcsc_trans_data_in; +#if 1 + g_con->header_size = 8; +#else g_con->header_size = RXSHAREDSEGMENT_BYTES; - - log_debug("my_pcsc_trans_conn_in: sizeof sharedSegmentMsg is %d", - sizeof(sharedSegmentMsg)); - + LLOGLN(0, ("my_pcsc_trans_conn_in: sizeof sharedSegmentMsg is %d", + sizeof(sharedSegmentMsg))); +#endif return 0; } @@ -252,33 +855,40 @@ int APP_CC scard_pcsc_init(void) { char port[256]; + char *home; + int disp; int error; + int index; - log_debug("scard_pcsc_init:"); - + LLOGLN(0, ("scard_pcsc_init:")); if (g_lis == 0) { g_lis = trans_create(2, 8192, 8192); - g_snprintf(g_pcsc_directory, 255, "/tmp/.xrdp/pcsc%d", g_display_num); - if (g_directory_exist(g_pcsc_directory)) + + //g_snprintf(g_pcsclite_ipc_dir, 255, "/tmp/.xrdp/pcsc%d", g_display_num); + home = g_getenv("HOME"); + disp = g_display_num; + g_snprintf(g_pcsclite_ipc_dir, 255, "%s/.pcsc%d", home, disp); + + if (g_directory_exist(g_pcsclite_ipc_dir)) { - if (g_remove_dir(g_pcsc_directory) != 0) + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_init: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_remove_dir failed")); } } - if (g_create_dir(g_pcsc_directory) != 0) + if (!g_create_dir(g_pcsclite_ipc_dir)) { - log_error("scard_pcsc_init: g_create_dir failed"); + LLOGLN(0, ("scard_pcsc_init: g_create_dir failed")); } - g_chmod_hex(g_pcsc_directory, 0x1777); - g_snprintf(port, 255, "%s/pcscd.comm", g_pcsc_directory); + g_chmod_hex(g_pcsclite_ipc_dir, 0x1777); + g_snprintf(port, 255, "%s/pcscd.comm", g_pcsclite_ipc_dir); g_lis->trans_conn_in = my_pcsc_trans_conn_in; error = trans_listen(g_lis, port); if (error != 0) { - log_error("scard_pcsc_init: trans_listen failed for port %s", - port); + LLOGLN(0, ("scard_pcsc_init: trans_listen failed for port %s", + port)); return 1; } } @@ -289,17 +899,20 @@ scard_pcsc_init(void) int APP_CC scard_pcsc_deinit(void) { - log_debug("scard_pcsc_deinit:"); - + LLOGLN(0, ("scard_pcsc_deinit:")); if (g_lis != 0) { trans_delete(g_lis); g_lis = 0; - if (g_remove_dir(g_pcsc_directory) != 0) + + g_file_close(g_pub_file_fd); + g_pub_file_fd = 0; + + if (g_remove_dir(g_pcsclite_ipc_dir) != 0) { - log_error("scard_pcsc_deinit: g_remove_dir failed"); + LLOGLN(0, ("scard_pcsc_deinit: g_remove_dir failed")); } - g_pcsc_directory[0] = 0; + g_pcsclite_ipc_dir[0] = 0; } return 0; } diff --git a/sesman/chansrv/smartcard_pcsc.h b/sesman/chansrv/smartcard_pcsc.h index a97a70d3..d22f4322 100644 --- a/sesman/chansrv/smartcard_pcsc.h +++ b/sesman/chansrv/smartcard_pcsc.h @@ -24,13 +24,28 @@ #ifndef _SMARTCARD_PCSC_H #define _SMARTCARD_PCSC_H -int APP_CC -scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -scard_pcsc_check_wait_objs(void); -int APP_CC -scard_pcsc_init(void); -int APP_CC -scard_pcsc_deinit(void); +int APP_CC scard_pcsc_get_wait_objs(tbus *objs, int *count, int *timeout); +int APP_CC scard_pcsc_check_wait_objs(void); +int APP_CC scard_pcsc_init(void); +int APP_CC scard_pcsc_deinit(void); +int APP_CC scard_function_establish_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_release_context_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_list_readers_return(struct trans *con, + struct stream *in_s, + int len); + +int APP_CC scard_function_get_status_change_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_connect_return(struct trans *con, + struct stream *in_s, + int len); +int APP_CC scard_function_begin_transaction_return(struct trans *con, + struct stream *in_s, + int len); #endif /* end #ifndef _SMARTCARD_PCSC_H */ diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index 9ee3c8c3..2e85f1f2 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -551,7 +551,8 @@ sound_init(void) LOG(0, ("sound_init:")); sound_send_server_formats(); - g_audio_l_trans = trans_create(2, 128 * 1024, 8192); + g_audio_l_trans = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192); + g_audio_l_trans->is_term = g_is_term; g_snprintf(port, 255, CHANSRV_PORT_STR, g_display_num); g_audio_l_trans->trans_conn_in = sound_trans_audio_conn_in; error = trans_listen(g_audio_l_trans, port); diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index c5a91cae..919bc41b 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -25,8 +25,10 @@ #include "clipboard.h" #include "rail.h" +/* #undef LOG_LEVEL #define LOG_LEVEL 11 +*/ extern int g_clip_up; /* in clipboard.c */ @@ -40,6 +42,9 @@ int g_screen_num = 0; Window g_root_window = 0; Atom g_wm_delete_window_atom = 0; Atom g_wm_protocols_atom = 0; +Atom g_utf8_string = 0; +Atom g_net_wm_name = 0; +Atom g_wm_state = 0; /*****************************************************************************/ static int DEFAULT_CC @@ -117,7 +122,10 @@ xcommon_init(void) g_wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", 0); g_wm_protocols_atom = XInternAtom(g_display, "WM_PROTOCOLS", 0); - + g_utf8_string = XInternAtom(g_display, "UTF8_STRING", 0); + g_net_wm_name = XInternAtom(g_display, "_NET_WM_NAME", 0); + g_wm_state = XInternAtom(g_display, "WM_STATE", 0); + return 0; } diff --git a/sesman/config.c b/sesman/config.c index c7c3de24..877a949c 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -130,7 +130,7 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n, } else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) { - cf->enable_user_wm = text2bool((char *)list_get_item(param_v, i)); + cf->enable_user_wm = g_text2bool((char *)list_get_item(param_v, i)); } else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) { @@ -212,7 +212,7 @@ config_read_logging(int file, struct log_config* lc, struct list* param_n, } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) { - lc->enable_syslog = text2bool((char*)list_get_item(param_v, i)); + lc->enable_syslog = g_text2bool((char*)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) { @@ -261,7 +261,7 @@ config_read_security(int file, struct config_security *sc, if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ROOT)) { - sc->allow_root = text2bool((char *)list_get_item(param_v, i)); + sc->allow_root = g_text2bool((char *)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) @@ -288,7 +288,7 @@ config_read_security(int file, struct config_security *sc, } if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALWAYSGROUPCHECK)) { - sc->ts_always_group_check = text2bool((char *)list_get_item(param_v, i)); + sc->ts_always_group_check = g_text2bool((char *)list_get_item(param_v, i)); } } @@ -355,7 +355,7 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n, if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC)) { - se->kill_disconnected = text2bool((char *)list_get_item(param_v, i)); + se->kill_disconnected = g_text2bool((char *)list_get_item(param_v, i)); } if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_IDLE_LIMIT)) diff --git a/sesman/sesman.ini b/sesman/sesman.ini index 571e063b..02fef5ba 100644 --- a/sesman/sesman.ini +++ b/sesman/sesman.ini @@ -17,8 +17,13 @@ AlwaysGroupCheck = false [Sessions] X11DisplayOffset=10 MaxSessions=10 +# if 1, true, or yes, kill session after 60 seconds KillDisconnected=0 +# if not zero, the seconds without mouse or keyboard input before disconnect +# not complete yet IdleTimeLimit=0 +# if not zero, the seconds before a disconnected session is killed +# min 60 seconds DisconnectedTimeLimit=0 [Logging] diff --git a/sesman/session.c b/sesman/session.c index 888604da..a5932736 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -62,11 +62,11 @@ static int g_sync_cmd; char *APP_CC dumpItemsToString(struct list *self, char *outstr, int len) { - g_memset(outstr, 0, len); int index; tbus item; int totalLen = 0; + g_memset(outstr, 0, len); if (self->count == 0) { g_writeln("List is empty"); @@ -385,6 +385,7 @@ session_start_fork(int width, int height, int bpp, char *username, int display = 0; int pid = 0; int wmpid = 0; + int pampid = 0; int xpid = 0; int i = 0; char geometry[32]; @@ -453,99 +454,105 @@ session_start_fork(int width, int height, int bpp, char *username, { g_tcp_close(g_sck); g_tcp_close(g_thread_sck); - auth_start_session(data, display); g_sprintf(geometry, "%dx%d", width, height); g_sprintf(depth, "%d", bpp); g_sprintf(screen, ":%d", display); wmpid = g_fork(); - if (wmpid == -1) { } else if (wmpid == 0) /* child (child sesman) xserver */ { wait_for_xserver(display); - env_set_user(username, 0, display); - - if (x_server_running(display)) + auth_start_session(data, display); + pampid = g_fork(); + if (pampid == -1) { - auth_set_env(data); - - if (directory != 0) + } + else if (pampid == 0) /* child: X11/client */ + { + env_set_user(username, 0, display); + if (x_server_running(display)) { - if (directory[0] != 0) + auth_set_env(data); + if (directory != 0) { - g_set_current_dir(directory); + if (directory[0] != 0) + { + g_set_current_dir(directory); + } } - } - - if (program != 0) - { - if (program[0] != 0) + if (program != 0) { - g_execlp3(program, program, 0); - log_message(LOG_LEVEL_ALWAYS, - "error starting program %s for user %s - pid %d", - program, username, g_getpid()); + if (program[0] != 0) + { + g_execlp3(program, program, 0); + log_message(LOG_LEVEL_ALWAYS, + "error starting program %s for user %s - pid %d", + program, username, g_getpid()); + } } - } - - /* try to execute user window manager if enabled */ - if (g_cfg->enable_user_wm) - { - g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm); - - if (g_file_exist(text)) + /* try to execute user window manager if enabled */ + if (g_cfg->enable_user_wm) { - g_execlp3(text, g_cfg->user_wm, 0); - log_message(LOG_LEVEL_ALWAYS, "error starting user " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, " - "description: %s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execlp3 parameter " - "list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->user_wm); + g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm); + if (g_file_exist(text)) + { + g_execlp3(text, g_cfg->user_wm, 0); + log_message(LOG_LEVEL_ALWAYS, "error starting user " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, " + "description: %s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter " + "list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->user_wm); + } } + /* if we're here something happened to g_execlp3 + so we try running the default window manager */ + g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); + g_execlp3(text, g_cfg->default_wm, 0); + + log_message(LOG_LEVEL_ALWAYS, "error starting default " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->default_wm); + + /* still a problem starting window manager just start xterm */ + g_execlp3("xterm", "xterm", 0); + + /* should not get here */ + log_message(LOG_LEVEL_ALWAYS, "error starting xterm " + "for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + } + else + { + log_message(LOG_LEVEL_ERROR, "another Xserver might " + "already be active on display %d - see log", display); } - /* if we're here something happened to g_execlp3 - so we try running the default window manager */ - g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); - g_execlp3(text, g_cfg->default_wm, 0); - - log_message( LOG_LEVEL_ALWAYS, "error starting default " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message( LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execlp3 parameter list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->default_wm); - - /* still a problem starting window manager just start xterm */ - g_execlp3("xterm", "xterm", 0); - - /* should not get here */ - log_message(LOG_LEVEL_ALWAYS, "error starting xterm " - "for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "aborting connection..."); + g_exit(0); } else { - log_message(LOG_LEVEL_ERROR, "another Xserver might " - "already be active on display %d - see log", display); + g_waitpid(pampid); + auth_stop_session(data); + g_exit(0); } - - log_message(LOG_LEVEL_DEBUG, "aborting connection..."); - g_exit(0); } else /* parent (child sesman) */ { @@ -559,6 +566,13 @@ session_start_fork(int width, int height, int bpp, char *username, env_set_user(username, passwd_file, display); env_check_password_file(passwd_file, password); + g_snprintf(text, 255, "%d", g_cfg->sess.max_idle_time); + g_setenv("XRDP_SESMAN_MAX_IDLE_TIME", text, 1); + g_snprintf(text, 255, "%d", g_cfg->sess.max_disc_time); + g_setenv("XRDP_SESMAN_MAX_DISC_TIME", text, 1); + g_snprintf(text, 255, "%d", g_cfg->sess.kill_disconnected); + g_setenv("XRDP_SESMAN_KILL_DISCONNECTED", text, 1); + if (type == SESMAN_SESSION_TYPE_XVNC) { xserver_params = list_create(); diff --git a/sesman/verify_user_kerberos.c b/sesman/verify_user_kerberos.c index a6480f56..bb7ba3d2 100644 --- a/sesman/verify_user_kerberos.c +++ b/sesman/verify_user_kerberos.c @@ -431,6 +431,14 @@ auth_start_session(void) } /******************************************************************************/ +/* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + return 0; +} + +/******************************************************************************/ int DEFAULT_CC auth_end(void) { diff --git a/sesman/verify_user_pam.c b/sesman/verify_user_pam.c index e53f72d5..4d73f85d 100644 --- a/sesman/verify_user_pam.c +++ b/sesman/verify_user_pam.c @@ -203,6 +203,26 @@ auth_start_session(long in_val, int in_display) /******************************************************************************/ /* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + struct t_auth_info *auth_info; + int error; + + auth_info = (struct t_auth_info *)in_val; + error = pam_close_session(auth_info->ph, 0); + if (error != PAM_SUCCESS) + { + g_printf("pam_close_session failed: %s\r\n", + pam_strerror(auth_info->ph, error)); + return 1; + } + auth_info->session_opened = 0; + return 0; +} + +/******************************************************************************/ +/* returns error */ /* cleanup */ int DEFAULT_CC auth_end(long in_val) diff --git a/sesman/verify_user_pam_userpass.c b/sesman/verify_user_pam_userpass.c index 7f31176e..b3d4de73 100644 --- a/sesman/verify_user_pam_userpass.c +++ b/sesman/verify_user_pam_userpass.c @@ -91,6 +91,14 @@ auth_start_session(void) } /******************************************************************************/ +/* returns error */ +int DEFAULT_CC +auth_stop_session(long in_val) +{ + return 0; +} + +/******************************************************************************/ int DEFAULT_CC auth_end(void) { |