diff options
110 files changed, 13893 insertions, 1186 deletions
@@ -35,4 +35,4 @@ xrdp-sesrun xrdp-sessvc xrdp-sestest xrdp-dis -xrdp/xrdp
\ No newline at end of file +xrdp/xrdp diff --git a/Makefile.am b/Makefile.am index 5193171f..26dcb8aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,12 @@ else FREERDPDIR = endif +if XRDP_NEUTRINORDP +NEUTRINORDPDIR = neutrinordp +else +NEUTRINORDPDIR = +endif + if XRDP_XRDPVR XRDPVRDIR = xrdpvr else @@ -19,6 +25,7 @@ SUBDIRS = \ xup \ mc \ $(FREERDPDIR) \ + $(NEUTRINORDPDIR) \ libxrdp \ xrdp \ sesman \ diff --git a/common/file.c b/common/file.c index c8be7af5..05f243ca 100644 --- a/common/file.c +++ b/common/file.c @@ -242,8 +242,19 @@ l_file_read_section(int fd, int max_file_size, const char *section, for (index = 0; index < len; index++) { + if (!s_check_rem(s, 1)) + { + break; + } in_uint8(s, c); - + if ((c == '#') || (c == ';')) + { + file_read_line(s, text); + in_it = 0; + in_it_index = 0; + g_memset(text, 0, 512); + continue; + } if (c == '[') { in_it = 1; @@ -253,7 +264,6 @@ l_file_read_section(int fd, int max_file_size, const char *section, if (g_strcasecmp(section, text) == 0) { file_read_line(s, text); - while (file_read_line(s, text) == 0) { if (g_strlen(text) > 0) @@ -296,7 +306,6 @@ l_file_read_section(int fd, int max_file_size, const char *section, } } } - free_stream(s); return 1; } diff --git a/common/file_loc.h b/common/file_loc.h index db312fb4..c8b3a76f 100644 --- a/common/file_loc.h +++ b/common/file_loc.h @@ -37,4 +37,8 @@ #define XRDP_SHARE_PATH "/usr/local/share/xrdp" #endif +#if !defined(XRDP_LIB_PATH) +#define XRDP_LIB_PATH "/usr/local/lib/xrdp" +#endif + #endif diff --git a/common/os_calls.c b/common/os_calls.c index 07f378e5..f5f5cd60 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,7 @@ #include "os_calls.h" #include "arch.h" +#include "log.h" /* for clearenv() */ #if defined(_WIN32) @@ -426,29 +427,42 @@ g_tcp_set_keepalive(int sck) /*****************************************************************************/ /* returns a newly created socket or -1 on error */ +/* in win32 a socket is an unsigned int, in linux, its an int */ int APP_CC g_tcp_socket(void) { -#if defined(_WIN32) int rv; int option_value; +#if defined(_WIN32) int option_len; #else - int rv; - int option_value; unsigned int option_len; #endif - /* in win32 a socket is an unsigned int, in linux, its an int */ - rv = (int)socket(PF_INET, SOCK_STREAM, 0); - +#if 0 && !defined(NO_ARPA_INET_H_IP6) + rv = (int)socket(AF_INET6, SOCK_STREAM, 0); +#else + rv = (int)socket(AF_INET, SOCK_STREAM, 0); +#endif if (rv < 0) { return -1; } - +#if 0 && !defined(NO_ARPA_INET_H_IP6) + option_len = sizeof(option_value); + if (getsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&option_value, + &option_len) == 0) + { + if (option_value != 0) + { + option_value = 0; + option_len = sizeof(option_value); + setsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&option_value, + option_len); + } + } +#endif option_len = sizeof(option_value); - if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value, &option_len) == 0) { @@ -493,52 +507,109 @@ g_tcp_local_socket(void) void APP_CC g_tcp_close(int sck) { + char ip[256]; + if (sck == 0) { return; } - #if defined(_WIN32) closesocket(sck); #else + g_write_ip_address(sck, ip, 255); + log_message(LOG_LEVEL_INFO, "An established connection closed to " + "endpoint: %s", ip); close(sck); #endif } /*****************************************************************************/ /* returns error, zero is good */ +#if 0 int APP_CC g_tcp_connect(int sck, const char *address, const char *port) { - struct sockaddr_in s; - struct hostent *h; - - g_memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = inet_addr(address); - - if (s.sin_addr.s_addr == INADDR_NONE) + int res = 0; + struct addrinfo p; + struct addrinfo *h = (struct addrinfo *)NULL; + struct addrinfo *rp = (struct addrinfo *)NULL; + + /* initialize (zero out) local variables: */ + g_memset(&p, 0, sizeof(struct addrinfo)); + + /* in IPv6-enabled environments, set the AI_V4MAPPED + * flag in ai_flags and specify ai_family=AF_INET6 in + * order to ensure that getaddrinfo() returns any + * available IPv4-mapped addresses in case the target + * host does not have a true IPv6 address: + */ + p.ai_socktype = SOCK_STREAM; + p.ai_protocol = IPPROTO_TCP; +#if !defined(NO_ARPA_INET_H_IP6) + p.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; + p.ai_family = AF_INET6; + if (g_strcmp(address, "127.0.0.1") == 0) + { + res = getaddrinfo("::1", port, &p, &h); + } + else { - h = gethostbyname(address); - - if (h != 0) + res = getaddrinfo(address, port, &p, &h); + } +#else + p.ai_flags = AI_ADDRCONFIG; + p.ai_family = AF_INET; + res = getaddrinfo(address, port, &p, &h); +#endif + if (res > -1) + { + if (h != NULL) { - if (h->h_name != 0) + for (rp = h; rp != NULL; rp = rp->ai_next) { - if (h->h_addr_list != 0) + rp = h; + res = connect(sck, (struct sockaddr *)(rp->ai_addr), + rp->ai_addrlen); + if (res != -1) { - if ((*(h->h_addr_list)) != 0) - { - s.sin_addr.s_addr = *((int *)(*(h->h_addr_list))); - } + break; /* Success */ } } } } + return res; +} +#else +int APP_CC +g_tcp_connect(int sck, const char* address, const char* port) +{ + struct sockaddr_in s; + struct hostent* h; - return connect(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); + g_memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = inet_addr(address); + if (s.sin_addr.s_addr == INADDR_NONE) + { + h = gethostbyname(address); + if (h != 0) + { + if (h->h_name != 0) + { + if (h->h_addr_list != 0) + { + if ((*(h->h_addr_list)) != 0) + { + s.sin_addr.s_addr = *((int*)(*(h->h_addr_list))); + } + } + } + } + } + return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } +#endif /*****************************************************************************/ /* returns error, zero is good */ @@ -574,23 +645,133 @@ g_tcp_set_non_blocking(int sck) return 0; } +#if 0 +/*****************************************************************************/ +/* return boolean */ +static int APP_CC +address_match(const char *address, struct addrinfo *j) +{ + struct sockaddr_in *ipv4_in; + struct sockaddr_in6 *ipv6_in; + + if (address == 0) + { + return 1; + } + if (address[0] == 0) + { + return 1; + } + if (g_strcmp(address, "0.0.0.0") == 0) + { + return 1; + } + if ((g_strcmp(address, "127.0.0.1") == 0) || + (g_strcmp(address, "::1") == 0) || + (g_strcmp(address, "localhost") == 0)) + { + if (j->ai_addr != 0) + { + if (j->ai_addr->sa_family == AF_INET) + { + ipv4_in = (struct sockaddr_in *) (j->ai_addr); + if (inet_pton(AF_INET, "127.0.0.1", &(ipv4_in->sin_addr))) + { + return 1; + } + } + if (j->ai_addr->sa_family == AF_INET6) + { + ipv6_in = (struct sockaddr_in6 *) (j->ai_addr); + if (inet_pton(AF_INET6, "::1", &(ipv6_in->sin6_addr))) + { + return 1; + } + } + } + } + if (j->ai_addr != 0) + { + if (j->ai_addr->sa_family == AF_INET) + { + ipv4_in = (struct sockaddr_in *) (j->ai_addr); + if (inet_pton(AF_INET, address, &(ipv4_in->sin_addr))) + { + return 1; + } + } + if (j->ai_addr->sa_family == AF_INET6) + { + ipv6_in = (struct sockaddr_in6 *) (j->ai_addr); + if (inet_pton(AF_INET6, address, &(ipv6_in->sin6_addr))) + { + return 1; + } + } + } + return 0; +} +#endif + +#if 0 +/*****************************************************************************/ +/* returns error, zero is good */ +static int APP_CC +g_tcp_bind_flags(int sck, const char *port, const char *address, int flags) +{ + int res; + int error; + struct addrinfo hints; + struct addrinfo *i; + + res = -1; + g_memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = flags; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + error = getaddrinfo(NULL, port, &hints, &i); + if (error == 0) + { + while ((i != 0) && (res < 0)) + { + if (address_match(address, i)) + { + res = bind(sck, i->ai_addr, i->ai_addrlen); + } + i = i->ai_next; + } + } + return res; +} + /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_bind(int sck, char *port) +g_tcp_bind(int sck, const char *port) { - struct sockaddr_in s; + int flags; + + flags = AI_ADDRCONFIG | AI_PASSIVE; + return g_tcp_bind_flags(sck, port, 0, flags); +} +#else +int APP_CC +g_tcp_bind(int sck, const char* port) +{ + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; - return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } +#endif /*****************************************************************************/ int APP_CC -g_tcp_local_bind(int sck, char *port) +g_tcp_local_bind(int sck, const char *port) { #if defined(_WIN32) return -1; @@ -604,25 +785,34 @@ g_tcp_local_bind(int sck, char *port) #endif } +#if 0 /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_bind_address(int sck, char *port, const char *address) +g_tcp_bind_address(int sck, const char *port, const char *address) { - struct sockaddr_in s; - - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; + int flags; - if (inet_aton(address, &s.sin_addr) < 0) - { - return -1; /* bad address */ - } + flags = AI_ADDRCONFIG | AI_PASSIVE; + return g_tcp_bind_flags(sck, port, address, flags); +} +#else +int APP_CC +g_tcp_bind_address(int sck, const char* port, const char* address) +{ + struct sockaddr_in s; - return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + if (inet_aton(address, &s.sin_addr) < 0) + { + return -1; /* bad address */ + } + return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); } +#endif /*****************************************************************************/ /* returns error, zero is good */ @@ -636,6 +826,8 @@ g_tcp_listen(int sck) int APP_CC g_tcp_accept(int sck) { + int ret ; + char ipAddr[256] ; struct sockaddr_in s; #if defined(_WIN32) signed int i; @@ -645,7 +837,14 @@ g_tcp_accept(int sck) i = sizeof(struct sockaddr_in); memset(&s, 0, i); - return accept(sck, (struct sockaddr *)&s, &i); + ret = accept(sck, (struct sockaddr *)&s, &i); + if(ret>0) + { + snprintf(ipAddr,255,"A connection received from: %s port %d" + ,inet_ntoa(s.sin_addr),ntohs(s.sin_port)); + log_message(LOG_LEVEL_INFO,ipAddr); + } + return ret ; } /*****************************************************************************/ @@ -2004,7 +2203,7 @@ g_htoi(char *str) /*****************************************************************************/ int APP_CC -g_pos(char *str, const char *to_find) +g_pos(const char *str, const char *to_find) { char *pp; diff --git a/common/os_calls.h b/common/os_calls.h index d4b86365..5844df27 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,11 +78,11 @@ g_tcp_force_recv(int sck, char* data, int len); int APP_CC g_tcp_set_non_blocking(int sck); int APP_CC -g_tcp_bind(int sck, char* port); +g_tcp_bind(int sck, const char *port); int APP_CC -g_tcp_local_bind(int sck, char* port); +g_tcp_local_bind(int sck, const char* port); int APP_CC -g_tcp_bind_address(int sck, char* port, const char* address); +g_tcp_bind_address(int sck, const char* port, const char* address); int APP_CC g_tcp_listen(int sck); int APP_CC @@ -196,7 +196,7 @@ g_atoi(const char* str); int APP_CC g_htoi(char* str); int APP_CC -g_pos(char* str, const char* to_find); +g_pos(const char* str, const char* to_find); int APP_CC g_mbstowcs(twchar* dest, const char* src, int n); int APP_CC diff --git a/common/parse.h b/common/parse.h index deee7845..49c2fa23 100644 --- a/common/parse.h +++ b/common/parse.h @@ -101,7 +101,6 @@ struct stream #define s_mark_end(s) \ (s)->end = (s)->p -/******************************************************************************/ #define in_sint8(s, v) do \ { \ (v) = *((signed char*)((s)->p)); \ @@ -303,4 +302,102 @@ struct stream (s)->p += (n); \ } while (0) +/* + * @brief allocate a new stream + * + * @param _s opaque handle to the new stream + * @param _l length of new stream + ******************************************************************************/ +#define xstream_new(_s, _l) \ +do \ +{ \ + make_stream((_s)); \ + init_stream((_s), (_l)); \ +} while (0) + +/** + * @brief release a previously allocated stream + * + * @param _s opaque handle returned by stream_new() + *****************************************************************************/ +#define xstream_free(_s) free_stream(_s) + +#define xstream_rd_u8(_s, _var) in_uint8(_s, _var) +#define xstream_rd_u16_le(_s, _var) in_uint16_le(_s, _var) +#define xstream_rd_u32_le(_s, _var) in_uint32_le(_s, _var) + +#define xstream_rd_s8_le(_s, _var) in_sint8(_s, _var) +#define xstream_rd_s16_le(_s, _var) in_sint16_le(_s, _var) +#define xstream_rd_s32_le(_s, _var) TODO + +#define xstream_wr_u8(_s, _var) out_uint8(_s, _var) +#define xstream_wr_u16_le(_s, _var) out_uint16_le(_s, _var) +#define xstream_wr_u32_le(_s, _var) out_uint32_le(_s, _var) + +#define xstream_wr_s8(_s, _var) TODO +#define xstream_wr_s16_le(_s, _var) TODO +#define xstream_wr_s32_le(_s, _var) TODO + +#define xstream_rd_u64_le(_s, _v) \ +do \ +{ \ + _v = \ + (tui64)(*((unsigned char *)_s->p)) | \ + (((tui64) (*(((unsigned char *)_s->p) + 1))) << 8) | \ + (((tui64) (*(((unsigned char *)_s->p) + 2))) << 16) | \ + (((tui64) (*(((unsigned char *)_s->p) + 3))) << 24) | \ + (((tui64) (*(((unsigned char *)_s->p) + 4))) << 32) | \ + (((tui64) (*(((unsigned char *)_s->p) + 5))) << 40) | \ + (((tui64) (*(((unsigned char *)_s->p) + 6))) << 48) | \ + (((tui64) (*(((unsigned char *)_s->p) + 7))) << 56); \ + _s->p += 8; \ +} while (0) + +#define xstream_wr_u64_le(_s, _v) \ +do \ +{ \ + *(((unsigned char *) _s->p) + 0) = (unsigned char) ((_v >> 0) & 0xff); \ + *(((unsigned char *) _s->p) + 1) = (unsigned char) ((_v >> 8) & 0xff); \ + *(((unsigned char *) _s->p) + 2) = (unsigned char) ((_v >> 16) & 0xff); \ + *(((unsigned char *) _s->p) + 3) = (unsigned char) ((_v >> 24) & 0xff); \ + *(((unsigned char *) _s->p) + 4) = (unsigned char) ((_v >> 32) & 0xff); \ + *(((unsigned char *) _s->p) + 5) = (unsigned char) ((_v >> 40) & 0xff); \ + *(((unsigned char *) _s->p) + 6) = (unsigned char) ((_v >> 48) & 0xff); \ + *(((unsigned char *) _s->p) + 7) = (unsigned char) ((_v >> 56) & 0xff); \ + _s->p += 8; \ +} while (0) + +/* copy data into stream */ +#define xstream_copyin(_s, _dest, _len) \ +do \ +{ \ + g_memcpy((_s)->p, (_dest), (_len)); \ + (_s)->p += (_len); \ +} while (0) + +/* copy data out of stream */ +#define xstream_copyout(_dest, _s, _len) \ +do \ +{ \ + g_memcpy((_dest), (_s)->p, (_len)); \ + (_s)->p += (_len); \ +} while (0) + +#define xstream_rd_string(_dest, _s, _len) \ +do \ +{ \ + g_memcpy((_dest), (_s)->p, (_len)); \ + (_s)->p += (_len); \ +} while (0) + +#define xstream_wr_string(_s, _src, _len) \ +do \ +{ \ + g_memcpy((_s)->p, (_src), (_len)); \ + (_s)->p += (_len); \ +} while (0) + +#define xstream_len(_s) (int) ((_s)->p - (_s)->data) +#define xstream_seek(_s, _len) (_s)->p += (_len) + #endif diff --git a/common/trans.h b/common/trans.h index 36d08a7c..1133477a 100644 --- a/common/trans.h +++ b/common/trans.h @@ -41,7 +41,7 @@ typedef int (*ttrans_conn_in)(struct trans* self, struct trans* new_self); struct trans { - tbus sck; + tbus sck; /* socket handle */ int mode; /* 1 tcp, 2 unix socket */ int status; int type1; /* 1 listener 2 server 3 client */ diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index a364927d..591d49d7 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,7 +86,11 @@ struct xrdp_client_info int jpeg_prop_len; char jpeg_prop[64]; int v3_codec_id; + int rfx_min_pixel; + char orders[32]; + int order_flags_ex; int use_bulk_comp; + int pointer_flags; /* 0 color, 1 new */ }; #endif diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 1aa18eb5..d6ea3a96 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -126,6 +126,7 @@ #define RDP_POINTER_MOVE 3 #define RDP_POINTER_COLOR 6 #define RDP_POINTER_CACHED 7 +#define RDP_POINTER_POINTER 8 #define RDP_NULL_POINTER 0 #define RDP_DEFAULT_POINTER 0x7F00 diff --git a/configure.ac b/configure.ac index 6dd4052e..92655612 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,10 @@ AC_ARG_ENABLE(freerdp1, AS_HELP_STRING([--enable-freerdp1], [Build freerdp1 module (default: no)]), [freerdp1=true], [freerdp1=false]) AM_CONDITIONAL(XRDP_FREERDP1, [test x$freerdp1 = xtrue]) +AC_ARG_ENABLE(neutrinordp, AS_HELP_STRING([--enable-neutrinordp], + [Build neutrinordp module (default: no)]), + [neutrinordp=true], [neutrinordp=false]) +AM_CONDITIONAL(XRDP_NEUTRINORDP, [test x$neutrinordp = xtrue]) AC_ARG_ENABLE(jpeg, AS_HELP_STRING([--enable-jpeg], [Build jpeg module (default: no)]), [jpeg=true], [jpeg=false]) @@ -69,8 +73,20 @@ then fi fi +AC_CHECK_MEMBER([struct in6_addr.s6_addr], + [], + [AC_DEFINE(NO_ARPA_INET_H_IP6, 1, [for IPv6])], + [#include <arpa/inet.h>]) + +if test "x$enable_nopam" = "xyes" +then + AC_DEFINE([USE_NOPAM],1,[Disable PAM]) +fi + AS_IF( [test "x$enable_freerdp1" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] ) +AS_IF( [test "x$enable_neutrinordp" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] ) + # checking for libjpeg if ! test -z "$enable_jpeg" then @@ -113,6 +129,7 @@ AC_CONFIG_FILES([Makefile xup/Makefile mc/Makefile freerdp1/Makefile + neutrinordp/Makefile xrdp/Makefile sesman/Makefile sesman/libscp/Makefile @@ -124,6 +141,8 @@ AC_CONFIG_FILES([Makefile docs/man/Makefile instfiles/Makefile instfiles/pam.d/Makefile + instfiles/init.d/Makefile + instfiles/default/Makefile genkeymap/Makefile xrdpapi/Makefile xrdpvr/Makefile diff --git a/description-pak b/description-pak new file mode 100644 index 00000000..9be64541 --- /dev/null +++ b/description-pak @@ -0,0 +1 @@ +RDP server for Linux diff --git a/freerdp1/xrdp-freerdp.c b/freerdp1/xrdp-freerdp.c index f50e22fa..ca4fe31f 100644 --- a/freerdp1/xrdp-freerdp.c +++ b/freerdp1/xrdp-freerdp.c @@ -17,9 +17,12 @@ * limitations under the License. */ +#include <freerdp/settings.h> +#include <X11/Xlib.h> #include "xrdp-freerdp.h" #include "xrdp-color.h" #include "xrdp_rail.h" +#include "log.h" #ifdef XRDP_DEBUG #define LOG_LEVEL 99 @@ -39,6 +42,18 @@ struct mod_context }; typedef struct mod_context modContext; +void verifyColorMap(struct mod *mod) +{ + int i ; + for( i = 0 ;i<255 ; i++) + { + if(mod->colormap[i]!=0) + { + return ; + } + } + LLOGLN(0, ("The colormap is all NULL\n")); +} /*****************************************************************************/ /* return error */ static int DEFAULT_CC @@ -132,13 +147,18 @@ lxrdp_connect(struct mod *mod) break; } } - + log_message(LOG_LEVEL_INFO,buf); mod->server_msg(mod, buf, 0); } #endif + log_message(LOG_LEVEL_INFO,"freerdp_connect Failed to destination :%s:%d",mod->inst->settings->ServerHostname,mod->inst->settings->ServerPort); return 1; } + else + { + log_message(LOG_LEVEL_INFO,"freerdp_connect returned Success to destination :%s:%d",mod->inst->settings->ServerHostname,mod->inst->settings->ServerPort); + } return 0; } @@ -158,7 +178,7 @@ lxrdp_event(struct mod *mod, int msg, long param1, long param2, int lchid; char *data; - LLOGLN(10, ("lxrdp_event: msg %d", msg)); + LLOGLN(12, ("lxrdp_event: msg %d", msg)); switch (msg) { @@ -169,53 +189,53 @@ lxrdp_event(struct mod *mod, int msg, long param1, long param2, mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); break; case 17: /*Synchronize*/ - LLOGLN(0, ("Synchronized event handled")); + LLOGLN(11, ("Synchronized event handled")); mod->inst->input->SynchronizeEvent(mod->inst->input, 0); break; case 100: /* mouse move */ - LLOGLN(10, ("mouse move %d %d", param1, param2)); + LLOGLN(12, ("mouse move %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_MOVE; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 101: /* left button up */ - LLOGLN(10, ("left button up %d %d", param1, param2)); + LLOGLN(12, ("left button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON1; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 102: /* left button down */ - LLOGLN(10, ("left button down %d %d", param1, param2)); + LLOGLN(12, ("left button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 103: /* right button up */ - LLOGLN(10, ("right button up %d %d", param1, param2)); + LLOGLN(12, ("right button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON2; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 104: /* right button down */ - LLOGLN(10, ("right button down %d %d", param1, param2)); + LLOGLN(12, ("right button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 105: /* middle button up */ - LLOGLN(10, ("middle button up %d %d", param1, param2)); + LLOGLN(12, ("middle button up %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON3; mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); break; case 106: /* middle button down */ - LLOGLN(10, ("middle button down %d %d", param1, param2)); + LLOGLN(12, ("middle button down %d %d", param1, param2)); x = param1; y = param2; flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; @@ -232,7 +252,7 @@ lxrdp_event(struct mod *mod, int msg, long param1, long param2, case 110: break; case 200: - LLOGLN(10, ("Invalidate request sent from client")); + LLOGLN(12, ("Invalidate request sent from client")); RECTANGLE_16 *rectangle = (RECTANGLE_16 *) g_malloc(sizeof(RECTANGLE_16), 0); /* The parameters are coded as follows param1 = MAKELONG(y, x), param2 =MAKELONG(h, w) * #define MAKELONG(lo, hi) ((((hi) & 0xffff) << 16) | ((lo) & 0xffff)) @@ -282,7 +302,7 @@ lxrdp_event(struct mod *mod, int msg, long param1, long param2, size = (int)param2; data = (char *)param3; total_size = (int)param4; - LLOGLN(10, ("lxrdp_event: client to server flags %d", flags)); + LLOGLN(12, ("lxrdp_event: client to server flags %d", flags)); if ((chanid < 0) || (chanid >= mod->inst->settings->ChannelDefArraySize)) { @@ -428,7 +448,7 @@ lxrdp_set_param(struct mod *mod, char *name, char *value) static int DEFAULT_CC lxrdp_session_change(struct mod *mod, int a, int b) { - LLOGLN(10, ("lxrdp_session_change:")); + LLOGLN(0, ("lxrdp_session_change: - no code here")); return 0; } @@ -441,7 +461,7 @@ lxrdp_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, void **wfds; BOOL ok; - LLOGLN(10, ("lxrdp_get_wait_objs:")); + LLOGLN(12, ("lxrdp_get_wait_objs:")); rfds = (void **)read_objs; wfds = (void **)write_objs; ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); @@ -461,7 +481,7 @@ lxrdp_check_wait_objs(struct mod *mod) { BOOL ok; - LLOGLN(10, ("lxrdp_check_wait_objs:")); + LLOGLN(12, ("lxrdp_check_wait_objs:")); ok = freerdp_check_fds(mod->inst); if (!ok) @@ -550,7 +570,7 @@ lfreerdp_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) for (index = 0; index < bitmap->number; index++) { - bd = bitmap->rectangles + index; + bd = &bitmap->rectangles[index]; cx = (bd->destRight - bd->destLeft) + 1; cy = (bd->destBottom - bd->destTop) + 1; line_bytes = server_Bpp * bd->width; @@ -558,12 +578,16 @@ lfreerdp_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) if (bd->compressed) { - bitmap_decompress(bd->bitmapDataStream, (tui8 *)dst_data, bd->width, - bd->height, bd->bitmapLength, server_bpp, server_bpp); + LLOGLN(20,("decompress size : %d",bd->bitmapLength)); + if(!bitmap_decompress(bd->bitmapDataStream, (tui8 *)dst_data, bd->width, + bd->height, bd->bitmapLength, server_bpp, server_bpp)){ + LLOGLN(0,("Failure to decompress the bitmap")); + } } else { /* bitmap is upside down */ + LLOGLN(10,("bitmap upside down")); src = (char *)(bd->bitmapDataStream); dst = dst_data + bd->height * line_bytes; @@ -627,6 +651,10 @@ lfreerdp_pat_blt(rdpContext *context, PATBLT_ORDER *patblt) bgcolor = convert_color(server_bpp, client_bpp, patblt->backColor, mod->colormap); + if(fgcolor==bgcolor) + { + LLOGLN(0, ("Warning same color on both bg and fg")); + } mod->server_set_mixmode(mod, 1); mod->server_set_opcode(mod, patblt->bRop); mod->server_set_fgcolor(mod, fgcolor); @@ -800,7 +828,7 @@ lfreerdp_line_to(rdpContext *context, LINE_TO_ORDER *line_to) static void DEFAULT_CC lfreerdp_cache_bitmap(rdpContext *context, CACHE_BITMAP_ORDER *cache_bitmap_order) { - LLOGLN(10, ("lfreerdp_cache_bitmap:")); + LLOGLN(0, ("lfreerdp_cache_bitmap: - no code here")); } /******************************************************************************/ @@ -862,6 +890,7 @@ lfreerdp_cache_bitmapV2(rdpContext *context, if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: CBR2_DO_NOT_CACHE")); idx = 4096 - 1; } @@ -1010,7 +1039,7 @@ static void DEFAULT_CC lfreerdp_pointer_position(rdpContext *context, POINTER_POSITION_UPDATE *pointer_position) { - LLOGLN(0, ("lfreerdp_pointer_position:")); + LLOGLN(0, ("lfreerdp_pointer_position: - no code here")); } /******************************************************************************/ @@ -1018,7 +1047,7 @@ static void DEFAULT_CC lfreerdp_pointer_system(rdpContext *context, POINTER_SYSTEM_UPDATE *pointer_system) { - LLOGLN(0, ("lfreerdp_pointer_system: - no code here")); + LLOGLN(0, ("lfreerdp_pointer_system: - no code here type value = %d",pointer_system->type)); } /******************************************************************************/ @@ -1026,7 +1055,7 @@ static void DEFAULT_CC lfreerdp_pointer_color(rdpContext *context, POINTER_COLOR_UPDATE *pointer_color) { - LLOGLN(0, ("lfreerdp_pointer_color:")); + LLOGLN(0, ("lfreerdp_pointer_color: - no code here")); } /******************************************************************************/ @@ -1131,18 +1160,25 @@ lfreerdp_pointer_new(rdpContext *context, tui8 *src; mod = ((struct mod_context *)context)->modi; - LLOGLN(0, ("lfreerdp_pointer_new:")); - LLOGLN(0, (" bpp %d", pointer_new->xorBpp)); - LLOGLN(0, (" width %d height %d", pointer_new->colorPtrAttr.width, + LLOGLN(20, ("lfreerdp_pointer_new:")); + LLOGLN(20, (" bpp %d", pointer_new->xorBpp)); + LLOGLN(20, (" width %d height %d", pointer_new->colorPtrAttr.width, pointer_new->colorPtrAttr.height)); - LLOGLN(0, (" lengthXorMask %d lengthAndMask %d", + LLOGLN(20, (" lengthXorMask %d lengthAndMask %d", pointer_new->colorPtrAttr.lengthXorMask, pointer_new->colorPtrAttr.lengthAndMask)); index = pointer_new->colorPtrAttr.cacheIndex; - - if (pointer_new->xorBpp == 1 && + if(index>=32) + { + LLOGLN(0,("pointer index too big")); + return ; + } + // In this fix we remove the xorBpp check, even if + // the mouse pointers are not correct we can use them. + // Configure your destination not to use windows Aero as pointer scheme + else if ( // pointer_new->xorBpp == 1 && pointer_new->colorPtrAttr.width == 32 && pointer_new->colorPtrAttr.height == 32 && index < 32) @@ -1165,15 +1201,15 @@ lfreerdp_pointer_new(rdpContext *context, //memcpy(mod->pointer_cache[index].mask, // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); - mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, + mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, mod->pointer_cache[index].mask); } else { - LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d", + LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d index: %d", pointer_new->xorBpp, pointer_new->colorPtrAttr.width, - pointer_new->colorPtrAttr.height)); + pointer_new->colorPtrAttr.height,index)); } free(pointer_new->colorPtrAttr.xorMaskData); @@ -1191,14 +1227,70 @@ lfreerdp_pointer_cached(rdpContext *context, struct mod *mod; int index; - LLOGLN(10, ("lfreerdp_pointer_cached:")); mod = ((struct mod_context *)context)->modi; index = pointer_cached->cacheIndex; - mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, + LLOGLN(10, ("lfreerdp_pointer_cached:%d", index)); + mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, mod->pointer_cache[index].mask); } +static void DEFAULT_CC lfreerdp_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) +{ + LLOGLN(0, ("lfreerdp_polygon_sc called:- not supported!!!!!!!!!!!!!!!!!!!!")); +} + +static void DEFAULT_CC lfreerdp_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) +{ + struct mod *mod; + int i, npoints; + XPoint points[4]; + int fgcolor; + int server_bpp, client_bpp; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_polygon_sc :%d(points) %d(color) %d(fillmode) %d(bRop) %d(cbData) %d(x) %d(y)", polygon_sc->numPoints,polygon_sc->brushColor,polygon_sc->fillMode,polygon_sc->bRop2,polygon_sc->cbData,polygon_sc->xStart,polygon_sc->yStart)); + if(polygon_sc->numPoints==3) + { + server_bpp = mod->inst->settings->ColorDepth; + client_bpp = mod->bpp; + + points[0].x = polygon_sc->xStart; + points[0].y = polygon_sc->yStart; + + for (i = 0; i < polygon_sc->numPoints; i++) + { + points[i + 1].x = polygon_sc->points[i].x; + points[i + 1].y = polygon_sc->points[i].y; + } + fgcolor = convert_color(server_bpp, client_bpp, + polygon_sc->brushColor, mod->colormap); + + mod->server_set_opcode(mod, polygon_sc->bRop2); + mod->server_set_bgcolor(mod, 255); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_pen(mod, 1, 1); // style, width + // TODO replace with correct brush; this is a workaround + // This workaround handles the text cursor in microsoft word. + mod->server_draw_line(mod,polygon_sc->xStart,polygon_sc->yStart,polygon_sc->xStart,polygon_sc->yStart+points[2].y); +// mod->server_fill_rect(mod, points[0].x, points[0].y, +// points[0].x-points[3].x, points[0].y-points[2].y); +// mod->server_set_brush(mod,); // howto use this on our indata?? + mod->server_set_opcode(mod, 0xcc); + } + else + { + LLOGLN(0, ("Not handled number of points in lfreerdp_polygon_sc")); + } +} + +static void DEFAULT_CC lfreerdp_syncronize(rdpContext* context) +{ + struct mod *mod; + mod = ((struct mod_context *)context)->modi; + LLOGLN(0, ("lfreerdp_synchronize received - not handled")); +} + /******************************************************************************/ static BOOL DEFAULT_CC lfreerdp_pre_connect(freerdp *instance) @@ -1213,6 +1305,7 @@ lfreerdp_pre_connect(freerdp *instance) LLOGLN(0, ("lfreerdp_pre_connect:")); mod = ((struct mod_context *)(instance->context))->modi; + verifyColorMap(mod); num_chans = 0; index = 0; error = mod->server_query_channel(mod, index, ch_name, &ch_flags); @@ -1235,6 +1328,7 @@ lfreerdp_pre_connect(freerdp *instance) // TODO // instance->settings->offscreen_bitmap_cache = false; instance->settings->OffscreenSupportLevel = 0; + instance->settings->DrawNineGridEnabled = 0 ; // TODO //instance->settings->glyph_cache = true; @@ -1262,6 +1356,7 @@ lfreerdp_pre_connect(freerdp *instance) instance->settings->BitmapCacheV2CellInfo[4].numEntries = 0; // 2048; instance->settings->BitmapCacheV2CellInfo[4].persistent = FALSE; + // instance->settings->BitmapCacheV3Enabled = FALSE; instance->settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; instance->settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; instance->settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; @@ -1273,20 +1368,28 @@ lfreerdp_pre_connect(freerdp *instance) if (mod->client_info.rail_support_level > 0) { + LLOGLN(0, ("Railsupport !!!!!!!!!!!!!!!!!!")); instance->settings->RemoteApplicationMode = TRUE; instance->settings->RemoteAppLanguageBarSupported = TRUE; instance->settings->Workarea = TRUE; instance->settings->PerformanceFlags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG; } - + else + { + LLOGLN(10, ("Special PerformanceFlags changed")); + instance->settings->PerformanceFlags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS | PERF_DISABLE_THEMING ; // | PERF_DISABLE_CURSOR_SHADOW | PERF_DISABLE_CURSORSETTINGS ; + } + instance->settings->CompressionEnabled = FALSE ; + instance->settings->IgnoreCertificate = TRUE ; + // here - //instance->settings->rdp_version = 4; + //instance->settings->RdpVersion = 4; instance->update->BeginPaint = lfreerdp_begin_paint; instance->update->EndPaint = lfreerdp_end_paint; instance->update->SetBounds = lfreerdp_set_bounds; instance->update->BitmapUpdate = lfreerdp_bitmap_update; - + instance->update->Synchronize = lfreerdp_syncronize ; instance->update->primary->DstBlt = lfreerdp_dst_blt; instance->update->primary->PatBlt = lfreerdp_pat_blt; instance->update->primary->ScrBlt = lfreerdp_scr_blt; @@ -1294,7 +1397,8 @@ lfreerdp_pre_connect(freerdp *instance) instance->update->primary->MemBlt = lfreerdp_mem_blt; instance->update->primary->GlyphIndex = lfreerdp_glyph_index; instance->update->primary->LineTo = lfreerdp_line_to; - + instance->update->primary->PolygonSC = lfreerdp_polygon_sc ; + instance->update->primary->PolygonCB = lfreerdp_polygon_cb; instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; @@ -1613,7 +1717,7 @@ lfreerdp_context_new(freerdp *instance, rdpContext *context) static void DEFAULT_CC lfreerdp_context_free(freerdp *instance, rdpContext *context) { - LLOGLN(0, ("lfreerdp_context_free:")); + LLOGLN(0, ("lfreerdp_context_free: - no code here")); } /******************************************************************************/ @@ -1662,7 +1766,7 @@ static BOOL DEFAULT_CC lfreerdp_authenticate(freerdp *instance, char **username, char **password, char **domain) { - LLOGLN(0, ("lfreerdp_authenticate:")); + LLOGLN(0, ("lfreerdp_authenticate: - no code here")); return TRUE; } @@ -1671,7 +1775,7 @@ static BOOL DEFAULT_CC lfreerdp_verify_certificate(freerdp *instance, char *subject, char *issuer, char *fingerprint) { - LLOGLN(0, ("lfreerdp_verify_certificate:")); + LLOGLN(0, ("lfreerdp_verify_certificate: - no code here")); return TRUE; } @@ -1714,7 +1818,7 @@ mod_init(void) lcon = (modContext *)(mod->inst->context); lcon->modi = mod; - LLOGLN(10, ("mod_init: mod %p", mod)); + LLOGLN(10, ("mod_init: mod %p", mod)); return mod; } diff --git a/freerdp1/xrdp-freerdp.h b/freerdp1/xrdp-freerdp.h index 1022e21d..c2956b4d 100644 --- a/freerdp1/xrdp-freerdp.h +++ b/freerdp1/xrdp-freerdp.h @@ -85,7 +85,7 @@ struct mod int srcx, int srcy); int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, char* data, int width, int height, int srcx, int srcy); - int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); + int (*server_set_pointer)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); int (*server_msg)(struct mod* v, char* msg, int code); int (*server_is_term)(struct mod* v); diff --git a/genkeymap/dump-keymaps.sh b/genkeymap/dump-keymaps.sh index 7f13b73e..e0f3b3b2 100755 --- a/genkeymap/dump-keymaps.sh +++ b/genkeymap/dump-keymaps.sh @@ -27,5 +27,9 @@ setxkbmap -model pc104 -layout ru setxkbmap -model pc104 -layout se ./xrdp-genkeymap ../instfiles/km-041d.ini +# Portuguese -PT 'pt-pt' 0x0816 +setxkbmap -model pc104 -layout pt +./xrdp-genkeymap ../instfiles/km-0816.ini + # set back to en-us setxkbmap -model pc104 -layout us diff --git a/instfiles/Makefile.am b/instfiles/Makefile.am index 4cabd942..7ba86d3d 100644 --- a/instfiles/Makefile.am +++ b/instfiles/Makefile.am @@ -1,9 +1,11 @@ -EXTRA_DIST = xrdp.sh km-0407.ini km-0409.ini km-040c.ini km-0410.ini km-0419.ini km-041d.ini \ +EXTRA_DIST = xrdp.sh km-0407.ini km-0409.ini km-040c.ini km-0410.ini km-0419.ini km-041d.ini km-0816.ini \ xrdp-sesman.service \ xrdp.service SUBDIRS = \ - pam.d + pam.d \ + init.d \ + default if HAVE_SYSTEMD systemdsystemunit_DATA = \ @@ -20,8 +22,10 @@ startscript_DATA = \ km-040c.ini \ km-0410.ini \ km-0419.ini \ - km-041d.ini + km-041d.ini \ + km-0816.ini # must be tab below install-data-hook: chmod 755 $(DESTDIR)$(sysconfdir)/xrdp/xrdp.sh + chmod 755 $(DESTDIR)$(sysconfdir)/init.d/xrdp diff --git a/instfiles/default/Makefile.am b/instfiles/default/Makefile.am new file mode 100644 index 00000000..6a7f4f2b --- /dev/null +++ b/instfiles/default/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST = xrdp +startscriptdir=$(sysconfdir)/default +startscript_DATA = xrdp diff --git a/instfiles/default/xrdp b/instfiles/default/xrdp new file mode 100644 index 00000000..bc51ce82 --- /dev/null +++ b/instfiles/default/xrdp @@ -0,0 +1,5 @@ +# Do we need to start sesman ? +SESMAN_START=yes +# Do we restart xrdp on upgrade ? If not set to no, any xrdp session will +# be shutdown on upgrade. +# RESTART_ON_UPGRADE=no diff --git a/instfiles/init.d/Makefile.am b/instfiles/init.d/Makefile.am new file mode 100644 index 00000000..ae411c20 --- /dev/null +++ b/instfiles/init.d/Makefile.am @@ -0,0 +1,4 @@ +EXTRA_DIST = xrdp +startscriptdir=$(sysconfdir)/init.d +startscript_DATA = xrdp + diff --git a/instfiles/init.d/xrdp b/instfiles/init.d/xrdp new file mode 100644 index 00000000..2cf20999 --- /dev/null +++ b/instfiles/init.d/xrdp @@ -0,0 +1,185 @@ +#!/bin/sh -e +# +# start/stop xrdp and sesman daemons +# +### BEGIN INIT INFO +# Provides: xrdp +# Required-Start: $network $remote_fs +# Required-Stop: $network $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start xrdp and sesman daemons +# Description: XRDP uses the Remote Desktop Protocol to present a +# graphical login to a remote client allowing connection +# to a VNC server or another RDP server. +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/xrdp +PIDDIR=/var/run/xrdp/ +SESMAN_START=yes +#USERID=xrdp +# the X11rdp backend only works as root at the moment - GH 20/03/2013 +USERID=root +RSAKEYS=/etc/xrdp/rsakeys.ini +NAME=xrdp +DESC="Remote Desktop Protocol server" + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +check_root() { + if [ "$(id -u)" != "0" ]; then + log_failure_msg "You must be root to start, stop or restart $NAME." + exit 4 + fi +} + +force_stop() { + +DELAY=1 +PROCLIST="xrdp-sesman xrdp-sessvc xrdp-chansrv X11rdp Xvnc" + + for p in $PROCLIST; do + pgrep -x $p >/dev/null && pkill -x $p + sleep $DELAY + pgrep -x $p >/dev/null && pkill -9 -x $p + done + # let's not kill ourselves - the init script is called xrdp as well + pgrep -fx $DAEMON >/dev/null && pkill -fx $DAEMON + sleep $DELAY + pgrep -fx $DAEMON >/dev/null && pkill -9 -fx $DAEMON + + rm -f $PIDDIR/xrdp*.pid +} + +if [ -r /etc/default/$NAME ]; then + . /etc/default/$NAME +fi + +# Tasks that can only be run as root +if [ "$(id -u)" = "0" ]; then + # Check for pid dir + if [ ! -d $PIDDIR ] ; then + mkdir $PIDDIR + fi + chown $USERID:$USERID $PIDDIR + + # Check for rsa key + if [ ! -f $RSAKEYS ] ; then + log_action_begin_msg "Generating xrdp RSA keys..." + (umask 077 ; xrdp-keygen xrdp $RSAKEYS) + chown $USERID:$USERID $RSAKEYS + if [ ! -f $RSAKEYS ] ; then + log_action_end_msg 1 "could not create $RSAKEYS" + exit 1 + fi + log_action_end_msg 0 "done" + fi +fi + + +case "$1" in + start) + check_root + exitval=0 + log_daemon_msg "Starting $DESC " + if pidofproc -p $PIDDIR/$NAME.pid $DAEMON > /dev/null; then + log_progress_msg "$NAME apparently already running" + log_end_msg 0 + exit 0 + fi + log_progress_msg $NAME + start-stop-daemon --start --quiet --oknodo --pidfile $PIDDIR/$NAME.pid \ + --chuid $USERID:$USERID --exec $DAEMON >/dev/null + exitval=$? + if [ "$SESMAN_START" = "yes" ] ; then + log_progress_msg "sesman" + start-stop-daemon --start --quiet --oknodo --pidfile $PIDDIR/xrdp-sesman.pid \ + --exec /usr/sbin/xrdp-sesman >/dev/null + value=$? + [ $value -gt 0 ] && exitval=$value + fi + # Make pidfile readables for all users (for status to work) + [ -e $PIDDIR/xrdp-sesman.pid ] && chmod 0644 $PIDDIR/xrdp-sesman.pid + [ -e $PIDDIR/$NAME.pid ] && chmod 0644 $PIDDIR/$NAME.pid + # Note: Unfortunately, xrdp currently takes too long to create + # the pidffile unless properly patched + log_end_msg $exitval + ;; + stop) + check_root + [ -n "$XRDP_UPGRADE" -a "$RESTART_ON_UPGRADE" = "no" ] && { + echo "Upgrade in progress, no restart of xrdp." + exit 0 + } + exitval=0 + log_daemon_msg "Stopping RDP Session manager " + log_progress_msg "sesman" + if pidofproc -p $PIDDIR/xrdp-sesman.pid /usr/sbin/xrdp-sesman > /dev/null; then + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDDIR/xrdp-sesman.pid \ + --chuid $USERID:$USERID --exec /usr/sbin/xrdp-sesman + exitval=$? + else + log_progress_msg "apparently not running" + fi + log_progress_msg $NAME + if pidofproc -p $PIDDIR/$NAME.pid $DAEMON > /dev/null; then + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDDIR/$NAME.pid \ + --exec $DAEMON + value=$? + [ $value -gt 0 ] && exitval=$value + else + log_progress_msg "apparently not running" + fi + log_end_msg $exitval + ;; + force-stop) + $0 stop + # because it doesn't allways die the right way + force_stop + ;; + restart|force-reload) + check_root + $0 stop + # Wait for things to settle down + sleep 1 + $0 start + ;; + reload) + log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" + log_warning_msg "cannot re-read the config file (use restart)." + ;; + status) + exitval=0 + log_daemon_msg "Checking status of $DESC" "$NAME" + if pidofproc -p $PIDDIR/$NAME.pid $DAEMON > /dev/null; then + log_progress_msg "running" + log_end_msg 0 + else + log_progress_msg "apparently not running" + log_end_msg 1 || true + exitval=1 + fi + if [ "$SESMAN_START" = "yes" ] ; then + log_daemon_msg "Checking status of RDP Session Manager" "sesman" + if pidofproc -p $PIDDIR/xrdp-sesman.pid /usr/sbin/xrdp-sesman > /dev/null; then + log_progress_msg "running" + log_end_msg 0 + else + log_progress_msg "apparently not running" + log_end_msg 1 || true + exitval=1 + fi + fi + exit $exitval + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/instfiles/km-0414.ini b/instfiles/km-0414.ini new file mode 100644 index 00000000..08ba2ab8 --- /dev/null +++ b/instfiles/km-0414.ini @@ -0,0 +1,659 @@ +[noshift] +Key8=65406:0 +Key9=65307:27 +Key10=49:49 +Key11=50:50 +Key12=51:51 +Key13=52:52 +Key14=53:53 +Key15=54:54 +Key16=55:55 +Key17=56:56 +Key18=57:57 +Key19=48:48 +Key20=43:43 +Key21=92:92 +Key22=65288:8 +Key23=65289:9 +Key24=113:113 +Key25=119:119 +Key26=101:101 +Key27=114:114 +Key28=116:116 +Key29=121:121 +Key30=117:117 +Key31=105:105 +Key32=111:111 +Key33=112:112 +Key34=229:229 +Key35=65111:168 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=115:115 +Key40=100:100 +Key41=102:102 +Key42=103:103 +Key43=104:104 +Key44=106:106 +Key45=107:107 +Key46=108:108 +Key47=248:248 +Key48=230:230 +Key49=124:124 +Key50=65505:0 +Key51=39:39 +Key52=122:122 +Key53=120:120 +Key54=99:99 +Key55=118:118 +Key56=98:98 +Key57=110:110 +Key58=109:109 +Key59=44:44 +Key60=46:46 +Key61=45:45 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=60:60 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025074:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 +Key137=0:0 + +[shift] +Key8=65406:0 +Key9=65307:27 +Key10=33:33 +Key11=34:34 +Key12=35:35 +Key13=164:164 +Key14=37:37 +Key15=38:38 +Key16=47:47 +Key17=40:40 +Key18=41:41 +Key19=61:61 +Key20=63:63 +Key21=65104:96 +Key22=65288:8 +Key23=65056:0 +Key24=81:81 +Key25=87:87 +Key26=69:69 +Key27=82:82 +Key28=84:84 +Key29=89:89 +Key30=85:85 +Key31=73:73 +Key32=79:79 +Key33=80:80 +Key34=197:197 +Key35=65106:94 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=83:83 +Key40=68:68 +Key41=70:70 +Key42=71:71 +Key43=72:72 +Key44=74:74 +Key45=75:75 +Key46=76:76 +Key47=216:216 +Key48=198:198 +Key49=167:167 +Key50=65505:0 +Key51=42:42 +Key52=90:90 +Key53=88:88 +Key54=67:67 +Key55=86:86 +Key56=66:66 +Key57=78:78 +Key58=77:77 +Key59=59:59 +Key60=58:58 +Key61=95:95 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65032:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65463:55 +Key80=65464:56 +Key81=65465:57 +Key82=65453:45 +Key83=65460:52 +Key84=65461:53 +Key85=65462:54 +Key86=65451:43 +Key87=65457:49 +Key88=65458:50 +Key89=65459:51 +Key90=65456:48 +Key91=65452:44 +Key92=0:0 +Key93=0:0 +Key94=62:62 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=65469:61 +Key127=65515:0 +Key128=65517:0 +Key129=269025074:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 +Key137=0:0 + +[altgr] +Key8=65406:0 +Key9=65307:27 +Key10=161:161 +Key11=64:64 +Key12=163:163 +Key13=36:36 +Key14=189:189 +Key15=165:165 +Key16=123:123 +Key17=91:91 +Key18=93:93 +Key19=125:125 +Key20=177:177 +Key21=65105:180 +Key22=65288:8 +Key23=65289:9 +Key24=64:64 +Key25=435:322 +Key26=8364:8364 +Key27=174:174 +Key28=254:254 +Key29=2299:8592 +Key30=2302:8595 +Key31=2301:8594 +Key32=5053:339 +Key33=2032:960 +Key34=65111:168 +Key35=65107:126 +Key36=65293:13 +Key37=65507:0 +Key38=170:170 +Key39=223:223 +Key40=240:240 +Key41=496:273 +Key42=959:331 +Key43=689:295 +Key44=106:106 +Key45=930:312 +Key46=435:322 +Key47=65105:180 +Key48=65106:94 +Key49=166:166 +Key50=65505:0 +Key51=65113:733 +Key52=171:171 +Key53=187:187 +Key54=169:169 +Key55=2770:8220 +Key56=2771:8221 +Key57=110:110 +Key58=181:181 +Key59=65115:184 +Key60=2734:8230 +Key61=2730:8211 +Key62=65506:0 +Key63=16786117:8901 +Key64=65513:0 +Key65=160:160 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=16785938:8722 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=16777259:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=189:189 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=16785941:8725 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025074:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 +Key137=0:0 + +[capslock] +Key8=65406:0 +Key9=65307:27 +Key10=49:49 +Key11=50:50 +Key12=51:51 +Key13=52:52 +Key14=53:53 +Key15=54:54 +Key16=55:55 +Key17=56:56 +Key18=57:57 +Key19=48:48 +Key20=43:43 +Key21=92:92 +Key22=65288:8 +Key23=65289:9 +Key24=81:81 +Key25=87:87 +Key26=69:69 +Key27=82:82 +Key28=84:84 +Key29=89:89 +Key30=85:85 +Key31=73:73 +Key32=79:79 +Key33=80:80 +Key34=197:197 +Key35=65111:168 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=83:83 +Key40=68:68 +Key41=70:70 +Key42=71:71 +Key43=72:72 +Key44=74:74 +Key45=75:75 +Key46=76:76 +Key47=216:216 +Key48=198:198 +Key49=124:124 +Key50=65505:0 +Key51=39:39 +Key52=90:90 +Key53=88:88 +Key54=67:67 +Key55=86:86 +Key56=66:66 +Key57=78:78 +Key58=77:77 +Key59=44:44 +Key60=46:46 +Key61=45:45 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=60:60 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025074:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 +Key137=0:0 + +[shiftcapslock] +Key8=65406:0 +Key9=65307:27 +Key10=33:33 +Key11=34:34 +Key12=35:35 +Key13=164:164 +Key14=37:37 +Key15=38:38 +Key16=47:47 +Key17=40:40 +Key18=41:41 +Key19=61:61 +Key20=63:63 +Key21=65104:96 +Key22=65288:8 +Key23=65056:0 +Key24=113:113 +Key25=119:119 +Key26=101:101 +Key27=114:114 +Key28=116:116 +Key29=121:121 +Key30=117:117 +Key31=105:105 +Key32=111:111 +Key33=112:112 +Key34=229:229 +Key35=65106:94 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=115:115 +Key40=100:100 +Key41=102:102 +Key42=103:103 +Key43=104:104 +Key44=106:106 +Key45=107:107 +Key46=108:108 +Key47=248:248 +Key48=230:230 +Key49=167:167 +Key50=65505:0 +Key51=42:42 +Key52=122:122 +Key53=120:120 +Key54=99:99 +Key55=118:118 +Key56=98:98 +Key57=110:110 +Key58=109:109 +Key59=59:59 +Key60=58:58 +Key61=95:95 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65032:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65463:55 +Key80=65464:56 +Key81=65465:57 +Key82=65453:45 +Key83=65460:52 +Key84=65461:53 +Key85=65462:54 +Key86=65451:43 +Key87=65457:49 +Key88=65458:50 +Key89=65459:51 +Key90=65456:48 +Key91=65452:44 +Key92=0:0 +Key93=0:0 +Key94=62:62 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=65469:61 +Key127=65515:0 +Key128=65517:0 +Key129=269025074:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 +Key137=0:0 diff --git a/instfiles/km-0816.ini b/instfiles/km-0816.ini new file mode 100644 index 00000000..bf3def89 --- /dev/null +++ b/instfiles/km-0816.ini @@ -0,0 +1,659 @@ +[noshift] +Key8=0:0 +Key9=65307:27 +Key10=49:49 +Key11=50:50 +Key12=51:51 +Key13=52:52 +Key14=53:53 +Key15=54:54 +Key16=55:55 +Key17=56:56 +Key18=57:57 +Key19=48:48 +Key20=39:39 +Key21=171:171 +Key22=65288:8 +Key23=65289:9 +Key24=113:113 +Key25=119:119 +Key26=101:101 +Key27=114:114 +Key28=116:116 +Key29=121:121 +Key30=117:117 +Key31=105:105 +Key32=111:111 +Key33=112:112 +Key34=43:43 +Key35=65105:180 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=115:115 +Key40=100:100 +Key41=102:102 +Key42=103:103 +Key43=104:104 +Key44=106:106 +Key45=107:107 +Key46=108:108 +Key47=231:231 +Key48=186:186 +Key49=92:92 +Key50=65505:0 +Key51=65107:126 +Key52=122:122 +Key53=120:120 +Key54=99:99 +Key55=118:118 +Key56=98:98 +Key57=110:110 +Key58=109:109 +Key59=44:44 +Key60=46:46 +Key61=45:45 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=65406:0 +Key94=60:60 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65312:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025170:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=269025166:0 +Key134=0:0 +Key135=65382:0 +Key136=65381:0 +Key137=0:0 + +[shift] +Key8=0:0 +Key9=65307:27 +Key10=33:33 +Key11=34:34 +Key12=35:35 +Key13=36:36 +Key14=37:37 +Key15=38:38 +Key16=47:47 +Key17=40:40 +Key18=41:41 +Key19=61:61 +Key20=63:63 +Key21=187:187 +Key22=65288:8 +Key23=65056:0 +Key24=81:81 +Key25=87:87 +Key26=69:69 +Key27=82:82 +Key28=84:84 +Key29=89:89 +Key30=85:85 +Key31=73:73 +Key32=79:79 +Key33=80:80 +Key34=42:42 +Key35=65104:96 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=83:83 +Key40=68:68 +Key41=70:70 +Key42=71:71 +Key43=72:72 +Key44=74:74 +Key45=75:75 +Key46=76:76 +Key47=199:199 +Key48=170:170 +Key49=124:124 +Key50=65505:0 +Key51=65106:94 +Key52=90:90 +Key53=88:88 +Key54=67:67 +Key55=86:86 +Key56=66:66 +Key57=78:78 +Key58=77:77 +Key59=59:59 +Key60=58:58 +Key61=95:95 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65273:0 +Key78=65300:0 +Key79=65463:55 +Key80=65464:56 +Key81=65465:57 +Key82=65453:45 +Key83=65460:52 +Key84=65461:53 +Key85=65462:54 +Key86=65451:43 +Key87=65457:49 +Key88=65458:50 +Key89=65459:51 +Key90=65456:48 +Key91=65454:46 +Key92=0:0 +Key93=65406:0 +Key94=62:62 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65312:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=65469:61 +Key127=65515:0 +Key128=65517:0 +Key129=269025170:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=269025166:0 +Key134=0:0 +Key135=65382:0 +Key136=65381:0 +Key137=0:0 + +[altgr] +Key8=0:0 +Key9=65307:27 +Key10=185:185 +Key11=64:64 +Key12=163:163 +Key13=167:167 +Key14=189:189 +Key15=172:172 +Key16=123:123 +Key17=91:91 +Key18=93:93 +Key19=125:125 +Key20=92:92 +Key21=65115:184 +Key22=65288:8 +Key23=65289:9 +Key24=64:64 +Key25=435:322 +Key26=8364:8364 +Key27=182:182 +Key28=956:359 +Key29=2299:8592 +Key30=2302:8595 +Key31=2301:8594 +Key32=248:248 +Key33=254:254 +Key34=65111:168 +Key35=65107:126 +Key36=65293:13 +Key37=65507:0 +Key38=230:230 +Key39=223:223 +Key40=240:240 +Key41=496:273 +Key42=959:331 +Key43=689:295 +Key44=106:106 +Key45=930:312 +Key46=435:322 +Key47=65105:180 +Key48=65106:94 +Key49=172:172 +Key50=65505:0 +Key51=65104:96 +Key52=171:171 +Key53=187:187 +Key54=162:162 +Key55=2770:8220 +Key56=2771:8221 +Key57=110:110 +Key58=181:181 +Key59=2211:0 +Key60=183:183 +Key61=65120:0 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=65406:0 +Key94=124:124 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65312:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025170:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=269025166:0 +Key134=0:0 +Key135=65382:0 +Key136=65381:0 +Key137=0:0 + +[capslock] +Key8=0:0 +Key9=65307:27 +Key10=49:49 +Key11=50:50 +Key12=51:51 +Key13=52:52 +Key14=53:53 +Key15=54:54 +Key16=55:55 +Key17=56:56 +Key18=57:57 +Key19=48:48 +Key20=39:39 +Key21=171:171 +Key22=65288:8 +Key23=65289:9 +Key24=81:81 +Key25=87:87 +Key26=69:69 +Key27=82:82 +Key28=84:84 +Key29=89:89 +Key30=85:85 +Key31=73:73 +Key32=79:79 +Key33=80:80 +Key34=43:43 +Key35=65105:180 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=83:83 +Key40=68:68 +Key41=70:70 +Key42=71:71 +Key43=72:72 +Key44=74:74 +Key45=75:75 +Key46=76:76 +Key47=199:199 +Key48=186:186 +Key49=92:92 +Key50=65505:0 +Key51=65107:126 +Key52=90:90 +Key53=88:88 +Key54=67:67 +Key55=86:86 +Key56=66:66 +Key57=78:78 +Key58=77:77 +Key59=44:44 +Key60=46:46 +Key61=45:45 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=65406:0 +Key94=60:60 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65312:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=269025170:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=269025166:0 +Key134=0:0 +Key135=65382:0 +Key136=65381:0 +Key137=0:0 + +[shiftcapslock] +Key8=0:0 +Key9=65307:27 +Key10=33:33 +Key11=34:34 +Key12=35:35 +Key13=36:36 +Key14=37:37 +Key15=38:38 +Key16=47:47 +Key17=40:40 +Key18=41:41 +Key19=61:61 +Key20=63:63 +Key21=187:187 +Key22=65288:8 +Key23=65056:0 +Key24=113:113 +Key25=119:119 +Key26=101:101 +Key27=114:114 +Key28=116:116 +Key29=121:121 +Key30=117:117 +Key31=105:105 +Key32=111:111 +Key33=112:112 +Key34=42:42 +Key35=65104:96 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=115:115 +Key40=100:100 +Key41=102:102 +Key42=103:103 +Key43=104:104 +Key44=106:106 +Key45=107:107 +Key46=108:108 +Key47=231:231 +Key48=170:170 +Key49=124:124 +Key50=65505:0 +Key51=65106:94 +Key52=122:122 +Key53=120:120 +Key54=99:99 +Key55=118:118 +Key56=98:98 +Key57=110:110 +Key58=109:109 +Key59=59:59 +Key60=58:58 +Key61=95:95 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65273:0 +Key78=65300:0 +Key79=65463:55 +Key80=65464:56 +Key81=65465:57 +Key82=65453:45 +Key83=65460:52 +Key84=65461:53 +Key85=65462:54 +Key86=65451:43 +Key87=65457:49 +Key88=65458:50 +Key89=65459:51 +Key90=65456:48 +Key91=65454:46 +Key92=0:0 +Key93=65406:0 +Key94=62:62 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65027:0 +Key114=0:0 +Key115=65515:0 +Key116=65312:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=65469:61 +Key127=65515:0 +Key128=65517:0 +Key129=269025170:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=269025166:0 +Key134=0:0 +Key135=65382:0 +Key136=65381:0 +Key137=0:0 diff --git a/instfiles/pam.d/xrdp-sesman b/instfiles/pam.d/xrdp-sesman index 7fdbee5b..789ce8f7 100644 --- a/instfiles/pam.d/xrdp-sesman +++ b/instfiles/pam.d/xrdp-sesman @@ -1,4 +1,5 @@ #%PAM-1.0 -auth required pam_unix.so shadow nullok -auth required pam_env.so readenv=1 -account required pam_unix.so +@include common-auth +@include common-account +@include common-session +@include common-password diff --git a/instfiles/pam.d/xrdp-sesman.other b/instfiles/pam.d/xrdp-sesman.other new file mode 100644 index 00000000..56c8d56a --- /dev/null +++ b/instfiles/pam.d/xrdp-sesman.other @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth required pam_unix.so shadow nullok +auth required pam_env.so readenv=1 +account required pam_unix.so diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index d4c9d372..19e8a2c6 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -417,44 +417,105 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, /*****************************************************************************/ int EXPORT_CC libxrdp_send_pointer(struct xrdp_session *session, int cache_idx, - char *data, char *mask, int x, int y) + char *data, char *mask, int x, int y, int bpp) { struct stream *s; char *p; + tui16 *p16; + tui32 *p32; int i; int j; + int data_bytes; DEBUG(("libxrdp_send_pointer sending cursor")); + if (bpp == 0) + { + bpp = 24; + } + /* error check */ + if ((session->client_info->pointer_flags & 1) == 0) + { + if (bpp != 24) + { + g_writeln("libxrdp_send_pointer: error"); + return 1; + } + } + if ((bpp == 15) && (bpp != 16) && (bpp != 24) && (bpp != 32)) + { + g_writeln("libxrdp_send_pointer: error"); + return 1; + } make_stream(s); init_stream(s, 8192); xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); - out_uint16_le(s, RDP_POINTER_COLOR); - out_uint16_le(s, 0); /* pad */ + if ((session->client_info->pointer_flags & 1) == 0) + { + out_uint16_le(s, RDP_POINTER_COLOR); + out_uint16_le(s, 0); /* pad */ + data_bytes = 3072; + } + else + { + out_uint16_le(s, RDP_POINTER_POINTER); + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, bpp); + data_bytes = ((bpp + 7) / 8) * 32 * 32; + } out_uint16_le(s, cache_idx); /* cache_idx */ out_uint16_le(s, x); out_uint16_le(s, y); out_uint16_le(s, 32); out_uint16_le(s, 32); out_uint16_le(s, 128); - out_uint16_le(s, 3072); - p = data; + out_uint16_le(s, data_bytes); - for (i = 0; i < 32; i++) + switch (bpp) { - for (j = 0; j < 32; j++) - { - out_uint8(s, *p); - p++; - out_uint8(s, *p); - p++; - out_uint8(s, *p); - p++; - } + case 15: + case 16: + p16 = (tui16 *) data; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + out_uint16_le(s, *p16); + p16++; + } + } + break; + case 24: + p = data; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; + } + } + break; + case 32: + p32 = (tui32 *) data; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + out_uint32_le(s, *p32); + p32++; + } + } + break; } out_uint8a(s, mask, 128); /* mask */ s_mark_end(s); - xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_POINTER); + xrdp_rdp_send_data((struct xrdp_rdp *)(session->rdp), s, + RDP_DATA_PDU_POINTER); free_stream(s); return 0; } diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index ebfc348c..9eac9733 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -91,7 +91,7 @@ libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, int bpp, char* data, int x, int y, int cx, int cy); int DEFAULT_CC libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, - char* data, char* mask, int x, int y); + char* data, char* mask, int x, int y, int bpp); int DEFAULT_CC libxrdp_set_pointer(struct xrdp_session* session, int cache_idx); int DEFAULT_CC diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 77c0d10d..dbcb0955 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -19,6 +19,7 @@ */ #include "libxrdp.h" +#include "log.h" /*****************************************************************************/ struct xrdp_mcs *APP_CC @@ -146,12 +147,12 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) { in_uint16_be(s, userid); in_uint16_be(s, chanid); - g_writeln("channel join request received %d:%d", userid, chanid); + log_message(LOG_LEVEL_DEBUG,"MCS_CJRQ - channel join request received"); DEBUG(("xrdp_mcs_recv adding channel %4.4x", chanid)); if (xrdp_mcs_send_cjcf(self, userid, chanid) != 0) { - g_writeln("Non handled error from xrdp_mcs_send_cjcf") ; + log_message(LOG_LEVEL_ERROR,"Non handled error from xrdp_mcs_send_cjcf") ; } continue; @@ -163,7 +164,7 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) } else { - g_writeln("Recieved an unhandled appid:%d", appid); + log_message(LOG_LEVEL_DEBUG,"Recieved an unhandled appid:%d",appid); } break; @@ -819,6 +820,25 @@ xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) return 0; } +/** + * Internal help function to close the socket + * @param self + */ +void close_rdp_socket(struct xrdp_mcs *self) +{ + if(self->iso_layer->tcp_layer) + { + if(self->iso_layer->tcp_layer->trans) + { + g_tcp_close(self->iso_layer->tcp_layer->trans->sck); + self->iso_layer->tcp_layer->trans->sck = 0 ; + g_writeln("xrdp_mcs_disconnect - socket closed"); + return ; + } + } + g_writeln("Failed to close socket"); +} + /*****************************************************************************/ /* returns error */ int APP_CC @@ -833,7 +853,8 @@ xrdp_mcs_disconnect(struct xrdp_mcs *self) if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); - DEBUG((" out xrdp_mcs_disconnect error")); + close_rdp_socket(self); + DEBUG((" out xrdp_mcs_disconnect error - 1")); return 1; } @@ -844,11 +865,13 @@ xrdp_mcs_disconnect(struct xrdp_mcs *self) if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); - DEBUG((" out xrdp_mcs_disconnect error")); + close_rdp_socket(self); + DEBUG((" out xrdp_mcs_disconnect error - 2")); return 1; } free_stream(s); - DEBUG((" out xrdp_mcs_disconnect")); + close_rdp_socket(self); + DEBUG(("xrdp_mcs_disconnect - close sent")); return 0; } diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c index bb95aa71..7a17759c 100644 --- a/libxrdp/xrdp_orders.c +++ b/libxrdp/xrdp_orders.c @@ -1872,9 +1872,9 @@ xrdp_orders_send_raw_bitmap(struct xrdp_orders *self, if (Bpp == 3) { pixel = GETPIXEL32(data, j, i, width); - out_uint8(self->out_s, pixel >> 16); - out_uint8(self->out_s, pixel >> 8); out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel >> 16); } else if (Bpp == 2) { @@ -2093,9 +2093,9 @@ xrdp_orders_send_raw_bitmap2(struct xrdp_orders *self, if (Bpp == 3) { pixel = GETPIXEL32(data, j, i, width); - out_uint8(self->out_s, pixel >> 16); - out_uint8(self->out_s, pixel >> 8); out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel >> 16); } else if (Bpp == 2) { diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index eff2a654..642da9b0 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,17 +114,17 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) } else { - g_writeln("Warning: Your configured crypt level is" + log_message(LOG_LEVEL_ALWAYS,"Warning: Your configured crypt level is" "undefined 'high' will be used"); client_info->crypt_level = 3; } } - else if (g_strcasecmp(item, "channel_code") == 0) + else if (g_strcasecmp(item, "allow_channels") == 0) { client_info->channel_code = text2bool(value); if (client_info->channel_code == 0) { - g_writeln("Info: All channels are disabled"); + log_message(LOG_LEVEL_DEBUG,"Info - All channels are disabled"); } } else if (g_strcasecmp(item, "max_bpp") == 0) @@ -829,6 +829,7 @@ xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, int i; char order_caps[32]; int ex_flags; + int cap_flags; DEBUG(("order capabilities")); in_uint8s(s, 20); /* Terminal desc, pad */ @@ -837,8 +838,9 @@ xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, in_uint8s(s, 2); /* Pad */ in_uint8s(s, 2); /* Max order level */ in_uint8s(s, 2); /* Number of fonts */ - in_uint8s(s, 2); /* Capability flags */ + in_uint16_le(s, cap_flags); /* Capability flags */ in_uint8a(s, order_caps, 32); /* Orders supported */ + g_memcpy(self->client_info.orders, order_caps, 32); DEBUG(("dest blt-0 %d", order_caps[0])); DEBUG(("pat blt-1 %d", order_caps[1])); DEBUG(("screen blt-2 %d", order_caps[2])); @@ -862,12 +864,15 @@ xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, /* read extended order support flags */ in_uint16_le(s, ex_flags); /* Ex flags */ - if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT) + if (cap_flags & 0x80) /* ORDER_FLAGS_EXTRA_SUPPORT */ { - g_writeln("xrdp_process_capset_order: bitmap cache v3 supported"); - self->client_info.bitmap_cache_version |= 4; + self->client_info.order_flags_ex = ex_flags; + if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT) + { + g_writeln("xrdp_process_capset_order: bitmap cache v3 supported"); + self->client_info.bitmap_cache_version |= 4; + } } - in_uint8s(s, 4); /* Pad */ in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ @@ -958,11 +963,26 @@ xrdp_process_capset_pointercache(struct xrdp_rdp *self, struct stream *s, int len) { int i; + int colorPointerFlag; - in_uint8s(s, 2); /* color pointer */ + in_uint16_le(s, colorPointerFlag); + self->client_info.pointer_flags = colorPointerFlag; in_uint16_le(s, i); i = MIN(i, 32); self->client_info.pointer_cache_entries = i; + if (colorPointerFlag & 1) + { + g_writeln("xrdp_process_capset_pointercache: client supports " + "new(color) cursor"); + in_uint16_le(s, i); + i = MIN(i, 32); + self->client_info.pointer_cache_entries = i; + } + else + { + g_writeln("xrdp_process_capset_pointercache: client does not support " + "new(color) cursor"); + } return 0; } diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 17348274..2cc2d424 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -19,6 +19,7 @@ */ #include "libxrdp.h" +#include "log.h" /* some compilers need unsigned char to avoid warnings */ static tui8 g_pad_54[40] = @@ -1056,7 +1057,7 @@ xrdp_sec_incoming(struct xrdp_sec *self) if (file_by_name_read_section(key_file, "keys", items, values) != 0) { /* this is a show stopper */ - g_writeln("xrdp_sec_incoming: error reading %s file", key_file); + log_message(LOG_LEVEL_ALWAYS,"XRDP cannot read file: %s (check permissions)", key_file); list_delete(items); list_delete(values); return 1; diff --git a/neutrinordp/Makefile.am b/neutrinordp/Makefile.am new file mode 100644 index 00000000..93e1196a --- /dev/null +++ b/neutrinordp/Makefile.am @@ -0,0 +1,28 @@ +EXTRA_DIST = xrdp-neutrinordp.h +EXTRA_DEFINES = + +if XRDP_DEBUG +EXTRA_DEFINES += -DXRDP_DEBUG +else +EXTRA_DEFINES += -DXRDP_NODEBUG +endif + +AM_CFLAGS = \ + -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ + -DXRDP_SBIN_PATH=\"${sbindir}\" \ + -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ + -DXRDP_PID_PATH=\"${localstatedir}/run\" \ + $(EXTRA_DEFINES) + +INCLUDES = \ + -I$(top_srcdir)/common \ + $(FREERDP_CFLAGS) + +lib_LTLIBRARIES = \ + libxrdpneutrinordp.la + +libxrdpneutrinordp_la_SOURCES = xrdp-neutrinordp.c xrdp-color.c + +libxrdpneutrinordp_la_LIBADD = \ + $(top_builddir)/common/libcommon.la \ + $(FREERDP_LIBS) diff --git a/neutrinordp/xrdp-color.c b/neutrinordp/xrdp-color.c new file mode 100644 index 00000000..8201e918 --- /dev/null +++ b/neutrinordp/xrdp-color.c @@ -0,0 +1,313 @@ +/** + * FreeRDP: A Remote Desktop Protocol Server + * freerdp wrapper + * + * Copyright 2011-2012 Jay Sorg + * + * 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. + */ + +#include "xrdp-neutrinordp.h" + +char *APP_CC +convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, + int width, int height, int *palette) +{ + char *out; + char *src; + char *dst; + int i; + int j; + int red; + int green; + int blue; + int pixel; + + if ((in_bpp == 8) && (out_bpp == 8)) + { + out = (char *)g_malloc(width * height, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + *dst = pixel; + src++; + dst++; + } + } + + return out; + } + + if ((in_bpp == 8) && (out_bpp == 16)) + { + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src++; + dst += 2; + } + } + + return out; + } + + if ((in_bpp == 8) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src++; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 15) && (out_bpp == 16)) + { + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src += 2; + dst += 2; + } + } + + return out; + } + + if ((in_bpp == 15) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 15) && (out_bpp == 15)) + { + return bmpdata; + } + + if ((in_bpp == 16) && (out_bpp == 16)) + { + return bmpdata; + } + + if ((in_bpp == 16) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + blue = *((tui8 *)src); + src++; + green = *((tui8 *)src); + src++; + red = *((tui8 *)src); + src++; + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return bmpdata; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return bmpdata; + } + + g_writeln("convert_bitmap: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; +} + +/*****************************************************************************/ +/* returns color or 0 */ +int APP_CC +convert_color(int in_bpp, int out_bpp, int in_color, int *palette) +{ + int pixel; + int red; + int green; + int blue; + + if ((in_bpp == 1) && (out_bpp == 24)) + { + pixel = in_color == 0 ? 0 : 0xffffff; + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 8)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 16)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 24)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 16)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 15)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 16)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return in_color; + } + + g_writeln("convert_color: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; +} diff --git a/neutrinordp/xrdp-color.h b/neutrinordp/xrdp-color.h new file mode 100644 index 00000000..6a3f7362 --- /dev/null +++ b/neutrinordp/xrdp-color.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Server + * freerdp wrapper + * + * Copyright 2011-2012 Jay Sorg + * + * 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. + */ + +#ifndef __XRDP_COLOR_H +#define __XRDP_COLOR_H + +char* APP_CC +convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, + int width, int height, int* palette); +int APP_CC +convert_color(int in_bpp, int out_bpp, int in_color, int* palette); + +#endif diff --git a/neutrinordp/xrdp-neutrinordp.c b/neutrinordp/xrdp-neutrinordp.c new file mode 100644 index 00000000..ef0e4d4c --- /dev/null +++ b/neutrinordp/xrdp-neutrinordp.c @@ -0,0 +1,1837 @@ +/** + * FreeRDP: A Remote Desktop Protocol Server + * freerdp wrapper + * + * Copyright 2011-2013 Jay Sorg + * + * 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. + */ + +#include <freerdp/settings.h> +#include <X11/Xlib.h> +#include "xrdp-neutrinordp.h" +#include "xrdp-color.h" +#include "xrdp_rail.h" +#include "log.h" + +#ifdef XRDP_DEBUG +#define LOG_LEVEL 99 +#else +#define LOG_LEVEL 0 +#endif + +#define LLOG(_level, _args) \ + do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) +#define LLOGLN(_level, _args) \ + do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) + +struct mod_context +{ + rdpContext _p; + struct mod *modi; +}; +typedef struct mod_context modContext; + +/*****************************************************************************/ +static void +verifyColorMap(struct mod *mod) +{ + int i; + + for(i = 0; i < 255; i++) + { + if (mod->colormap[i] != 0) + { + return ; + } + } + LLOGLN(0, ("The colormap is all NULL")); +} + +/*****************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_start(struct mod *mod, int w, int h, int bpp) +{ + rdpSettings *settings; + + LLOGLN(10, ("lxrdp_start: w %d h %d bpp %d", w, h, bpp)); + settings = mod->inst->settings; + settings->width = w; + settings->height = h; + settings->color_depth = bpp; + mod->bpp = bpp; + + settings->encryption = 1; + settings->tls_security = 1; + settings->nla_security = 0; + settings->rdp_security = 1; + + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_connect(struct mod *mod) +{ + boolean ok; + + LLOGLN(10, ("lxrdp_connect:")); + + ok = freerdp_connect(mod->inst); + LLOGLN(0, ("lxrdp_connect: freerdp_connect returned %d", ok)); + + if (!ok) + { + LLOGLN(0, ("Failure to connect")); +#ifdef ERRORSTART + + if (connectErrorCode != 0) + { + char buf[128]; + + if (connectErrorCode < ERRORSTART) + { + if (strerror_r(connectErrorCode, buf, 128) != 0) + { + g_snprintf(buf, 128, "Errorcode from connect : %d", connectErrorCode); + } + } + else + { + switch (connectErrorCode) + { + case PREECONNECTERROR: + g_snprintf(buf, 128, "The error code from connect is " + "PREECONNECTERROR"); + break; + case UNDEFINEDCONNECTERROR: + g_snprintf(buf, 128, "The error code from connect is " + "UNDEFINEDCONNECTERROR"); + break; + case POSTCONNECTERROR: + g_snprintf(buf, 128, "The error code from connect is " + "POSTCONNECTERROR"); + break; + case DNSERROR: + g_snprintf(buf, 128, "The DNS system generated an error"); + break; + case DNSNAMENOTFOUND: + g_snprintf(buf, 128, "The DNS system could not find the " + "specified name"); + break; + case CONNECTERROR: + g_snprintf(buf, 128, "A general connect error was returned"); + break; + case MCSCONNECTINITIALERROR: + g_snprintf(buf, 128, "The error code from connect is " + "MCSCONNECTINITIALERROR"); + break; + case TLSCONNECTERROR: + g_snprintf(buf, 128, "Error in TLS handshake"); + break; + case AUTHENTICATIONERROR: + g_snprintf(buf, 128, "Authentication error check your password " + "and username"); + break; + default: + g_snprintf(buf, 128, "Unhandled Errorcode from connect : %d", + connectErrorCode); + break; + } + } + log_message(LOG_LEVEL_INFO,buf); + mod->server_msg(mod, buf, 0); + } + +#endif + log_message(LOG_LEVEL_INFO, "freerdp_connect Failed to " + "destination :%s:%d", + mod->inst->settings->hostname, + mod->inst->settings->port); + return 1; + } + else + { + log_message(LOG_LEVEL_INFO, "freerdp_connect returned Success to " + "destination :%s:%d", + mod->inst->settings->hostname, + mod->inst->settings->port); + } + + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_event(struct mod *mod, int msg, long param1, long param2, + long param3, long param4) +{ + int x; + int y; + int cx; + int cy; + int flags; + int size; + int total_size; + int chanid; + int lchid; + char *data; + + LLOGLN(12, ("lxrdp_event: msg %d", msg)); + + switch (msg) + { + case 15: /* key down */ + mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); + break; + case 16: /* key up */ + mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); + break; + case 17: /*Synchronize*/ + LLOGLN(11, ("Synchronized event handled")); + mod->inst->input->SynchronizeEvent(mod->inst->input, 0); + break; + case 100: /* mouse move */ + LLOGLN(12, ("mouse move %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_MOVE; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 101: /* left button up */ + LLOGLN(12, ("left button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON1; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 102: /* left button down */ + LLOGLN(12, ("left button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 103: /* right button up */ + LLOGLN(12, ("right button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON2; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 104: /* right button down */ + LLOGLN(12, ("right button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 105: /* middle button up */ + LLOGLN(12, ("middle button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON3; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 106: /* middle button down */ + LLOGLN(12, ("middle button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 107: /* wheel up */ + flags = PTR_FLAGS_WHEEL | 0x0078; + mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); + case 108: + break; + case 109: /* wheel down */ + flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); + case 110: + break; + case 200: + LLOGLN(10, ("Invalidate request sent from client")); + x = (param1 >> 16) & 0xffff; + y = (param1 >> 0) & 0xffff; + cx = (param2 >> 16) & 0xffff; + cy = (param2 >> 0) & 0xffff; + mod->inst->SendInvalidate(mod->inst, -1, x, y, cx, cy); + break; + case 0x5555: + chanid = LOWORD(param1); + flags = HIWORD(param1); + size = (int)param2; + data = (char *)param3; + total_size = (int)param4; + LLOGLN(12, ("lxrdp_event: client to server flags %d", flags)); + + if ((chanid < 0) || (chanid >= mod->inst->settings->num_channels)) + { + LLOGLN(0, ("lxrdp_event: error chanid %d", chanid)); + break; + } + + lchid = mod->inst->settings->channels[chanid].channel_id; + + switch (flags & 3) + { + case 3: + mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)data, total_size); + break; + case 2: + /* end */ + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)(mod->chan_buf), + total_size); + g_free(mod->chan_buf); + mod->chan_buf = 0; + mod->chan_buf_bytes = 0; + mod->chan_buf_valid = 0; + break; + case 1: + /* start */ + g_free(mod->chan_buf); + mod->chan_buf = (char *)g_malloc(total_size, 0); + mod->chan_buf_bytes = total_size; + mod->chan_buf_valid = 0; + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + break; + default: + /* middle */ + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + break; + } + + break; + default: + LLOGLN(0, ("Unhandled message type in eventhandler %d", msg)); + break; + } + + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_signal(struct mod *mod) +{ + LLOGLN(10, ("lxrdp_signal:")); + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_end(struct mod *mod) +{ + int i; + int j; + + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4096; i++) + { + g_free(mod->bitmap_cache[j][i].data); + } + } + + for (i = 0; i < 64; i++) + { + if (mod->brush_cache[i].data != mod->brush_cache[i].b8x8) + { + g_free(mod->brush_cache[i].data); + } + } + + LLOGLN(10, ("lxrdp_end:")); + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_set_param(struct mod *mod, char *name, char *value) +{ + rdpSettings *settings; + + LLOGLN(10, ("lxrdp_set_param: name [%s] value [%s]", name, value)); + settings = mod->inst->settings; + + if (g_strcmp(name, "hostname") == 0) + { + } + else if (g_strcmp(name, "ip") == 0) + { + settings->hostname = g_strdup(value); + } + else if (g_strcmp(name, "port") == 0) + { + settings->port = g_atoi(value); + } + else if (g_strcmp(name, "keylayout") == 0) + { + } + else if (g_strcmp(name, "name") == 0) + { + } + else if (g_strcmp(name, "lib") == 0) + { + } + else if (g_strcmp(name, "username") == 0) + { + g_strncpy(mod->username, value, 255); + } + else if (g_strcmp(name, "password") == 0) + { + g_strncpy(mod->password, value, 255); + } + else if (g_strcmp(name, "client_info") == 0) + { + g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); + /* This is a Struct and cannot be printed in next else*/ + LLOGLN(10, ("Client_info struct ignored")); + } + else + { + LLOGLN(0, ("lxrdp_set_param: unknown name [%s] value [%s]", name, value)); + } + + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_session_change(struct mod *mod, int a, int b) +{ + LLOGLN(0, ("lxrdp_session_change: - no code here")); + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) +{ + void **rfds; + void **wfds; + boolean ok; + + LLOGLN(12, ("lxrdp_get_wait_objs:")); + rfds = (void **)read_objs; + wfds = (void **)write_objs; + ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); + + if (!ok) + { + LLOGLN(0, ("lxrdp_get_wait_objs: freerdp_get_fds failed")); + return 1; + } + + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_check_wait_objs(struct mod *mod) +{ + boolean ok; + + LLOGLN(12, ("lxrdp_check_wait_objs:")); + ok = freerdp_check_fds(mod->inst); + + if (!ok) + { + LLOGLN(0, ("lxrdp_check_wait_objs: freerdp_check_fds failed")); + return 1; + } + + return 0; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_begin_paint(rdpContext *context) +{ + struct mod *mod; + + LLOGLN(10, ("lfreerdp_begin_paint:")); + mod = ((struct mod_context *)context)->modi; + mod->server_begin_update(mod); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_end_paint(rdpContext *context) +{ + struct mod *mod; + + LLOGLN(10, ("lfreerdp_end_paint:")); + mod = ((struct mod_context *)context)->modi; + mod->server_end_update(mod); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_set_bounds(rdpContext *context, rdpBounds *bounds) +{ + struct mod *mod; + int x; + int y; + int cx; + int cy; + + LLOGLN(10, ("lfreerdp_set_bounds: %p", bounds)); + mod = ((struct mod_context *)context)->modi; + + if (bounds != 0) + { + x = bounds->left; + y = bounds->top; + cx = (bounds->right - bounds->left) + 1; + cy = (bounds->bottom - bounds->top) + 1; + mod->server_set_clip(mod, x, y, cx, cy); + } + else + { + mod->server_reset_clip(mod); + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) +{ + struct mod *mod; + int index; + int cx; + int cy; + int server_bpp; + int server_Bpp; + int client_bpp; + int j; + int line_bytes; + BITMAP_DATA *bd; + char *dst_data; + char *dst_data1; + char *src; + char *dst; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_bitmap_update: %d %d", bitmap->number, bitmap->count)); + + server_bpp = mod->inst->settings->color_depth; + server_Bpp = (server_bpp + 7) / 8; + client_bpp = mod->bpp; + + for (index = 0; index < bitmap->number; index++) + { + bd = &bitmap->rectangles[index]; + cx = (bd->destRight - bd->destLeft) + 1; + cy = (bd->destBottom - bd->destTop) + 1; + line_bytes = server_Bpp * bd->width; + dst_data = (char *)g_malloc(bd->height * line_bytes + 16, 0); + + if (bd->compressed) + { + LLOGLN(20,("decompress size : %d",bd->bitmapLength)); + if(!bitmap_decompress(bd->bitmapDataStream, (tui8 *)dst_data, bd->width, + bd->height, bd->bitmapLength, server_bpp, server_bpp)){ + LLOGLN(0,("Failure to decompress the bitmap")); + } + } + else + { + /* bitmap is upside down */ + LLOGLN(10,("bitmap upside down")); + src = (char *)(bd->bitmapDataStream); + dst = dst_data + bd->height * line_bytes; + + for (j = 0; j < bd->height; j++) + { + dst -= line_bytes; + g_memcpy(dst, src, line_bytes); + src += line_bytes; + } + } + + dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, + bd->width, bd->height, mod->colormap); + mod->server_paint_rect(mod, bd->destLeft, bd->destTop, cx, cy, + dst_data1, bd->width, bd->height, 0, 0); + + if (dst_data1 != dst_data) + { + g_free(dst_data1); + } + + g_free(dst_data); + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_dst_blt(rdpContext *context, DSTBLT_ORDER *dstblt) +{ + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_dst_blt:")); + mod->server_set_opcode(mod, dstblt->bRop); + mod->server_fill_rect(mod, dstblt->nLeftRect, dstblt->nTopRect, + dstblt->nWidth, dstblt->nHeight); + mod->server_set_opcode(mod, 0xcc); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pat_blt(rdpContext *context, PATBLT_ORDER *patblt) +{ + struct mod *mod; + int idx; + int fgcolor; + int bgcolor; + int server_bpp; + int client_bpp; + struct brush_item *bi; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_pat_blt:")); + + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp)); + + fgcolor = convert_color(server_bpp, client_bpp, + patblt->foreColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + patblt->backColor, mod->colormap); + + if(fgcolor==bgcolor) + { + LLOGLN(0, ("Warning same color on both bg and fg")); + } + mod->server_set_mixmode(mod, 1); + mod->server_set_opcode(mod, patblt->bRop); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_bgcolor(mod, bgcolor); + + if (patblt->brush.style & 0x80) + { + idx = patblt->brush.hatch; + + if ((idx < 0) || (idx >= 64)) + { + LLOGLN(0, ("lfreerdp_pat_blt: error")); + return; + } + + bi = mod->brush_cache + idx; + mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, + 3, bi->b8x8); + } + else + { + mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, + patblt->brush.style, + (char *)(patblt->brush.p8x8)); + } + + mod->server_fill_rect(mod, patblt->nLeftRect, patblt->nTopRect, + patblt->nWidth, patblt->nHeight); + mod->server_set_opcode(mod, 0xcc); + mod->server_set_mixmode(mod, 0); + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_scr_blt(rdpContext *context, SCRBLT_ORDER *scrblt) +{ + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_scr_blt:")); + mod->server_set_opcode(mod, scrblt->bRop); + mod->server_screen_blt(mod, scrblt->nLeftRect, scrblt->nTopRect, + scrblt->nWidth, scrblt->nHeight, + scrblt->nXSrc, scrblt->nYSrc); + mod->server_set_opcode(mod, 0xcc); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_opaque_rect(rdpContext *context, OPAQUE_RECT_ORDER *opaque_rect) +{ + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_opaque_rect:")); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + opaque_rect->color, mod->colormap); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect, + opaque_rect->nWidth, opaque_rect->nHeight); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_mem_blt(rdpContext *context, MEMBLT_ORDER *memblt) +{ + int id; + int idx; + struct mod *mod; + struct bitmap_item *bi; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_mem_blt: cacheId %d cacheIndex %d", + memblt->cacheId, memblt->cacheIndex)); + + id = memblt->cacheId; + idx = memblt->cacheIndex; + + if (idx == 32767) /* BITMAPCACHE_WAITING_LIST_INDEX */ + { + idx = 4096 - 1; + } + + if ((id < 0) || (id >= 4)) + { + LLOGLN(0, ("lfreerdp_mem_blt: bad id [%d]", id)); + return; + } + + if ((idx < 0) || (idx >= 4096)) + { + LLOGLN(0, ("lfreerdp_mem_blt: bad idx [%d]", idx)); + return; + } + + bi = &(mod->bitmap_cache[id][idx]); + + mod->server_set_opcode(mod, memblt->bRop); + mod->server_paint_rect(mod, memblt->nLeftRect, memblt->nTopRect, + memblt->nWidth, memblt->nHeight, + bi->data, bi->width, bi->height, + memblt->nXSrc, memblt->nYSrc); + mod->server_set_opcode(mod, 0xcc); + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_glyph_index(rdpContext *context, GLYPH_INDEX_ORDER *glyph_index) +{ + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; + int bgcolor; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_glyph_index:")); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + glyph_index->foreColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + glyph_index->backColor, mod->colormap); + mod->server_set_bgcolor(mod, fgcolor); + mod->server_set_fgcolor(mod, bgcolor); + mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel, + glyph_index->fOpRedundant, + glyph_index->bkLeft, glyph_index->bkTop, + glyph_index->bkRight, glyph_index->bkBottom, + glyph_index->opLeft, glyph_index->opTop, + glyph_index->opRight, glyph_index->opBottom, + glyph_index->x, glyph_index->y, + (char *)(glyph_index->data), glyph_index->cbData); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_line_to(rdpContext *context, LINE_TO_ORDER *line_to) +{ + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; + int bgcolor; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_line_to:")); + mod->server_set_opcode(mod, line_to->bRop2); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + line_to->penColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + line_to->backColor, mod->colormap); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_bgcolor(mod, bgcolor); + mod->server_set_pen(mod, line_to->penStyle, line_to->penWidth); + mod->server_draw_line(mod, line_to->nXStart, line_to->nYStart, + line_to->nXEnd, line_to->nYEnd); + mod->server_set_opcode(mod, 0xcc); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_bitmap(rdpContext *context, CACHE_BITMAP_ORDER *cache_bitmap_order) +{ + LLOGLN(0, ("lfreerdp_cache_bitmap: - no code here")); +} + +/******************************************************************************/ +/* Turn the bitmap upside down*/ +static void DEFAULT_CC +lfreerdp_upsidedown(uint8* destination, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2_order, int server_Bpp) +{ + tui8 *src; + tui8 *dst; + int line_bytes; + int j; + + if (destination == NULL) + { + LLOGLN(0, ("lfreerdp_upsidedown: destination pointer is NULL !!!")); + return; + } + + line_bytes = server_Bpp * cache_bitmap_v2_order->bitmapWidth; + src = cache_bitmap_v2_order->bitmapDataStream; + dst = destination + ((cache_bitmap_v2_order->bitmapHeight) * line_bytes); + + for (j = 0; j < cache_bitmap_v2_order->bitmapHeight; j++) + { + dst -= line_bytes; + g_memcpy(dst, src, line_bytes); + src += line_bytes; + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_bitmapV2(rdpContext *context, + CACHE_BITMAP_V2_ORDER *cache_bitmap_v2_order) +{ + char *dst_data; + char *dst_data1; + int bytes; + int width; + int height; + int id; + int idx; + int flags; + int server_bpp; + int server_Bpp; + int client_bpp; + struct mod *mod; + + LLOGLN(10, ("lfreerdp_cache_bitmapV2: %d %d 0x%8.8x compressed %d", + cache_bitmap_v2_order->cacheId, + cache_bitmap_v2_order->cacheIndex, + cache_bitmap_v2_order->flags, + cache_bitmap_v2_order->compressed)); + + mod = ((struct mod_context *)context)->modi; + id = cache_bitmap_v2_order->cacheId; + idx = cache_bitmap_v2_order->cacheIndex; + flags = cache_bitmap_v2_order->flags; + + if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ + { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: CBR2_DO_NOT_CACHE")); + idx = 4096 - 1; + } + + if ((id < 0) || (id >= 4)) + { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad id [%d]", id)); + return; + } + + if ((idx < 0) || (idx >= 4096)) + { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad idx [%d]", idx)); + return; + } + + server_bpp = mod->inst->settings->color_depth; + server_Bpp = (server_bpp + 7) / 8; + client_bpp = mod->bpp; + + width = cache_bitmap_v2_order->bitmapWidth; + height = cache_bitmap_v2_order->bitmapHeight; + bytes = width * height * server_Bpp + 16; + dst_data = (char *)g_malloc(bytes, 0); + + if (cache_bitmap_v2_order->compressed) + { + bitmap_decompress(cache_bitmap_v2_order->bitmapDataStream, + (tui8 *)dst_data, width, height, + cache_bitmap_v2_order->bitmapLength, + server_bpp, server_bpp); + } + else + { + /* Uncompressed bitmaps are upside down */ + lfreerdp_upsidedown((tui8 *)dst_data, cache_bitmap_v2_order, server_Bpp); + LLOGLN(10, ("lfreerdp_cache_bitmapV2: upside down progressed")); + } + + dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, + width, height, mod->colormap); + g_free(mod->bitmap_cache[id][idx].data); + mod->bitmap_cache[id][idx].width = width; + mod->bitmap_cache[id][idx].height = height; + mod->bitmap_cache[id][idx].data = dst_data1; + + if (dst_data != dst_data1) + { + g_free(dst_data); + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_glyph(rdpContext *context, CACHE_GLYPH_ORDER *cache_glyph_order) +{ + int index; + GLYPH_DATA *gd; + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_cache_glyph: %d", cache_glyph_order->cGlyphs)); + + for (index = 0; index < cache_glyph_order->cGlyphs; index++) + { + gd = cache_glyph_order->glyphData[index]; + LLOGLN(10, (" %d %d %d %d %d", gd->cacheIndex, gd->x, gd->y, + gd->cx, gd->cy)); + mod->server_add_char(mod, cache_glyph_order->cacheId, gd->cacheIndex, + gd->x, gd->y, gd->cx, gd->cy, (char *)(gd->aj)); + free(gd->aj); + gd->aj = 0; + free(gd); + cache_glyph_order->glyphData[index] = 0; + } + + free(cache_glyph_order->unicodeCharacters); + cache_glyph_order->unicodeCharacters = 0; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_brush(rdpContext *context, CACHE_BRUSH_ORDER *cache_brush_order) +{ + int idx; + int bytes; + int bpp; + int cx; + int cy; + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + bpp = cache_brush_order->bpp; + cx = cache_brush_order->cx; + cy = cache_brush_order->cy; + idx = cache_brush_order->index; + bytes = cache_brush_order->length; + LLOGLN(10, ("lfreerdp_cache_brush: bpp %d cx %d cy %d idx %d bytes %d", + bpp, cx, cy, idx, bytes)); + + if ((idx < 0) || (idx >= 64)) + { + LLOGLN(0, ("lfreerdp_cache_brush: error idx %d", idx)); + return; + } + + if ((bpp != 1) || (cx != 8) || (cy != 8)) + { + LLOGLN(0, ("lfreerdp_cache_brush: error unsupported brush " + "bpp %d cx %d cy %d", bpp, cx, cy)); + return; + } + + mod->brush_cache[idx].bpp = bpp; + mod->brush_cache[idx].width = cx; + mod->brush_cache[idx].height = cy; + mod->brush_cache[idx].data = mod->brush_cache[idx].b8x8; + + if (bytes > 8) + { + bytes = 8; + } + + g_memset(mod->brush_cache[idx].data, 0, 8); + + if (bytes > 0) + { + if (bytes > 8) + { + LLOGLN(0, ("lfreerdp_cache_brush: bytes to big %d", bytes)); + bytes = 8; + } + + g_memcpy(mod->brush_cache[idx].data, cache_brush_order->data, bytes); + } + + LLOGLN(10, ("lfreerdp_cache_brush: out bpp %d cx %d cy %d idx %d bytes %d", + bpp, cx, cy, idx, bytes)); + + free(cache_brush_order->data); + cache_brush_order->data = 0; + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_position(rdpContext *context, + POINTER_POSITION_UPDATE *pointer_position) +{ + LLOGLN(0, ("lfreerdp_pointer_position: - no code here")); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_system(rdpContext *context, + POINTER_SYSTEM_UPDATE *pointer_system) +{ + LLOGLN(0, ("lfreerdp_pointer_system: - no code here type value = %d",pointer_system->type)); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_color(rdpContext *context, + POINTER_COLOR_UPDATE *pointer_color) +{ + LLOGLN(0, ("lfreerdp_pointer_color: - no code here")); +} + +/******************************************************************************/ +static int APP_CC +lfreerdp_get_pixel(void *bits, int width, int height, int bpp, + int delta, int x, int y) +{ + int start; + int shift; + int pixel; + tui8 *src8; + + if (bpp == 1) + { + src8 = (tui8 *)bits; + start = (y * delta) + x / 8; + shift = x % 8; + pixel = (src8[start] & (0x80 >> shift)) != 0; + return pixel ? 0xffffff : 0; + } + else + { + LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp)); + } + + return 0; +} + +/******************************************************************************/ +static int APP_CC +lfreerdp_set_pixel(int pixel, void *bits, int width, int height, int bpp, + int delta, int x, int y) +{ + tui8 *dst8; + int start; + int shift; + + if (bpp == 1) + { + dst8 = (tui8 *)bits; + start = (y * delta) + x / 8; + shift = x % 8; + + if (pixel) + { + dst8[start] = dst8[start] | (0x80 >> shift); + } + else + { + dst8[start] = dst8[start] & ~(0x80 >> shift); + } + } + else if (bpp == 24) + { + dst8 = (tui8 *)bits; + dst8 += y * delta + x * 3; + dst8[0] = (pixel >> 0) & 0xff; + dst8[1] = (pixel >> 8) & 0xff; + dst8[2] = (pixel >> 16) & 0xff; + } + else + { + LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp)); + } + + return 0; +} + +/******************************************************************************/ +static int APP_CC +lfreerdp_convert_color_image(void *dst, int dst_width, int dst_height, + int dst_bpp, int dst_delta, + void *src, int src_width, int src_height, + int src_bpp, int src_delta) +{ + int i; + int j; + int pixel; + + for (j = 0; j < dst_height; j++) + { + for (i = 0; i < dst_width; i++) + { + pixel = lfreerdp_get_pixel(src, src_width, src_height, src_bpp, + src_delta, i, j); + lfreerdp_set_pixel(pixel, dst, dst_width, dst_height, dst_bpp, + dst_delta, i, j); + } + } + + return 0; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_new(rdpContext *context, + POINTER_NEW_UPDATE *pointer_new) +{ + struct mod *mod; + int index; + tui8 *dst; + tui8 *src; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(20, ("lfreerdp_pointer_new:")); + LLOGLN(20, (" bpp %d", pointer_new->xorBpp)); + LLOGLN(20, (" width %d height %d", pointer_new->colorPtrAttr.width, + pointer_new->colorPtrAttr.height)); + + LLOGLN(20, (" lengthXorMask %d lengthAndMask %d", + pointer_new->colorPtrAttr.lengthXorMask, + pointer_new->colorPtrAttr.lengthAndMask)); + + index = pointer_new->colorPtrAttr.cacheIndex; + if(index>=32) + { + LLOGLN(0,("pointer index too big")); + return ; + } + // In this fix we remove the xorBpp check, even if + // the mouse pointers are not correct we can use them. + // Configure your destination not to use windows Aero as pointer scheme + else if ( // pointer_new->xorBpp == 1 && + pointer_new->colorPtrAttr.width == 32 && + pointer_new->colorPtrAttr.height == 32 && + index < 32) + { + mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos; + mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos; + + dst = (tui8 *)(mod->pointer_cache[index].data); + dst += 32 * 32 * 3 - 32 * 3; + src = pointer_new->colorPtrAttr.xorMaskData; + lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3, + src, 32, 32, 1, 32 / 8); + + dst = (tui8 *)(mod->pointer_cache[index].mask); + dst += ( 32 * 32 / 8) - (32 / 8); + src = pointer_new->colorPtrAttr.andMaskData; + lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8, + src, 32, 32, 1, 32 / 8); + + //memcpy(mod->pointer_cache[index].mask, + // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); + + mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, + mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, + mod->pointer_cache[index].mask); + } + else + { + LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d index: %d", + pointer_new->xorBpp, pointer_new->colorPtrAttr.width, + pointer_new->colorPtrAttr.height,index)); + } + + free(pointer_new->colorPtrAttr.xorMaskData); + pointer_new->colorPtrAttr.xorMaskData = 0; + free(pointer_new->colorPtrAttr.andMaskData); + pointer_new->colorPtrAttr.andMaskData = 0; + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_cached(rdpContext *context, + POINTER_CACHED_UPDATE *pointer_cached) +{ + struct mod *mod; + int index; + + mod = ((struct mod_context *)context)->modi; + index = pointer_cached->cacheIndex; + LLOGLN(10, ("lfreerdp_pointer_cached:%d", index)); + mod->server_set_pointer(mod, mod->pointer_cache[index].hotx, + mod->pointer_cache[index].hoty, + mod->pointer_cache[index].data, + mod->pointer_cache[index].mask); +} + +static void DEFAULT_CC lfreerdp_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) +{ + LLOGLN(0, ("lfreerdp_polygon_sc called:- not supported!!!!!!!!!!!!!!!!!!!!")); +} + +static void DEFAULT_CC lfreerdp_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) +{ + struct mod *mod; + int i, npoints; + XPoint points[4]; + int fgcolor; + int server_bpp, client_bpp; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_polygon_sc :%d(points) %d(color) %d(fillmode) " + "%d(bRop) %d(cbData) %d(x) %d(y)", + polygon_sc->nDeltaEntries, polygon_sc->brushColor, + polygon_sc->fillMode, polygon_sc->bRop2, + polygon_sc->cbData, polygon_sc->xStart, + polygon_sc->yStart)); + if (polygon_sc->nDeltaEntries == 3) + { + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + + points[0].x = polygon_sc->xStart; + points[0].y = polygon_sc->yStart; + + for (i = 0; i < polygon_sc->nDeltaEntries; i++) + { + points[i + 1].x = 0; // polygon_sc->points[i].x; + points[i + 1].y = 0; // polygon_sc->points[i].y; + } + fgcolor = convert_color(server_bpp, client_bpp, + polygon_sc->brushColor, mod->colormap); + + mod->server_set_opcode(mod, polygon_sc->bRop2); + mod->server_set_bgcolor(mod, 255); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_pen(mod, 1, 1); // style, width + // TODO replace with correct brush; this is a workaround + // This workaround handles the text cursor in microsoft word. + mod->server_draw_line(mod,polygon_sc->xStart,polygon_sc->yStart,polygon_sc->xStart,polygon_sc->yStart+points[2].y); +// mod->server_fill_rect(mod, points[0].x, points[0].y, +// points[0].x-points[3].x, points[0].y-points[2].y); +// mod->server_set_brush(mod,); // howto use this on our indata?? + mod->server_set_opcode(mod, 0xcc); + } + else + { + LLOGLN(0, ("Not handled number of points in lfreerdp_polygon_sc")); + } +} + +static void DEFAULT_CC lfreerdp_syncronize(rdpContext* context) +{ + struct mod *mod; + mod = ((struct mod_context *)context)->modi; + LLOGLN(0, ("lfreerdp_synchronize received - not handled")); +} + +/******************************************************************************/ +static boolean DEFAULT_CC +lfreerdp_pre_connect(freerdp *instance) +{ + struct mod *mod; + int index; + int error; + int num_chans; + int ch_flags; + char ch_name[256]; + char *dst_ch_name; + + LLOGLN(0, ("lfreerdp_pre_connect:")); + mod = ((struct mod_context *)(instance->context))->modi; + verifyColorMap(mod); + num_chans = 0; + index = 0; + error = mod->server_query_channel(mod, index, ch_name, &ch_flags); + + while (error == 0) + { + num_chans++; + LLOGLN(10, ("lfreerdp_pre_connect: got channel [%s], flags [0x%8.8x]", + ch_name, ch_flags)); + dst_ch_name = instance->settings->channels[index].name; + g_memset(dst_ch_name, 0, 8); + g_snprintf(dst_ch_name, 8, "%s", ch_name); + instance->settings->channels[index].options = ch_flags; + index++; + error = mod->server_query_channel(mod, index, ch_name, &ch_flags); + } + + instance->settings->num_channels = num_chans; + + instance->settings->offscreen_bitmap_cache = 0; + instance->settings->draw_nine_grid = 0; + + instance->settings->glyph_cache = true; + instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; + instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = 1; + instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = 0; + instance->settings->order_support[NEG_FAST_INDEX_INDEX] = 0; + instance->settings->order_support[NEG_SCRBLT_INDEX] = 1; + instance->settings->order_support[NEG_SAVEBITMAP_INDEX] = 0; + + instance->settings->bitmap_cache = 1; + instance->settings->order_support[NEG_MEMBLT_INDEX] = 1; + instance->settings->order_support[NEG_MEMBLT_V2_INDEX] = 1; + instance->settings->order_support[NEG_MEM3BLT_INDEX] = 0; + instance->settings->order_support[NEG_MEM3BLT_V2_INDEX] = 0; + instance->settings->bitmapCacheV2NumCells = 3; // 5; + instance->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; + instance->settings->bitmapCacheV2CellInfo[0].persistent = 0; + instance->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; + instance->settings->bitmapCacheV2CellInfo[1].persistent = 0; + instance->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; + instance->settings->bitmapCacheV2CellInfo[2].persistent = 0; + instance->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; + instance->settings->bitmapCacheV2CellInfo[3].persistent = 0; + instance->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; + instance->settings->bitmapCacheV2CellInfo[4].persistent = 0; + + // instance->settings->BitmapCacheV3Enabled = FALSE; + instance->settings->order_support[NEG_MULTIDSTBLT_INDEX] = 0; + instance->settings->order_support[NEG_MULTIPATBLT_INDEX] = 0; + instance->settings->order_support[NEG_MULTISCRBLT_INDEX] = 0; + instance->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = 0; + instance->settings->order_support[NEG_POLYLINE_INDEX] = 0; + + instance->settings->username = g_strdup(mod->username); + instance->settings->password = g_strdup(mod->password); + + if (mod->client_info.rail_support_level > 0) + { + LLOGLN(0, ("Railsupport !!!!!!!!!!!!!!!!!!")); + instance->settings->remote_app = 1; + instance->settings->rail_langbar_supported = 1; + instance->settings->workarea = 1; + instance->settings->performance_flags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG; + } + else + { + LLOGLN(10, ("Special PerformanceFlags changed")); + instance->settings->performance_flags = PERF_DISABLE_WALLPAPER | + PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS | + PERF_DISABLE_THEMING; + // | PERF_DISABLE_CURSOR_SHADOW | PERF_DISABLE_CURSORSETTINGS; + } + instance->settings->compression = 0; + instance->settings->ignore_certificate = 1; + + // here + //instance->settings->RdpVersion = 4; + + instance->update->BeginPaint = lfreerdp_begin_paint; + instance->update->EndPaint = lfreerdp_end_paint; + instance->update->SetBounds = lfreerdp_set_bounds; + instance->update->BitmapUpdate = lfreerdp_bitmap_update; + instance->update->Synchronize = lfreerdp_syncronize ; + instance->update->primary->DstBlt = lfreerdp_dst_blt; + instance->update->primary->PatBlt = lfreerdp_pat_blt; + instance->update->primary->ScrBlt = lfreerdp_scr_blt; + instance->update->primary->OpaqueRect = lfreerdp_opaque_rect; + instance->update->primary->MemBlt = lfreerdp_mem_blt; + instance->update->primary->GlyphIndex = lfreerdp_glyph_index; + instance->update->primary->LineTo = lfreerdp_line_to; + instance->update->primary->PolygonSC = lfreerdp_polygon_sc ; + instance->update->primary->PolygonCB = lfreerdp_polygon_cb; + instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; + instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; + instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; + instance->update->secondary->CacheBrush = lfreerdp_cache_brush; + + instance->update->pointer->PointerPosition = lfreerdp_pointer_position; + instance->update->pointer->PointerSystem = lfreerdp_pointer_system; + instance->update->pointer->PointerColor = lfreerdp_pointer_color; + instance->update->pointer->PointerNew = lfreerdp_pointer_new; + instance->update->pointer->PointerCached = lfreerdp_pointer_cached; + + if ((mod->username[0] != 0) && (mod->password[0] != 0)) + { + /* since we have username and password, we can try nla */ + instance->settings->nla_security = 1; + } + else + { + instance->settings->nla_security = 0; + } + + return 1; +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_STATE_ORDER *window_state) +{ + int index; + struct mod *mod; + struct rail_window_state_order wso; + + LLOGLN(0, ("llrail_WindowCreate:")); + mod = ((struct mod_context *)context)->modi; + memset(&wso, 0, sizeof(wso)); + /* copy the window state order */ + wso.owner_window_id = window_state->ownerWindowId; + wso.style = window_state->style; + wso.extended_style = window_state->extendedStyle; + wso.show_state = window_state->showState; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) + { + freerdp_UnicodeToAsciiAlloc(window_state->titleInfo.string, &wso.title_info, window_state->titleInfo.length / 2); + } + + LLOGLN(0, ("lrail_WindowCreate: %s", wso.title_info)); + wso.client_offset_x = window_state->clientOffsetX; + wso.client_offset_y = window_state->clientOffsetY; + wso.client_area_width = window_state->clientAreaWidth; + wso.client_area_height = window_state->clientAreaHeight; + wso.rp_content = window_state->RPContent; + wso.root_parent_handle = window_state->rootParentHandle; + wso.window_offset_x = window_state->windowOffsetX; + wso.window_offset_y = window_state->windowOffsetY; + wso.window_client_delta_x = window_state->windowClientDeltaX; + wso.window_client_delta_y = window_state->windowClientDeltaY; + wso.window_width = window_state->windowWidth; + wso.window_height = window_state->windowHeight; + wso.num_window_rects = window_state->numWindowRects; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) + { + wso.window_rects = (struct rail_window_rect *) + g_malloc(sizeof(struct rail_window_rect) * wso.num_window_rects, 0); + + for (index = 0; index < wso.num_window_rects; index++) + { + wso.window_rects[index].left = window_state->windowRects[index].left; + wso.window_rects[index].top = window_state->windowRects[index].top; + wso.window_rects[index].right = window_state->windowRects[index].right; + wso.window_rects[index].bottom = window_state->windowRects[index].bottom; + } + } + + wso.visible_offset_x = window_state->visibleOffsetX; + wso.visible_offset_y = window_state->visibleOffsetY; + wso.num_visibility_rects = window_state->numVisibilityRects; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) + { + wso.visibility_rects = (struct rail_window_rect *) + g_malloc(sizeof(struct rail_window_rect) * wso.num_visibility_rects, 0); + + for (index = 0; index < wso.num_visibility_rects; index++) + { + wso.visibility_rects[index].left = window_state->visibilityRects[index].left; + wso.visibility_rects[index].top = window_state->visibilityRects[index].top; + wso.visibility_rects[index].right = window_state->visibilityRects[index].right; + wso.visibility_rects[index].bottom = window_state->visibilityRects[index].bottom; + } + } + + mod->server_window_new_update(mod, orderInfo->windowId, &wso, + orderInfo->fieldFlags); + + free(wso.title_info); + g_free(wso.window_rects); + g_free(wso.visibility_rects); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_STATE_ORDER *window_state) +{ + LLOGLN(0, ("lrail_WindowUpdate:")); + lrail_WindowCreate(context, orderInfo, window_state); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_WindowDelete:")); + mod = ((struct mod_context *)context)->modi; + mod->server_window_delete(mod, orderInfo->windowId); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_ICON_ORDER *window_icon) +{ + struct mod *mod; + struct rail_icon_info rii; + + LLOGLN(0, ("lrail_WindowIcon:")); + mod = ((struct mod_context *)context)->modi; + memset(&rii, 0, sizeof(rii)); + rii.bpp = window_icon->iconInfo->bpp; + rii.width = window_icon->iconInfo->width; + rii.height = window_icon->iconInfo->height; + rii.cmap_bytes = window_icon->iconInfo->cbColorTable; + rii.mask_bytes = window_icon->iconInfo->cbBitsMask; + rii.data_bytes = window_icon->iconInfo->cbBitsColor; + rii.mask = (char *)(window_icon->iconInfo->bitsMask); + rii.cmap = (char *)(window_icon->iconInfo->colorTable); + rii.data = (char *)(window_icon->iconInfo->bitsColor); + mod->server_window_icon(mod, orderInfo->windowId, + window_icon->iconInfo->cacheEntry, + window_icon->iconInfo->cacheId, &rii, + orderInfo->fieldFlags); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowCachedIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_CACHED_ICON_ORDER *window_cached_icon) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_WindowCachedIcon:")); + mod = ((struct mod_context *)context)->modi; + mod->server_window_cached_icon(mod, orderInfo->windowId, + window_cached_icon->cachedIcon.cacheEntry, + window_cached_icon->cachedIcon.cacheId, + orderInfo->fieldFlags); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + NOTIFY_ICON_STATE_ORDER *notify_icon_state) +{ + struct mod *mod; + struct rail_notify_state_order rnso; + + LLOGLN(0, ("lrail_NotifyIconCreate:")); + + mod = ((struct mod_context *)context)->modi; + + memset(&rnso, 0, sizeof(rnso)); + rnso.version = notify_icon_state->version; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) + { + freerdp_UnicodeToAsciiAlloc(notify_icon_state->toolTip.string, + &rnso.tool_tip, notify_icon_state->toolTip.length / 2); + } + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) + { + rnso.infotip.timeout = notify_icon_state->infoTip.timeout; + rnso.infotip.flags = notify_icon_state->infoTip.flags; + freerdp_UnicodeToAsciiAlloc(notify_icon_state->infoTip.text.string, + &rnso.infotip.text, notify_icon_state->infoTip.text.length / 2); + freerdp_UnicodeToAsciiAlloc(notify_icon_state->infoTip.title.string, + &rnso.infotip.title, notify_icon_state->infoTip.title.length / 2); + } + + rnso.state = notify_icon_state->state; + rnso.icon_cache_entry = notify_icon_state->icon.cacheEntry; + rnso.icon_cache_id = notify_icon_state->icon.cacheId; + + rnso.icon_info.bpp = notify_icon_state->icon.bpp; + rnso.icon_info.width = notify_icon_state->icon.width; + rnso.icon_info.height = notify_icon_state->icon.height; + rnso.icon_info.cmap_bytes = notify_icon_state->icon.cbColorTable; + rnso.icon_info.mask_bytes = notify_icon_state->icon.cbBitsMask; + rnso.icon_info.data_bytes = notify_icon_state->icon.cbBitsColor; + rnso.icon_info.mask = (char *)(notify_icon_state->icon.bitsMask); + rnso.icon_info.cmap = (char *)(notify_icon_state->icon.colorTable); + rnso.icon_info.data = (char *)(notify_icon_state->icon.bitsColor); + + mod->server_notify_new_update(mod, orderInfo->windowId, + orderInfo->notifyIconId, + &rnso, orderInfo->fieldFlags); + + free(rnso.tool_tip); + free(rnso.infotip.text); + free(rnso.infotip.title); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + NOTIFY_ICON_STATE_ORDER *notify_icon_state) +{ + LLOGLN(0, ("lrail_NotifyIconUpdate:")); + lrail_NotifyIconCreate(context, orderInfo, notify_icon_state); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_NotifyIconDelete:")); + mod = ((struct mod_context *)context)->modi; + mod->server_notify_delete(mod, orderInfo->windowId, + orderInfo->notifyIconId); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_MonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + MONITORED_DESKTOP_ORDER *monitored_desktop) +{ + int index; + struct mod *mod; + struct rail_monitored_desktop_order rmdo; + + LLOGLN(0, ("lrail_MonitoredDesktop:")); + mod = ((struct mod_context *)context)->modi; + memset(&rmdo, 0, sizeof(rmdo)); + rmdo.active_window_id = monitored_desktop->activeWindowId; + rmdo.num_window_ids = monitored_desktop->numWindowIds; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) + { + if (rmdo.num_window_ids > 0) + { + rmdo.window_ids = (int *)g_malloc(sizeof(int) * rmdo.num_window_ids, 0); + + for (index = 0; index < rmdo.num_window_ids; index++) + { + rmdo.window_ids[index] = monitored_desktop->windowIds[index]; + } + } + } + + mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); + g_free(rmdo.window_ids); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NonMonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + struct rail_monitored_desktop_order rmdo; + + LLOGLN(0, ("lrail_NonMonitoredDesktop:")); + mod = ((struct mod_context *)context)->modi; + memset(&rmdo, 0, sizeof(rmdo)); + mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); +} + +/******************************************************************************/ +static boolean DEFAULT_CC +lfreerdp_post_connect(freerdp *instance) +{ + struct mod *mod; + + LLOGLN(0, ("lfreerdp_post_connect:")); + mod = ((struct mod_context *)(instance->context))->modi; + g_memset(mod->password, 0, sizeof(mod->password)); + + mod->inst->update->window->WindowCreate = lrail_WindowCreate; + mod->inst->update->window->WindowUpdate = lrail_WindowUpdate; + mod->inst->update->window->WindowDelete = lrail_WindowDelete; + mod->inst->update->window->WindowIcon = lrail_WindowIcon; + mod->inst->update->window->WindowCachedIcon = lrail_WindowCachedIcon; + mod->inst->update->window->NotifyIconCreate = lrail_NotifyIconCreate; + mod->inst->update->window->NotifyIconUpdate = lrail_NotifyIconUpdate; + mod->inst->update->window->NotifyIconDelete = lrail_NotifyIconDelete; + mod->inst->update->window->MonitoredDesktop = lrail_MonitoredDesktop; + mod->inst->update->window->NonMonitoredDesktop = lrail_NonMonitoredDesktop; + + return 1; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_context_new(freerdp *instance, rdpContext *context) +{ + LLOGLN(0, ("lfreerdp_context_new: %p", context)); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_context_free(freerdp *instance, rdpContext *context) +{ + LLOGLN(0, ("lfreerdp_context_free: - no code here")); +} + +/******************************************************************************/ +static int DEFAULT_CC +lfreerdp_receive_channel_data(freerdp *instance, int channelId, uint8 *data, + int size, int flags, int total_size) +{ + struct mod *mod; + int lchid; + int index; + int error; + + mod = ((struct mod_context *)(instance->context))->modi; + lchid = -1; + + for (index = 0; index < instance->settings->num_channels; index++) + { + if (instance->settings->channels[index].channel_id == channelId) + { + lchid = index; + break; + } + } + + if (lchid >= 0) + { + LLOGLN(10, ("lfreerdp_receive_channel_data: server to client")); + error = mod->server_send_to_channel(mod, lchid, (char *)data, size, + total_size, flags); + + if (error != 0) + { + LLOGLN(0, ("lfreerdp_receive_channel_data: error %d", error)); + } + } + else + { + LLOGLN(0, ("lfreerdp_receive_channel_data: bad lchid")); + } + + return 0; +} + +/******************************************************************************/ +static boolean DEFAULT_CC +lfreerdp_authenticate(freerdp *instance, char **username, + char **password, char **domain) +{ + LLOGLN(0, ("lfreerdp_authenticate: - no code here")); + return 1; +} + +/******************************************************************************/ +static boolean DEFAULT_CC +lfreerdp_verify_certificate(freerdp *instance, char *subject, char *issuer, + char *fingerprint) +{ + LLOGLN(0, ("lfreerdp_verify_certificate: - no code here")); + return 1; +} + +/******************************************************************************/ +struct mod *EXPORT_CC +mod_init(void) +{ + struct mod *mod; + modContext *lcon; + + LLOGLN(0, ("mod_init:")); + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + freerdp_get_version(&(mod->vmaj), &(mod->vmin), &(mod->vrev)); + LLOGLN(0, (" FreeRDP version major %d minor %d revision %d", + mod->vmaj, mod->vmin, mod->vrev)); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (tbus)mod; + mod->mod_connect = lxrdp_connect; + mod->mod_start = lxrdp_start; + mod->mod_event = lxrdp_event; + mod->mod_signal = lxrdp_signal; + mod->mod_end = lxrdp_end; + mod->mod_set_param = lxrdp_set_param; + mod->mod_session_change = lxrdp_session_change; + mod->mod_get_wait_objs = lxrdp_get_wait_objs; + mod->mod_check_wait_objs = lxrdp_check_wait_objs; + + mod->inst = freerdp_new(); + mod->inst->PreConnect = lfreerdp_pre_connect; + mod->inst->PostConnect = lfreerdp_post_connect; + mod->inst->context_size = sizeof(modContext); + mod->inst->ContextNew = lfreerdp_context_new; + mod->inst->ContextFree = lfreerdp_context_free; + mod->inst->ReceiveChannelData = lfreerdp_receive_channel_data; + mod->inst->Authenticate = lfreerdp_authenticate; + mod->inst->VerifyCertificate = lfreerdp_verify_certificate; + + freerdp_context_new(mod->inst); + + lcon = (modContext *)(mod->inst->context); + lcon->modi = mod; + LLOGLN(10, ("mod_init: mod %p", mod)); + + return mod; +} + +/******************************************************************************/ +int EXPORT_CC +mod_exit(struct mod *mod) +{ + LLOGLN(0, ("mod_exit:")); + + if (mod == 0) + { + return 0; + } + + if (mod->inst == NULL) + { + LLOGLN(0, ("mod_exit - null pointer for inst:")); + g_free(mod); + return 0 ; + } + + freerdp_disconnect(mod->inst); + + if ((mod->vmaj == 1) && (mod->vmin == 0) && (mod->vrev == 1)) + { + /* this version has a bug with double free in freerdp_free */ + } + else + { + freerdp_context_free(mod->inst); + } + + freerdp_free(mod->inst); + g_free(mod); + return 0; +} diff --git a/neutrinordp/xrdp-neutrinordp.h b/neutrinordp/xrdp-neutrinordp.h new file mode 100644 index 00000000..474c46b7 --- /dev/null +++ b/neutrinordp/xrdp-neutrinordp.h @@ -0,0 +1,180 @@ +/** + * FreeRDP: A Remote Desktop Protocol Server + * freerdp wrapper + * + * Copyright 2011-2013 Jay Sorg + * + * 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. + */ + +/* include other h files */ +#include "arch.h" +#include "parse.h" +#include "os_calls.h" +#include "defines.h" +#include "xrdp_rail.h" +#include "xrdp_client_info.h" + +/* this is the freerdp main header */ +#include <freerdp/freerdp.h> +#include <freerdp/rail.h> +#include <freerdp/rail/rail.h> +#include <freerdp/codec/bitmap.h> +//#include <freerdp/utils/memory.h> +//#include "/home/jay/git/jsorg71/staging/include/freerdp/freerdp.h" + +struct bitmap_item +{ + int width; + int height; + char* data; +}; + +struct brush_item +{ + int bpp; + int width; + int height; + char* data; + char b8x8[8]; +}; + +struct pointer_item +{ + int hotx; + int hoty; + char data[32 * 32 * 3]; + char mask[32 * 32 / 8]; +}; + +#define CURRENT_MOD_VER 2 + +struct mod +{ + int size; /* size of this struct */ + int version; /* internal version */ + /* client functions */ + int (*mod_start)(struct mod* v, int w, int h, int bpp); + int (*mod_connect)(struct mod* v); + int (*mod_event)(struct mod* v, int msg, long param1, long param2, + long param3, long param4); + int (*mod_signal)(struct mod* v); + int (*mod_end)(struct mod* v); + int (*mod_set_param)(struct mod* v, char* name, char* value); + int (*mod_session_change)(struct mod* v, int, int); + int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, + tbus* write_objs, int* wcount, int* timeout); + int (*mod_check_wait_objs)(struct mod* v); + long mod_dumby[100 - 9]; /* align, 100 minus the number of mod + functions above */ + /* server functions */ + int (*server_begin_update)(struct mod* v); + int (*server_end_update)(struct mod* v); + int (*server_fill_rect)(struct mod* v, int x, int y, int cx, int cy); + int (*server_screen_blt)(struct mod* v, int x, int y, int cx, int cy, + int srcx, int srcy); + int (*server_paint_rect)(struct mod* v, int x, int y, int cx, int cy, + char* data, int width, int height, int srcx, int srcy); + int (*server_set_pointer)(struct mod* v, int x, int y, char* data, char* mask); + int (*server_palette)(struct mod* v, int* palette); + int (*server_msg)(struct mod* v, char* msg, int code); + int (*server_is_term)(struct mod* v); + int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); + int (*server_reset_clip)(struct mod* v); + int (*server_set_fgcolor)(struct mod* v, int fgcolor); + int (*server_set_bgcolor)(struct mod* v, int bgcolor); + int (*server_set_opcode)(struct mod* v, int opcode); + int (*server_set_mixmode)(struct mod* v, int mixmode); + int (*server_set_brush)(struct mod* v, int x_orgin, int y_orgin, + int style, char* pattern); + int (*server_set_pen)(struct mod* v, int style, + int width); + int (*server_draw_line)(struct mod* v, int x1, int y1, int x2, int y2); + int (*server_add_char)(struct mod* v, int font, int charactor, + int offset, int baseline, + int width, int height, char* data); + int (*server_draw_text)(struct mod* v, int font, + int flags, int mixmode, int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char* data, int data_len); + int (*server_reset)(struct mod* v, int width, int height, int bpp); + int (*server_query_channel)(struct mod* v, int index, + char* channel_name, + int* channel_flags); + int (*server_get_channel_id)(struct mod* v, char* name); + int (*server_send_to_channel)(struct mod* v, int channel_id, + char* data, int data_len, + int total_data_len, int flags); + int (*server_bell_trigger)(struct mod* v); + /* off screen bitmaps */ + int (*server_create_os_surface)(struct mod* v, int rdpindex, + int width, int height); + int (*server_switch_os_surface)(struct mod* v, int rdpindex); + int (*server_delete_os_surface)(struct mod* v, int rdpindex); + int (*server_paint_rect_os)(struct mod* mod, int x, int y, + int cx, int cy, + int rdpindex, int srcx, int srcy); + int (*server_set_hints)(struct mod* mod, int hints, int mask); + /* rail */ + int (*server_window_new_update)(struct mod* mod, int window_id, + struct rail_window_state_order* window_state, + int flags); + int (*server_window_delete)(struct mod* mod, int window_id); + int (*server_window_icon)(struct mod* mod, + int window_id, int cache_entry, int cache_id, + struct rail_icon_info* icon_info, + int flags); + int (*server_window_cached_icon)(struct mod* mod, + int window_id, int cache_entry, + int cache_id, int flags); + int (*server_notify_new_update)(struct mod* mod, + int window_id, int notify_id, + struct rail_notify_state_order* notify_state, + int flags); + int (*server_notify_delete)(struct mod* mod, int window_id, + int notify_id); + int (*server_monitored_desktop)(struct mod* mod, + struct rail_monitored_desktop_order* mdo, + int flags); + + long server_dumby[100 - 37]; /* align, 100 minus the number of server + functions above */ + /* common */ + tbus handle; /* pointer to self as long */ + tbus wm; + tbus painter; + int sck; + /* mod data */ + int width; + int height; + int bpp; + int colormap[256]; + char* chan_buf; + int chan_buf_valid; + int chan_buf_bytes; + int vmaj; + int vmin; + int vrev; + char username[256]; + char password[256]; + + struct xrdp_client_info client_info; + + struct rdp_freerdp* inst; + struct bitmap_item bitmap_cache[4][4096]; + struct brush_item brush_cache[64]; + struct pointer_item pointer_cache[32]; + +}; diff --git a/postinstall-pak b/postinstall-pak new file mode 100644 index 00000000..011857ad --- /dev/null +++ b/postinstall-pak @@ -0,0 +1,21 @@ +#!/bin/sh -e + +if ! ([ "$1" = "configure" ] || [ "$1" = "reconfigure" ]); then + exit 0 +fi + + +XRDP="xrdp" +ADDUSER="/usr/sbin/adduser" +XRDPLOG="/var/log/xrdp-sesman.log" +SESMANLOG="/var/log/xrdp-sesman.log" + +[ -d /var/run/xrdp ] || mkdir -p /var/run/xrdp +$ADDUSER --system --disabled-password --disabled-login --home /var/run/xrdp \ + --no-create-home --quiet --group $XRDP + +touch $SESMANLOG $XRDPLOG +chown $XRDP:$XRDP $SESMANLOG +chown $XRDP:$XRDP $XRDPLOG + +#DEBHELPER# diff --git a/sesman/access.c b/sesman/access.c index 00c9c381..692575e5 100644 --- a/sesman/access.c +++ b/sesman/access.c @@ -42,7 +42,7 @@ access_login_allowed(char *user) return 0; } - if (0 == g_cfg->sec.ts_users_enable) + if ((0 == g_cfg->sec.ts_users_enable) && (0==g_cfg->sec.ts_always_group_check)) { LOG_DBG("Terminal Server Users group is disabled, allowing authentication", 1); @@ -57,7 +57,7 @@ access_login_allowed(char *user) if (g_cfg->sec.ts_users == gid) { - LOG_DBG("ts_users is user's primary group"); + log_message(LOG_LEVEL_DEBUG,"ts_users is user's primary group"); return 1; } diff --git a/sesman/auth.h b/sesman/auth.h index 09bec2e9..39acc0b8 100644 --- a/sesman/auth.h +++ b/sesman/auth.h @@ -36,7 +36,7 @@ * */ long DEFAULT_CC -auth_userpass(char* user, char* pass); +auth_userpass(char* user, char* pass, int *errorcode); /** * diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 39d808c9..89753430 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -45,10 +45,12 @@ xrdp_chansrv_SOURCES = \ clipboard.c \ clipboard_file.c \ devredir.c \ + smartcard.c \ rail.c \ xcommon.c \ drdynvc.c \ - chansrv_fuse.c + chansrv_fuse.c \ + irp.c xrdp_chansrv_LDFLAGS = \ $(EXTRA_FLAGS) diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 9d55388e..0f7ff042 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 * Copyright (C) Laxmikant Rashinkar 2009-2012 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,6 +45,7 @@ static int g_rdpsnd_index = -1; static int g_rdpdr_index = -1; static int g_rail_index = -1; static int g_drdynvc_index = -1; +static int g_sent = 0; /* if sent data to xrdp, waiting response */ /* state info for dynamic virtual channels */ static struct xrdp_api_data *g_dvc_channels[MAX_DVC_CHANNELS]; @@ -149,6 +150,7 @@ send_data_from_chan_item(struct chan_item *chan_item) s_mark_end(s); LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " "size %d chan_flags 0x%8.8x", size, chan_flags)); + g_sent = 1; error = trans_force_write(g_con_trans); if (error != 0) @@ -214,7 +216,10 @@ send_channel_data(int chan_id, char *data, int size) if (g_chan_items[index].id == chan_id) { add_data_to_chan_item(g_chan_items + index, data, size); - check_chan_items(); + if (g_sent == 0) + { + check_chan_items(); + } return 0; } } @@ -376,7 +381,7 @@ process_message_channel_setup(struct stream *s) if (g_cliprdr_index >= 0) { clipboard_init(); - fuse_init(); + xfuse_init(); } if (g_rdpsnd_index >= 0) @@ -387,6 +392,7 @@ process_message_channel_setup(struct stream *s) if (g_rdpdr_index >= 0) { dev_redir_init(); + xfuse_init(); } if (g_rail_index >= 0) @@ -477,6 +483,7 @@ static int APP_CC process_message_channel_data_response(struct stream *s) { LOG(10, ("process_message_channel_data_response:")); + g_sent = 0; check_chan_items(); return 0; } @@ -953,7 +960,7 @@ channel_thread_loop(void *in_val) xcommon_check_wait_objs(); sound_check_wait_objs(); dev_redir_check_wait_objs(); - fuse_check_wait_objs(); + xfuse_check_wait_objs(); timeout = -1; num_objs = 0; objs[num_objs] = g_term_event; @@ -965,8 +972,8 @@ channel_thread_loop(void *in_val) 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); - fuse_get_wait_objs(objs, &num_objs, &timeout); - } + xfuse_get_wait_objs(objs, &num_objs, &timeout); + } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */ } trans_delete(g_lis_trans); diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index eb60f63a..70dd12af 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2012 + * 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. @@ -16,7 +16,74 @@ * limitations under the License. */ -#ifdef XRDP_FUSE +/* + * TODO + * o when creating dir/file, ensure it does not already exist + * o do not allow dirs to be created in ino==1 except for .clipbard and share mounts + * o fix the HACK where I have to use my own buf instead of g_buffer + * this is in func xfuse_check_wait_objs() + * o if fuse mount point is already mounted, I get segfault + * o in open, check for modes such as O_TRUNC, O_APPEND + * o copying over an existing file does not work + * o after a dir is created, the device cannot be unmounted on the client side + * so something is holding it up + * o in thunar, when I move a file by dragging to another folder, the file + * is getting copied instead of being moved + * o unable to edit files in vi + * o fuse ops to support + * o touch does not work + * o chmod must work + * o cat >> file is not working + * + */ + +//#define USE_SYNC_FLAG + +/* FUSE mount point */ +char g_fuse_root_path[256] = ""; +char g_fuse_clipboard_path[256] = ""; /* for clipboard use */ + +#ifndef XRDP_FUSE + +/****************************************************************************** +** ** +** when FUSE is NOT enabled in xrdp ** +** ** +******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arch.h" +#include "chansrv_fuse.h" + +/* dummy calls when XRDP_FUSE is not defined */ +int xfuse_init() {} +int xfuse_deinit() {} +int xfuse_check_wait_objs(void) {} +int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) {} +int xfuse_clear_clip_dir(void) {} +int xfuse_file_contents_range(int stream_id, char *data, int data_bytes) {} +int xfuse_file_contents_size(int stream_id, int file_size) {} +int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) {} +int xfuse_create_share(tui32 device_id, char *dirname) {} +void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId) {} +void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length) {} +void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length) {} +void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) {} +void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) {} +void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus) {} +void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus) {} +void xfuse_devredir_cb_file_close(void *vp) {} + +#else + +/****************************************************************************** +** ** +** when FUSE is enabled in xrdp ** +** ** +******************************************************************************/ #define FUSE_USE_VERSION 26 #define _FILE_OFFSET_BITS 64 @@ -24,692 +91,2940 @@ #include <fuse/fuse_lowlevel.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <errno.h> -#include <fcntl.h> +#include <time.h> #include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <sched.h> + #include "arch.h" -#include "parse.h" -#include "list.h" #include "os_calls.h" -#include "chansrv.h" #include "chansrv_fuse.h" -#include "clipboard_file.h" - -#define LLOG_LEVEL 1 -#define LLOGLN(_level, _args) \ - do \ - { \ - if (_level < LLOG_LEVEL) \ - { \ - g_write("chansrv:fuse [%10.10u]: ", g_time3()); \ - g_writeln _args ; \ - } \ - } \ - while (0) +#include "list.h" -char g_fuse_root_path[256] = ""; +#define min(x, y) ((x) < (y) ? (x) : (y)) -static struct fuse_chan *g_ch = 0; -static struct fuse_session *g_se = 0; -static char *g_mountpoint = 0; -static tintptr g_bufsize = 0; -static char *g_buffer = 0; -static int g_fd = 0; -static time_t g_time = 0; -static int g_uid = 0; -static int g_gid = 0; +#define XFUSE_ATTR_TIMEOUT 1.0 +#define XFUSE_ENTRY_TIMEOUT 1.0 -/* used for file data request sent to client */ -struct req_list_item +#define DOTDOT_INODE 0 +#define DOT_INODE 0 +#define FIRST_INODE 1 + +/* 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]: FUSE %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + +#define log_info(_params...) \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: FUSE %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +#define log_debug(_params...) \ +{ \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: FUSE %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +#define OP_RENAME_FILE 0x01 + +/* the xrdp file system in memory */ +struct xrdp_fs { - fuse_req_t req; - int stream_id; - int lindex; - int off; - int size; + struct xrdp_inode **inode_table; /* a table of entries; can grow */ + unsigned int max_entries; /* size of inode_table[] */ + unsigned int num_entries; /* num entries available in inode_table */ + unsigned int next_node; /* next free node number */ }; -static struct list *g_req_list = 0; struct dirbuf { char *p; - int size; - int alloc_bytes; + size_t size; }; -struct xfuse_file_info +struct dirbuf1 { - int ino; + char buf[4096]; + int bytes_in_buf; + int first_time; +}; + +/* FUSE reply types */ +#define RT_FUSE_REPLY_OPEN 1 +#define RT_FUSE_REPLY_CREATE 2 + +struct xfuse_info +{ + struct fuse_file_info *fi; + fuse_req_t req; + fuse_ino_t inode; + fuse_ino_t new_inode; + int invoke_fuse; + char name[1024]; + char new_name[1024]; + tui32 device_id; + int reply_type; + int mode; + int type; + size_t size; + off_t off; + struct dirbuf1 dirbuf1; +}; +typedef struct xfuse_info XFUSE_INFO; + +struct xfuse_handle +{ + tui32 DeviceId; + tui32 FileId; + int is_loc_resource; /* this is not a redirected resource */ +}; +typedef struct xfuse_handle XFUSE_HANDLE; + +/* used for file data request sent to client */ +struct req_list_item +{ + fuse_req_t req; + int stream_id; int lindex; - char pathname[256]; - char filename[256]; - int flags; + int off; int size; - tui64 time; - struct xfuse_file_info* child; - struct xfuse_file_info* parent; - struct xfuse_file_info* next; - struct xfuse_file_info* prev; }; -static struct xfuse_file_info *g_fuse_files = 0; -static struct fuse_lowlevel_ops g_xrdp_ll_oper; -static int g_ino = 2; +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 */ +static struct fuse_lowlevel_ops g_xfuse_ops; /* setup FUSE callbacks */ +static int g_xfuse_inited = 0; /* true when FUSE is inited */ +static struct fuse_chan *g_ch = 0; +static struct fuse_session *g_se = 0; +static char *g_buffer = 0; +static int g_fd = 0; +static tintptr g_bufsize = 0; + +/* forward declarations for internal access */ +static int xfuse_init_xrdp_fs(); +static int xfuse_deinit_xrdp_fs(); +static int xfuse_init_lib(struct fuse_args *args); +static int xfuse_is_inode_valid(int ino); + +// LK_TODO +#if 0 +static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, int type); +#endif + +static void xfuse_dump_fs(); +static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino); +static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path); +static void fuse_reverse_pathname(char *full_path, char *reverse_path); + +static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode, + const char *name); + +static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, + int pinode, char *name, + int type); -/*****************************************************************************/ -static struct xfuse_file_info *APP_CC -fuse_find_file_info_by_name(struct xfuse_file_info *ffi, const char *filename) +static int xfuse_does_file_exist(int parent, char *name); +static int xfuse_delete_file(int parent, char *name); +static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode); +static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode); +static void xfuse_update_xrdpfs_size(); +static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi); + +/* forward declarations for calls we make into devredir */ +int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path); + +int dev_redir_file_open(void *fusep, tui32 device_id, char *path, + int mode, int type, char *gen_buf); + +int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId, + tui32 Length, tui64 Offset); + +int dev_redir_file_write(void *fusep, tui32 device_id, tui32 FileId, + const char *buf, tui32 Length, tui64 Offset); + +int devredir_file_close(void *fusep, tui32 device_id, tui32 FileId); + +/* forward declarations for FUSE callbacks */ +static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, + const char *name); + +static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + +/* this is not a callback, but its's used by xfuse_cb_readdir() */ +static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, + const char *name, fuse_ino_t ino); + +static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, + const char *name, fuse_ino_t ino); + +static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi); + +static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode); + +static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, + const char *name); + +static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, + const char *name); + +static void xfuse_cb_rename(fuse_req_t req, + fuse_ino_t old_parent, const char *old_name, + fuse_ino_t new_parent, const char *new_name); + +/* this is not a callback, but it is used by the above two functions */ +static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent, + const char *name, int type); + +static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi, int type); + +static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + +static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct + fuse_file_info *fi); + +static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi); + +static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + +static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi); + +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); + +/***************************************************************************** +** ** +** public functions - can be called from any code path ** +** ** +*****************************************************************************/ + +/** + * Initialize FUSE subsystem + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_init() { - struct xfuse_file_info *rv; - struct xfuse_file_info *rv1; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - rv = ffi; - while (rv != 0) + /* if already inited, just return */ + if (g_xfuse_inited) { - if (g_strcmp(rv->filename, filename) == 0) - { - return rv; - } - if (rv->flags & 1) + log_debug("already inited"); + return 1; + } + + if (g_ch != 0) + { + log_error("g_ch is not zero"); + return -1; + } + + /* define FUSE mount point to ~/xrdp_client */ + g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME")); + g_snprintf(g_fuse_clipboard_path, 255, "%s/.clipboard", g_fuse_root_path); + + /* if FUSE mount point does not exist, create it */ + if (!g_directory_exist(g_fuse_root_path)) + { + if (!g_create_dir(g_fuse_root_path)) { - rv1 = fuse_find_file_info_by_name(rv->child, filename); - if (rv1 != 0) - { - return rv1; - } + log_error("mkdir %s failed. If %s is already mounted, you must " + "first unmount it", g_fuse_root_path, g_fuse_root_path); + return -1; } - rv = rv->next; } + + /* setup xrdp file system */ + if (xfuse_init_xrdp_fs()) + return -1; + + /* setup FUSE callbacks */ + g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops)); + g_xfuse_ops.lookup = xfuse_cb_lookup; + g_xfuse_ops.readdir = xfuse_cb_readdir; + g_xfuse_ops.mkdir = xfuse_cb_mkdir; + g_xfuse_ops.rmdir = xfuse_cb_rmdir; + g_xfuse_ops.unlink = xfuse_cb_unlink; + g_xfuse_ops.rename = xfuse_cb_rename; + g_xfuse_ops.open = xfuse_cb_open; + g_xfuse_ops.release = xfuse_cb_release; + g_xfuse_ops.read = xfuse_cb_read; + g_xfuse_ops.write = xfuse_cb_write; + g_xfuse_ops.create = xfuse_cb_create; + //g_xfuse_ops.fsync = xfuse_cb_fsync; /* LK_TODO delete this */ + g_xfuse_ops.getattr = xfuse_cb_getattr; + g_xfuse_ops.setattr = xfuse_cb_setattr; + + fuse_opt_add_arg(&args, "xrdp-chansrv"); + fuse_opt_add_arg(&args, g_fuse_root_path); + + if (xfuse_init_lib(&args)) + { + xfuse_deinit(); + return -1; + } + + g_xfuse_inited = 1; return 0; } -/*****************************************************************************/ -static struct xfuse_file_info *APP_CC -fuse_find_file_info_by_ino(struct xfuse_file_info *ffi, int ino) +/** + * De-initialize FUSE subsystem + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_deinit() { - struct xfuse_file_info *rv; - struct xfuse_file_info *rv1; + xfuse_deinit_xrdp_fs(); - rv = ffi; - while (rv != 0) + if (g_ch != 0) { - if (rv->ino == ino) - { - return rv; - } - if (rv->flags & 1) + fuse_session_remove_chan(g_ch); + fuse_unmount(g_mount_point, g_ch); + g_ch = 0; + } + + if (g_se != 0) + { + fuse_session_destroy(g_se); + g_se = 0; + } + + if (g_buffer != 0) + { + g_free(g_buffer); + g_buffer = 0; + } + + if (g_req_list != 0) + { + list_delete(g_req_list); + g_req_list = 0; + } + + g_xfuse_inited = 0; + return 0; +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ +int xfuse_check_wait_objs(void) +{ + struct fuse_chan *tmpch; + int rval; + +#define HACK + +#ifdef HACK +char buf[135168]; +#endif + + if (g_ch == 0) + return 0; + + if (g_tcp_select(g_fd, 0) & 1) + { + tmpch = g_ch; + +#ifdef HACK + rval = fuse_chan_recv(&tmpch, buf, g_bufsize); +#else + rval = fuse_chan_recv(&tmpch, g_buffer, g_bufsize); +#endif + if (rval == -EINTR) + return -1; + + if (rval == -ENODEV) + return -1; + + if (rval <= 0) + return -1; + +#ifdef HACK + fuse_session_process(g_se, buf, rval, tmpch); +#else + fuse_session_process(g_se, g_buffer, rval, tmpch); +#endif + } + + return 0; +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) +{ + int lcount; + + if (g_ch == 0) + return 0; + + lcount = *count; + objs[lcount] = g_fd; + lcount++; + *count = lcount; + + return 0; +} + +/** + * @brief Create specified share directory. + * + * This code gets called from devredir + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_create_share(tui32 device_id, char *dirname) +{ +#if 0 + XFUSE_INFO *fip; +#endif + XRDP_INODE *xinode; + /* tui32 saved_inode; */ + + if (dirname == NULL || strlen(dirname) == 0) + return -1; + + if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) + { + log_debug("calloc() failed"); + return -1; + } + + /* create directory entry */ + xinode->parent_inode = 1; + xinode->inode = g_xrdp_fs.next_node++; + xinode->mode = 0755 | S_IFDIR; + xinode->nlink = 1; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->size = 0; + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + strcpy(xinode->name, dirname); + xinode->device_id = device_id; + + g_xrdp_fs.num_entries++; + /* saved_inode = xinode->inode; */ + + /* insert it in xrdp fs */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + log_debug("created new share named %s at inode_table[%d]", + dirname, (int) xinode->inode); + + /* update nentries in parent inode */ + xinode = g_xrdp_fs.inode_table[1]; + if (xinode == NULL) + return -1; + xinode->nentries++; + +#if 0 + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + return -1; + } + + /* enumerate root dir, do not call FUSE when done */ + fip->req = NULL; + fip->inode = 1; /* TODO saved_inode; */ + strncpy(fip->name, dirname, 1024); + fip->name[1023] = 0; + fip->device_id = device_id; + + dev_redir_get_dir_listing((void *) fip, device_id, "\\"); +#endif + + return 0; +} + +/** + * Clear all clipboard entries in xrdp_fs + * + * This function is called by clipboard code + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_clear_clip_dir(void) +{ + int i; + XRDP_INODE *xinode; + XRDP_INODE *xip; + + log_debug("entered"); + + /* xinode for .clipboard */ + xip = g_xrdp_fs.inode_table[2]; + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + if (xinode->parent_inode == 2) { - rv1 = fuse_find_file_info_by_ino(rv->child, ino); - if (rv1 != 0) - { - return rv1; - } + g_xrdp_fs.inode_table[i] = NULL; + free(xinode); + xip->nentries--; } - rv = rv->next; } + return 0; } -/*****************************************************************************/ -static int APP_CC -xrdp_ffi2stat(struct xfuse_file_info *ffi, struct stat *stbuf) +/** + * Return clipboard data to fuse + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_file_contents_range(int stream_id, char *data, int data_bytes) { - stbuf->st_ino = ffi->ino; - if (ffi->flags & 1) + log_debug("entered: stream_id=%d data_bytes=%d", stream_id, data_bytes); + + struct req_list_item *rli; + + if ((rli = (struct req_list_item *) list_get_item(g_req_list, 0)) == NULL) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - stbuf->st_uid = g_uid; - stbuf->st_gid = g_gid; - stbuf->st_atime = g_time; - stbuf->st_mtime = g_time; - stbuf->st_ctime = g_time; + log_error("range error!"); + return -1; } - else + + log_debug("lindex=%d off=%d size=%d", rli->lindex, rli->off, rli->size); + + fuse_reply_buf(rli->req, data, data_bytes); + + list_remove_item(g_req_list, 0); + if (g_req_list->count <= 0) { - stbuf->st_mode = S_IFREG | 0664; - stbuf->st_nlink = 1; - stbuf->st_size = ffi->size; - stbuf->st_uid = g_uid; - stbuf->st_gid = g_gid; - stbuf->st_atime = g_time; - stbuf->st_mtime = g_time; - stbuf->st_ctime = g_time; + log_debug("completed all requests"); + return 0; } + + /* send next request */ + rli = (struct req_list_item *) list_get_item(g_req_list, 0); + if (rli == NULL) + { + log_error("range error!"); + return -1; + } + + log_debug("requesting clipboard file data"); + + clipboard_request_file_data(rli->stream_id, rli->lindex, + rli->off, rli->size); + return 0; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) +/** + * Create a file in .clipboard dir + * + * This function is called by clipboard code + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +{ + log_debug("entered: filename=%s flags=%d size=%d lindex=%d", + filename, flags, size, lindex); + + /* add entry to xrdp_fs */ + XRDP_INODE *xinode = xfuse_create_file_in_xrdp_fs(0, /* device id */ + 2, /* parent inode */ + filename, + S_IFREG); + xinode->size = size; + xinode->lindex = lindex; + xinode->is_loc_resource = 1; + + return 0; +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_file_contents_size(int stream_id, int file_size) +{ + log_debug("entered: stream_id=%d file_size=%d", stream_id, file_size); + return 0; +} + +/***************************************************************************** +** ** +** private functions - can only be called from within this file ** +** ** +*****************************************************************************/ + +/** + * Initialize FUSE library + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +static int xfuse_init_lib(struct fuse_args *args) { - struct xfuse_file_info *ffi; - struct fuse_entry_param e; + if (fuse_parse_cmdline(args, &g_mount_point, 0, 0) < 0) + { + log_error("fuse_parse_cmdline() failed"); + fuse_opt_free_args(args); + return -1; + } - LLOGLN(10, ("xrdp_ll_lookup: name %s", name)); - if (parent != 1) + if ((g_ch = fuse_mount(g_mount_point, args)) == 0) { - fuse_reply_err(req, ENOENT); + log_error("fuse_mount() failed"); + fuse_opt_free_args(args); + return -1; } - else + + g_se = fuse_lowlevel_new(args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0); + if (g_se == 0) { - ffi = fuse_find_file_info_by_name(g_fuse_files, name); - if (ffi != 0) - { - LLOGLN(10, ("xrdp_ll_lookup: name %s ino %d", name, ffi->ino)); - g_memset(&e, 0, sizeof(e)); - e.ino = ffi->ino; - e.attr_timeout = 1.0; - e.entry_timeout = 1.0; - xrdp_ffi2stat(ffi, &e.attr); - fuse_reply_entry(req, &e); - return; - } + log_error("fuse_lowlevel_new() failed"); + fuse_unmount(g_mount_point, g_ch); + g_ch = 0; + fuse_opt_free_args(args); + return -1; } - fuse_reply_err(req, ENOENT); + + fuse_opt_free_args(args); + fuse_session_add_chan(g_se, g_ch); + g_bufsize = fuse_chan_bufsize(g_ch); + + g_buffer = calloc(g_bufsize, 1); + g_fd = fuse_chan_fd(g_ch); + + g_req_list = list_create(); + g_req_list->auto_free = 1; + + return 0; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +/** + * Initialize xrdp file system + * + * @return 0 on success, -1 on failure + * + *****************************************************************************/ + +static int xfuse_init_xrdp_fs() { - struct stat stbuf; - struct xfuse_file_info *ffi; + struct xrdp_inode *xino; - LLOGLN(10, ("xrdp_ll_getattr: ino %d", ino)); - g_memset(&stbuf, 0, sizeof(stbuf)); - if (ino == 1) + g_xrdp_fs.inode_table = calloc(4096, sizeof(struct xrdp_inode *)); + if (g_xrdp_fs.inode_table == NULL) { - stbuf.st_mode = S_IFDIR | 0755; - stbuf.st_nlink = 2; - stbuf.st_uid = g_uid; - stbuf.st_gid = g_gid; - stbuf.st_atime = g_time; - stbuf.st_mtime = g_time; - stbuf.st_ctime = g_time; - fuse_reply_attr(req, &stbuf, 1.0); - return; + log_error("system out of memory"); + return -1; } - ffi = fuse_find_file_info_by_ino(g_fuse_files, ino); - if (ffi == 0) + + /* + * index 0 is our .. dir + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - LLOGLN(0, ("xrdp_ll_getattr: fuse_find_file_info_by_ino failed ino %d", ino)); - fuse_reply_err(req, ENOENT); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table); + return -1; } - else if (xrdp_ffi2stat(ffi, &stbuf) == -1) + g_xrdp_fs.inode_table[0] = xino; + xino->parent_inode = 0; + xino->inode = 0; + xino->mode = S_IFDIR | 0755; + xino->nentries = 1; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + strcpy(xino->name, ".."); + + /* + * index 1 is our . dir + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - fuse_reply_err(req, ENOENT); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table[0]); + free(g_xrdp_fs.inode_table); + return -1; } - else + g_xrdp_fs.inode_table[1] = xino; + xino->parent_inode = 0; + xino->inode = 1; + xino->mode = S_IFDIR | 0755; + xino->nentries = 1; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + strcpy(xino->name, "."); + + /* + * index 2 is for clipboard use + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - fuse_reply_attr(req, &stbuf, 1.0); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table[0]); + free(g_xrdp_fs.inode_table[1]); + free(g_xrdp_fs.inode_table); + return -1; } + + g_xrdp_fs.inode_table[2] = xino; + xino->parent_inode = 1; + xino->inode = 2; + xino->nentries = 0; + xino->mode = S_IFDIR | 0755; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + xino->is_loc_resource = 1; + strcpy(xino->name, ".clipboard"); + + g_xrdp_fs.max_entries = 4096; + g_xrdp_fs.num_entries = 3; + g_xrdp_fs.next_node = 3; + + return 0; } -/*****************************************************************************/ -static void APP_CC -dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, fuse_ino_t ino) +/** + * zap the xrdp file system + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +static int xfuse_deinit_xrdp_fs() { - struct stat stbuf; - char *newp; - int oldsize; - - oldsize = b->size; - b->size += fuse_add_direntry(req, 0, 0, name, 0, 0); - LLOGLN(10, ("1 %d %d %d", b->alloc_bytes, b->size, oldsize)); - if (b->size > b->alloc_bytes) - { - b->alloc_bytes = (b->size + 1023) & (~1023); - LLOGLN(10, ("2 %d %d %d", b->alloc_bytes, b->size, oldsize)); - newp = g_malloc(b->alloc_bytes, 0); - g_memcpy(newp, b->p, oldsize); - g_free(b->p); - b->p = newp; - } - g_memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_ino = ino; - fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, - &stbuf, b->size); + return 0; +} + +/** + * determine if specified ino exists in xrdp file system + * + * @return 1 if it does, 0 otherwise + *****************************************************************************/ + +static int xfuse_is_inode_valid(int ino) +{ + /* our lowest ino is FIRST_INODE */ + if (ino < FIRST_INODE) + return 0; + + /* is ino present in our table? */ + if (ino >= g_xrdp_fs.next_node) + return 0; + + return 1; } -#define lmin(x, y) ((x) < (y) ? (x) : (y)) +/** + * @brief Create a directory or regular file. + *****************************************************************************/ -/*****************************************************************************/ -static int APP_CC -reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, - off_t off, size_t maxsize) +// LK_TODO +#if 0 +static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, int type) { - LLOGLN(10, ("reply_buf_limited: %d", maxsize)); - if (off < bufsize) + struct xrdp_inode *xinode; + struct fuse_entry_param e; + + log_debug("parent=%d name=%s", (int) parent, name); + + /* do we have a valid parent inode? */ + if (!xfuse_is_inode_valid(parent)) { - return fuse_reply_buf(req, buf + off, - lmin(bufsize - off, maxsize)); + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); } - else + + if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - return fuse_reply_buf(req, 0, 0); + log_error("calloc() failed"); + fuse_reply_err(req, ENOMEM); } + + /* create directory entry */ + xinode->parent_inode = parent; + xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */ + xinode->mode = mode | type; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->size = 0; + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + strcpy(xinode->name, name); + + g_xrdp_fs.num_entries++; + + /* insert it in xrdp fs */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + xfuse_update_xrdpfs_size(); + log_debug("inserted new dir at inode_table[%d]", (int) xinode->inode); + + xfuse_dump_fs(); + + log_debug("new inode=%d", (int) xinode->inode); + + /* setup return value */ + memset(&e, 0, sizeof(e)); + e.ino = xinode->inode; + e.attr_timeout = XFUSE_ATTR_TIMEOUT; + e.entry_timeout = XFUSE_ENTRY_TIMEOUT; + e.attr.st_ino = xinode->inode; + e.attr.st_mode = xinode->mode; + e.attr.st_nlink = xinode->nlink; + e.attr.st_uid = xinode->uid; + e.attr.st_gid = xinode->gid; + e.attr.st_size = 0; + e.attr.st_atime = xinode->atime; + e.attr.st_mtime = xinode->mtime; + e.attr.st_ctime = xinode->ctime; + e.generation = 1; + + fuse_reply_entry(req, &e); } +#endif -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) +static void xfuse_dump_fs() { - struct xfuse_file_info *ffi; - struct dirbuf b; + int i; + struct xrdp_inode *xinode; - LLOGLN(10, ("xrdp_ll_readdir: ino %d", ino)); - if (ino != 1) - { - fuse_reply_err(req, ENOTDIR); - } - else + log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE); + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - ffi = g_fuse_files; - g_memset(&b, 0, sizeof(b)); - dirbuf_add(req, &b, ".", 1); - dirbuf_add(req, &b, "..", 1); - while (ffi != 0) - { - LLOGLN(10, ("xrdp_ll_readdir: %s", ffi->filename)); - dirbuf_add(req, &b, ffi->filename, ffi->ino); - ffi = ffi->next; - } - reply_buf_limited(req, b.p, b.size, off, size); - g_free(b.p); + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + log_debug("pinode=%d inode=%d nentries=%d nopen=%d is_synced=%d name=%s", + (int) xinode->parent_inode, (int) xinode->inode, + xinode->nentries, xinode->nopen, xinode->is_synced, + xinode->name); } + log_debug(""); +} + +/** + * Dump contents of xinode structure + * + * @param xino xinode structure to dump + *****************************************************************************/ + +static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino) +{ + log_debug("--- dumping struct xinode ---"); + log_debug("name: %s", xino->name); + log_debug("parent_inode: %ld", xino->parent_inode); + log_debug("inode: %ld", xino->inode); + log_debug("mode: %o", xino->mode); + log_debug("nlink: %d", xino->nlink); + log_debug("uid: %d", xino->uid); + log_debug("gid: %d", xino->gid); + log_debug("size: %ld", xino->size); + log_debug("device_id: %d", xino->device_id); + log_debug(""); } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +/** + * Return the device_id associated with specified inode and copy the + * full path to the specified inode into full_path + * + * @param ino the inode + * @param full_path full path to the inode + * + * @return the device_id of specified inode + *****************************************************************************/ + +static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path) { - LLOGLN(10, ("xrdp_ll_open: ino %d", (int)ino)); + tui32 parent_inode = 0; + tui32 child_inode = ino; + char reverse_path[4096]; + + /* ino == 1 is a special case; we already know that it is not */ + /* associated with any device redirection */ if (ino == 1) { - fuse_reply_err(req, EISDIR); + /* just return the device_id for the file in full_path */ + log_debug("looking for file with pinode=%d name=%s", ino, full_path); + xfuse_dump_fs(); + + XRDP_INODE *xinode = xfuse_get_inode_from_pinode_name(ino, full_path); + full_path[0] = 0; + if (xinode) + return xinode->device_id; + else + return 0; } - else if ((fi->flags & 3) != O_RDONLY) + + reverse_path[0] = 0; + full_path[0] = 0; + + while (1) { - fuse_reply_err(req, EACCES); + strcat(reverse_path, g_xrdp_fs.inode_table[child_inode]->name); + + parent_inode = g_xrdp_fs.inode_table[child_inode]->parent_inode; + if (parent_inode == 1) + break; + + strcat(reverse_path, "/"); + child_inode = parent_inode; } - else + + fuse_reverse_pathname(full_path, reverse_path); + + return g_xrdp_fs.inode_table[child_inode]->device_id; +} + +/** + * Reverse the pathname in 'reverse_path' and insert it into 'full_path' + * + * Example: abba/music/share1 becomes share1/music/abba + * + * @param full_path path name in the correct order + * @param reverse_path path name in the reverse order + *****************************************************************************/ + +static void fuse_reverse_pathname(char *full_path, char *reverse_path) +{ + char *cptr; + + full_path[0] = 0; + + while ((cptr = strrchr(reverse_path, '/')) != NULL) { - fuse_reply_open(req, fi); + strcat(full_path, cptr + 1); + strcat(full_path, "/"); + cptr[0] = 0; } + strcat(full_path, reverse_path); } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) +/** + * Return the inode that matches the name and parent inode + *****************************************************************************/ + +static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode, + const char *name) { - char *data; - int stream_id; - struct xfuse_file_info *ffi; - struct req_list_item *rli; + int i; + struct xrdp_inode * xinode; - LLOGLN(10, ("xrdp_ll_read: %d %d %d", (int)ino, (int)off, (int)size)); - ffi = fuse_find_file_info_by_ino(g_fuse_files, ino); - if (ffi != 0) + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - /* reply later */ - stream_id = 0; - rli = (struct req_list_item *) - g_malloc(sizeof(struct req_list_item), 1); - rli->req = req; - rli->stream_id = stream_id; - rli->lindex = ffi->lindex; - rli->off = off; - rli->size = size; - list_add_item(g_req_list, (tbus)rli); - if (g_req_list->count == 1) - { - clipboard_request_file_data(rli->stream_id, rli->lindex, - rli->off, rli->size); - } - return; - } - LLOGLN(0, ("xrdp_ll_read: fuse_find_file_info_by_ino failed ino %d", (int)ino)); - data = (char *)g_malloc(size, 1); - fuse_reply_buf(req, data, size); - g_free(data); + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + /* match parent inode */ + if (xinode->parent_inode != pinode) + continue; + + /* match name */ + if (strcmp(xinode->name, name) != 0) + continue; + + return xinode; + } + return NULL; } -/*****************************************************************************/ -/* returns error */ -static int APP_CC -fuse_init_lib(int argc, char **argv) +/** + * Create file in xrdp file system + * + * @param pinode the parent inode + * @param name filename + * + * @return XRDP_INODE on success, NULL on failure + *****************************************************************************/ + +static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, + int pinode, char *name, + int type) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - int error; + XRDP_INODE *xinode; + XRDP_INODE *xinodep; - error = fuse_parse_cmdline(&args, &g_mountpoint, 0, 0); - if (error == -1) + if ((name == NULL) || (strlen(name) == 0)) + return NULL; + + if ((xinode = calloc(1, sizeof(XRDP_INODE))) == NULL) { - LLOGLN(0, ("fuse_init_lib: fuse_parse_cmdline failed")); - fuse_opt_free_args(&args); - return 1; + log_error("system out of memory"); + return NULL; } - g_ch = fuse_mount(g_mountpoint, &args); - if (g_ch == 0) + + xinode->parent_inode = pinode; + xinode->inode = g_xrdp_fs.next_node++; + xinode->nlink = 1; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + xinode->device_id = device_id; + xinode->is_synced = 1; + strcpy(xinode->name, name); + + if (type == S_IFDIR) { - LLOGLN(0, ("fuse_init_lib: fuse_mount failed")); - fuse_opt_free_args(&args); - return 1; + xinode->mode = 0755 | type; + xinode->size = 4096; } - g_se = fuse_lowlevel_new(&args, &g_xrdp_ll_oper, - sizeof(g_xrdp_ll_oper), 0); - if (g_se == 0) + else { - LLOGLN(0, ("fuse_init_lib: fuse_lowlevel_new failed")); - fuse_unmount(g_mountpoint, g_ch); - g_ch = 0; - fuse_opt_free_args(&args); - return 1; + xinode->mode = 0644 | type; + xinode->size = 0; } - fuse_opt_free_args(&args); - fuse_session_add_chan(g_se, g_ch); - g_bufsize = fuse_chan_bufsize(g_ch); - g_buffer = g_malloc(g_bufsize, 0); - g_fd = fuse_chan_fd(g_ch); - return 0; + + g_xrdp_fs.inode_table[xinode->inode] = xinode; + g_xrdp_fs.num_entries++; + + /* bump up lookup count in parent dir */ + xinodep = g_xrdp_fs.inode_table[pinode]; + xinodep->nentries++; + xfuse_update_xrdpfs_size(); + + log_debug("incremented nentries; parent=%d nentries=%d", + pinode, xinodep->nentries); + + /* LK_TODO */ + xfuse_dump_fs(); + + return xinode; } -/*****************************************************************************/ -static int APP_CC -fuse_delete_dir_items(struct xfuse_file_info *ffi) +/** + * Check if specified file exists + * + * @param parent parent inode of file + * @param name flilename or dirname + * + * @return 1 if specified file exists, 0 otherwise + *****************************************************************************/ + +static int xfuse_does_file_exist(int parent, char *name) { - struct xfuse_file_info *ffi1; + int i; + XRDP_INODE *xinode; - while (ffi != 0) + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - if (ffi->flags & 1) + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + if ((xinode->parent_inode == parent) && + (strcmp(xinode->name, name) == 0)) { - fuse_delete_dir_items(ffi->child); + return 1; } - ffi1 = ffi; - ffi = ffi->next; - g_free(ffi1); } + return 0; } -/*****************************************************************************/ -int APP_CC -fuse_clear_clip_dir(void) +static int xfuse_delete_file(int parent, char *name) +{ + return -1; +} + +static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode) { - fuse_delete_dir_items(g_fuse_files); - g_fuse_files = 0; + /* make sure it is not a dir */ + if ((xinode == NULL) || (xinode->mode & S_IFDIR)) + return -1; + + g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; + g_xrdp_fs.inode_table[xinode->inode] = NULL; + free(xinode); + return 0; } -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode) { - struct xfuse_file_info *ffi; - struct xfuse_file_info *ffi1; + XRDP_INODE *xip; + int i; - LLOGLN(10, ("fuse_add_clip_dir_item: adding %s ino %d", filename, g_ino)); - ffi = g_fuse_files; - if (ffi == 0) + /* make sure it is not a file */ + if ((xinode == NULL) || (xinode->mode & S_IFREG)) + return -1; + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - ffi1 = (struct xfuse_file_info *) - g_malloc(sizeof(struct xfuse_file_info), 1); - ffi1->flags = flags; - ffi1->ino = g_ino++; - ffi1->lindex = lindex; - ffi1->size = size; - g_strncpy(ffi1->filename, filename, 255); - g_fuse_files = ffi1; - return 0; + if ((xip = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + /* look for child inodes */ + if (xip->parent_inode == xinode->inode) + { + /* got one, delete it */ + g_xrdp_fs.inode_table[xip->inode] = NULL; + free(xip); + } } - while (ffi->next != 0) + + /* our parent will have one less dir */ + g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--; + + g_xrdp_fs.inode_table[xinode->inode] = NULL; + free(xinode); + + return 0; +} + +static void xfuse_update_xrdpfs_size() +{ + void *vp; + int diff; + + diff = g_xrdp_fs.max_entries - g_xrdp_fs.num_entries; + if (diff > 100) + return; + + /* extend memory */ + vp = realloc(g_xrdp_fs.inode_table, + (g_xrdp_fs.max_entries + 100) * sizeof(struct xrdp_inode *)); + + if (vp == NULL) { - ffi = ffi->next; + log_error("system out of memory"); + return; } - ffi1 = (struct xfuse_file_info *) - g_malloc(sizeof(struct xfuse_file_info), 1); - ffi1->flags = flags; - ffi1->ino = g_ino++; - ffi1->lindex = lindex; - ffi1->size = size; - g_strncpy(ffi1->filename, filename, 255); - ffi->next = ffi1; - return 0; + + /* zero newly added memory */ + memset(vp + g_xrdp_fs.max_entries * sizeof(struct xrdp_inode *), + 0, + 100 * sizeof(struct xrdp_inode *)); + + g_xrdp_fs.max_entries += 100; + g_xrdp_fs.inode_table = vp; } -/*****************************************************************************/ -int APP_CC -fuse_get_wait_objs(tbus *objs, int *count, int *timeout) +static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) { - int lcount; + XRDP_INODE *xinode; + XRDP_INODE *xinode1; + struct dirbuf b; + int first_time = 1; + int i; - LLOGLN(10, ("fuse_get_wait_objs:")); - if (g_ch == 0) + memset(&b, 0, sizeof(struct dirbuf)); + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - return 0; + 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); } - lcount = *count; - objs[lcount] = g_fd; - lcount++; - *count = lcount; - return 0; + 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); } -/*****************************************************************************/ -int APP_CC -fuse_check_wait_objs(void) +/****************************************************************************** +** ** +** callbacks for devredir ** +** ** +******************************************************************************/ + +/** + * Add a file or directory to xrdp file system + *****************************************************************************/ + +/* LK_TODO delete this after testing */ +#if 0 +void ___xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { - struct fuse_chan *tmpch; - int res; + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *xip = NULL; - LLOGLN(10, ("fuse_check_wait_objs:")); - if (g_ch == 0) + log_debug("<<<<<< entered"); + + if ((fip == NULL) || (xinode == NULL)) { - return 0; + log_error("fip or xinode are NULL"); + printf("RASH_TODO: fip or xinode are NULL - leaving\n"); + return; } - if (g_tcp_select(g_fd, 0) & 1) + + log_debug("req=%p", fip->req); + + /* do we have a valid inode? */ + if (!xfuse_is_inode_valid(fip->inode)) { - LLOGLN(10, ("fuse_check_wait_objs: fd is set")); - tmpch = g_ch; - res = fuse_chan_recv(&tmpch, g_buffer, g_bufsize); - if (res == -EINTR) + log_error("inode %d is not valid", fip->inode); + printf("RASH_TODO: inode %d is not valid - leaving\n", (tui32) fip->inode); + return; + } + + /* if filename is . or .. don't add it */ + if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) + { + free(xinode); + printf("RASH_TODO: not adding ./.. - leaving\n"); + return; + } + +// LK_TODO +#if 0 + /* we have a parent inode and a dir name; what we need is the xinode */ + /* that matches the parent inode and the dir name */ + target_inode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); + if (target_inode == 0) + { + log_debug("did not find entry with inode=%d name=%s", + fip->inode, fip->name); + return; + } +#endif + + if ((xip = xfuse_get_inode_from_pinode_name(fip->inode, xinode->name)) != NULL) + { + log_debug("inode=%d name=%s already exists in xrdp_fs; not adding it", + fip->inode, xinode->name); + free(xinode); + xinode = xip; + goto update_fuse; + } + + xinode->parent_inode = fip->inode; + xinode->inode = g_xrdp_fs.next_node++; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->device_id = fip->device_id; + + g_xrdp_fs.num_entries++; + + /* insert it in xrdp fs and update lookup count */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + g_xrdp_fs.inode_table[fip->inode]->nentries; + xfuse_update_xrdpfs_size(); + +update_fuse: + +#if 1 + /* let FUSE know about this entry */ + if (fip->invoke_fuse) + { + struct dirbuf b; + + memset(&b, 0, sizeof(struct dirbuf)); + + /* RASH_TODO if we are not using dirbuf, change this code */ + if (fip->dirbuf == NULL) { - return 0; + fip->dirbuf = calloc(1, sizeof(struct dirbuf)); + xfuse_dirbuf_add(fip->req, &b, ".", xinode->inode); + xfuse_dirbuf_add(fip->req, &b, "..", xinode->parent_inode); } - if (res <= 0) + + xfuse_dirbuf_add(fip->req, &b, xinode->name, xinode->inode); + + if (fip->off < b.size) { - return 1; + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): req=%p off=%d\n", + fip->req, (tui32) fip->off); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping req b4\n\n"); + g_hexdump((char *) fip->req, 128); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping buf b4\n\n"); + g_hexdump(b.p, b.size); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse\n"); + + fuse_reply_buf(fip->req, b.p, b.size); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse...done\n"); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping req aft\n\n"); + g_hexdump((char *) fip->req, 128); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping buf aft\n\n"); + g_hexdump(b.p, b.size); } - fuse_session_process(g_se, g_buffer, res, tmpch); + else + { + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse with NULL\n"); + fuse_reply_buf(fip->req, NULL, 0); + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse with NULL...done\n"); + } + + log_debug("added inode=%d name=%s to FUSE", (tui32) xinode->inode, xinode->name); } - return 0; +#endif + + log_debug("leaving"); + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): leaving\n"); } +#endif -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_init(void) +void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { - char *param0 = "xrdp-chansrv"; - char *argv[4]; + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *xip = NULL; - if (g_ch != 0) + if ((fip == NULL) || (xinode == NULL)) { - return 0; + log_error("fip or xinode are NULL"); + return; } - g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME")); - LLOGLN(0, ("fuse_init: using root_path [%s]", g_fuse_root_path)); - if (!g_directory_exist(g_fuse_root_path)) + + log_debug("fip->req=%p", fip->req); + + if (!xfuse_is_inode_valid(fip->inode)) { - if (!g_create_dir(g_fuse_root_path)) - { - LLOGLN(0, ("fuse_init: g_create_dir failed [%s]", - g_fuse_root_path)); - return 1; - } + log_error("inode %d is not valid", fip->inode); + return; } - g_time = g_time1(); - g_uid = g_getuid(); - g_gid = g_getgid(); - argv[0] = param0; - argv[1] = g_fuse_root_path; - argv[2] = 0; - g_memset(&g_xrdp_ll_oper, 0, sizeof(g_xrdp_ll_oper)); - g_xrdp_ll_oper.lookup = xrdp_ll_lookup; - g_xrdp_ll_oper.getattr = xrdp_ll_getattr; - g_xrdp_ll_oper.readdir = xrdp_ll_readdir; - g_xrdp_ll_oper.open = xrdp_ll_open; - g_xrdp_ll_oper.read = xrdp_ll_read; + /* if filename is . or .. don't add it */ + if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) + { + free(xinode); + return; + } - g_req_list = list_create(); - g_req_list->auto_free = 1; + if ((xip = xfuse_get_inode_from_pinode_name(fip->inode, xinode->name)) != NULL) + { + log_debug("inode=%d name=%s already exists in xrdp_fs; not adding it", + fip->inode, xinode->name); + free(xinode); + xinode = xip; + return; + } + + xinode->parent_inode = fip->inode; + xinode->inode = g_xrdp_fs.next_node++; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->device_id = fip->device_id; - return fuse_init_lib(2, argv); + g_xrdp_fs.num_entries++; + + /* insert it in xrdp fs and update lookup count */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + g_xrdp_fs.inode_table[fip->inode]->nentries++; /* this was missing */ + xfuse_update_xrdpfs_size(); } -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_deinit(void) +/** + *****************************************************************************/ + +void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) { - LLOGLN(0, ("fuse_deinit:")); - if (g_ch != 0) + log_debug(">>>>>> vp=%p IoStatus=0x%x", vp, IoStatus); + + if (vp == NULL) + return; + + XRDP_INODE *xinode; + XRDP_INODE *ti; + struct dirbuf1 b; + int i; + int first_time = 1; + + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + + if (fip == NULL) { - LLOGLN(0, ("fuse_deinit: calling fuse_unmount")); - fuse_session_remove_chan(g_ch); - fuse_unmount(g_mountpoint, g_ch); - g_ch = 0; + log_debug("fip is NULL"); + goto done; } - if (g_se != 0) + + log_debug("fip->req=%p", fip->req); + + if (IoStatus != 0) { - LLOGLN(0, ("fuse_deinit: calling fuse_session_destroy")); - fuse_session_destroy(g_se); - g_se = 0; + /* command failed */ + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOENT); + goto done; } - if (g_buffer != 0) + + /* do we have a valid inode? */ + if (!xfuse_is_inode_valid(fip->inode)) { - g_free(g_buffer); - g_buffer = 0; + log_error("inode %d is not valid", fip->inode); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, EBADF); + goto done; } - if (g_req_list != 0) +#if 0 + memset(&b, 0, sizeof(struct dirbuf)); +#else + b.bytes_in_buf = 0; +#endif + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - list_delete(g_req_list); - g_req_list = 0; + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + /* match parent inode */ + if (xinode->parent_inode != fip->inode) + continue; + + xinode->is_synced = 1; + + if (first_time) + { + first_time = 0; + ti = g_xrdp_fs.inode_table[fip->inode]; +#if 0 + xfuse_dirbuf_add(fip->req, &b, ".", fip->inode); + xfuse_dirbuf_add(fip->req, &b, "..", ti->parent_inode); +#else + xfuse_dirbuf_add1(fip->req, &b, ".", fip->inode); + xfuse_dirbuf_add1(fip->req, &b, "..", ti->parent_inode); +#endif + } +#if 0 + xfuse_dirbuf_add(fip->req, &b, xinode->name, xinode->inode); +#else + xfuse_dirbuf_add1(fip->req, &b, xinode->name, xinode->inode); +#endif } - return 0; + + if ((first_time == 0) && (fip->invoke_fuse)) + { + if (fip->off < b.bytes_in_buf) + { +#if 0 + fuse_reply_buf(fip->req, b.p + fip->off, + min(b.size - fip->off, fip->size)); +#else + log_debug("calling fuse_reply_buf() with data..."); + fuse_reply_buf(fip->req, b.buf, b.bytes_in_buf); + log_debug("calling fuse_reply_buf() with data...done"); +#endif + } + else + { + log_debug("calling fuse_reply_buf() with NULL..."); + fuse_reply_buf(fip->req, NULL, 0); + log_debug("calling fuse_reply_buf() with NULL...done"); + } + } + else + { + log_debug("calling fuse_reply_err()..."); + fuse_reply_err(fip->req, ENOENT); + log_debug("calling fuse_reply_err()...done"); + } + +done: + +#if 0 + if (b.p) + free(b.p); +#endif + + if (!fip) + printf("###### %s : %s : %d: fip is NULL\n", __FILE__, __func__, __LINE__); + + if (fip) + free(fip); } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_size(int stream_id, int file_size) +void xfuse_devredir_cb_enum_dir_done_TODO(void *vp, tui32 IoStatus) { - LLOGLN(10, ("fuse_file_contents_size: file_size %d", file_size)); - return 0; + struct xrdp_inode *xinode; + struct fuse_entry_param e; + int i; + + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + + printf("--------- xfuse_devredir_cb_enum_dir_done() entered\n"); + + xfuse_dump_fs(); + + if (fip == NULL) + { + log_debug("fip is NULL"); + goto done; + } + + if (IoStatus != 0) + { + /* command failed */ + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOENT); + goto done; + } + + /* do we have a valid inode? */ + if (!xfuse_is_inode_valid(fip->inode)) + { + log_error("inode %d is not valid", fip->inode); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, EBADF); + goto done; + } + + log_debug("looking for parent_inode=%d name=%s", fip->inode, fip->name); + + 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 != fip->inode) + continue; + + /* match name */ + if (strcmp(xinode->name, fip->name) != 0) + continue; + + memset(&e, 0, sizeof(e)); + e.ino = xinode->inode; + e.attr_timeout = XFUSE_ATTR_TIMEOUT; + e.entry_timeout = XFUSE_ENTRY_TIMEOUT; + e.attr.st_ino = xinode->inode; + e.attr.st_mode = xinode->mode; + e.attr.st_nlink = xinode->nlink; + e.attr.st_uid = xinode->uid; + e.attr.st_gid = xinode->gid; + e.attr.st_size = xinode->size; + e.attr.st_atime = xinode->atime; + e.attr.st_mtime = xinode->mtime; + e.attr.st_ctime = xinode->ctime; + e.generation = 1; + + xinode->is_synced = 1; + + if (fip->invoke_fuse) + fuse_reply_entry(fip->req, &e); + + break; + } + + if (i == g_xrdp_fs.num_entries) + { + /* requested entry not found */ + log_debug("did NOT find entry"); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOENT); + } + +done: + + free(fip); } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_range(int stream_id, char *data, int data_bytes) +void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId) { - struct req_list_item *rli; + XFUSE_HANDLE *fh; + XRDP_INODE *xinode; + + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + if (fip == NULL) + { + log_debug("fip is NULL"); + goto done; + } + + log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p DeviceId=%d FileId=%d", + fip, fip->fi, DeviceId, FileId); - LLOGLN(10, ("fuse_file_contents_range: data_bytes %d", data_bytes)); - rli = (struct req_list_item *)list_get_item(g_req_list, 0); - if (rli != 0) + if (fip->fi != NULL) { - fuse_reply_buf(rli->req, data, data_bytes); - list_remove_item(g_req_list, 0); - if (g_req_list->count > 0) + if ((fh = calloc(1, sizeof(XFUSE_HANDLE))) == NULL) { - /* send next request */ - rli = (struct req_list_item *)list_get_item(g_req_list, 0); - if (rli != 0) + log_error("system out of memory"); + free(fip); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOMEM); + return; + } + + /* save file handle for later use */ + fh->DeviceId = DeviceId; + fh->FileId = FileId; + + fip->fi->fh = (uint64_t) ((long) fh); + log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=%p", + fip, fip->fi, fip->fi->fh); + } + + if (fip->invoke_fuse) + { + if (fip->reply_type == RT_FUSE_REPLY_OPEN) + { + log_debug("LK_TODO sending fuse_reply_open(); " + "DeviceId=%d FileId=%d req=%p fi=%p", + fh->DeviceId, fh->FileId, fip->req, fip->fi); + + /* update open count */ + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) + xinode->nopen++; + + fuse_reply_open(fip->req, fip->fi); + } + else if (fip->reply_type == RT_FUSE_REPLY_CREATE) + { + struct fuse_entry_param e; + +// LK_TODO +#if 0 + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL) { - clipboard_request_file_data(rli->stream_id, rli->lindex, - rli->off, rli->size); + log_error("inode at inode_table[%d] is NULL", fip->inode); + fuse_reply_err(fip->req, EBADF); + goto done; + } +#else + /* create entry in xrdp file system */ + xinode = xfuse_create_file_in_xrdp_fs(fip->device_id, fip->inode, + fip->name, fip->mode); + if (xinode == NULL) + { + fuse_reply_err(fip->req, ENOMEM); + return; + } +#endif + memset(&e, 0, sizeof(struct fuse_entry_param)); + + e.ino = xinode->inode; + e.attr_timeout = XFUSE_ATTR_TIMEOUT; + e.entry_timeout = XFUSE_ENTRY_TIMEOUT; + e.attr.st_ino = xinode->inode; + e.attr.st_mode = xinode->mode; + e.attr.st_nlink = xinode->nlink; + e.attr.st_uid = xinode->uid; + e.attr.st_gid = xinode->gid; + e.attr.st_size = xinode->size; + e.attr.st_atime = xinode->atime; + e.attr.st_mtime = xinode->mtime; + e.attr.st_ctime = xinode->ctime; + e.generation = 1; + + if (fip->mode == S_IFDIR) + { + fuse_reply_entry(fip->req, &e); } else { - LLOGLN(0, ("fuse_file_contents_range: error")); + xinode->nopen++; + fuse_reply_create(fip->req, &e, fip->fi); } } + else + { + log_error("invalid reply type: %d", fip->reply_type); + } + } + +done: + + free(fip); +} + +void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length) +{ + XFUSE_INFO *fip; + + fip = (XFUSE_INFO *) vp; + if ((fip == NULL) || (fip->req == NULL)) + { + log_error("fip for fip->req is NULL"); + return; } + + fuse_reply_buf(fip->req, buf, length); + free(fip); +} + +void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length) +{ + XRDP_INODE *xinode; + XFUSE_INFO *fip; + + fip = (XFUSE_INFO *) vp; + if ((fip == NULL) || (fip->req == NULL) || (fip->fi == NULL)) + { + log_error("fip, fip->req or fip->fi is NULL"); + return; + } + + log_debug("+++ XFUSE_INFO=%p, XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=%p", + fip, fip->fi, fip->fi->fh); + + fuse_reply_write(fip->req, length); + + /* update file size */ + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) + xinode->size += length; else + log_error("inode at inode_table[%d] is NULL", fip->inode); + + free(fip); +} + +void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus) +{ + XFUSE_INFO *fip; + XRDP_INODE *xinode; + + fip = (XFUSE_INFO *) vp; + if (fip == NULL) + return; + + if (IoStatus != 0) { - LLOGLN(0, ("fuse_file_contents_range: error")); + fuse_reply_err(fip->req, EBADF); + free(fip); + return; } - return 0; + + /* now delete the item in xrdp fs */ + xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); + if (xinode == NULL) + { + fuse_reply_err(fip->req, EBADF); + free(fip); + return; + } + + g_xrdp_fs.inode_table[xinode->inode] = NULL; + free(xinode); + + /* update parent */ + xinode = g_xrdp_fs.inode_table[fip->inode]; + xinode->nentries--; + + fuse_reply_err(fip->req, 0); + free(fip); } -#else +void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus) +{ + XFUSE_INFO *fip; + XRDP_INODE *old_xinode; + XRDP_INODE *new_xinode; -#include "arch.h" + fip = (XFUSE_INFO *) vp; + if (fip == NULL) + return; -char g_fuse_root_path[256] = ""; + if (IoStatus != 0) + { + fuse_reply_err(fip->req, EEXIST); + free(fip); + return; + } + + /* + * update xrdp file system + */ + + /* if destination dir/file exists, delete it */ + if (xfuse_does_file_exist(fip->new_inode, fip->new_name)) + { + new_xinode = xfuse_get_inode_from_pinode_name(fip->new_inode, + fip->new_name); + + if (new_xinode->mode & S_IFREG) + xfuse_delete_file_with_xinode(new_xinode); + else + xfuse_delete_dir_with_xinode(new_xinode); + + new_xinode = NULL; + } + + old_xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); + if (old_xinode == NULL) + { + fuse_reply_err(fip->req, EBADF); + free(fip); + return; + } -/*****************************************************************************/ -int APP_CC -fuse_get_wait_objs(tbus *objs, int *count, int *timeout) + old_xinode->parent_inode = fip->new_inode; + strcpy(old_xinode->name, fip->new_name); + + if (fip->inode != fip->new_inode) + { + /* file has been moved to a different dir */ + old_xinode->is_synced = 1; + g_xrdp_fs.inode_table[fip->inode]->nentries--; + g_xrdp_fs.inode_table[fip->new_inode]->nentries++; + } + + fuse_reply_err(fip->req, 0); + free(fip); +} + +void xfuse_devredir_cb_file_close(void *vp) { - return 0; + XFUSE_INFO *fip; + XRDP_INODE *xinode; + + fip = (XFUSE_INFO *) vp; + if (fip == NULL) + { + log_error("fip is NULL"); + return; + } + + if (fip->fi == NULL) + { + log_error("fip->fi is NULL"); + return; + } + + log_debug("+++ XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=%p", + fip, fip->fi, fip->fi->fh); + + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL) + { + log_debug("inode_table[%d] is NULL", fip->inode); + fuse_reply_err(fip->req, EBADF); + return; + } + + log_debug("before: inode=%d nopen=%d", xinode->inode, xinode->nopen); + + if (xinode->nopen > 0) + xinode->nopen--; + + /* LK_TODO */ +#if 0 + if ((xinode->nopen == 0) && fip->fi && fip->fi->fh) + { + printf("LK_TODO: ################################ fi=%p fi->fh=%p\n", + fip->fi, fip->fi->fh); + + free((char *) (tintptr) (fip->fi->fh)); + fip->fi->fh = NULL; + } +#endif + + fuse_reply_err(fip->req, 0); } -/*****************************************************************************/ -int APP_CC -fuse_check_wait_objs(void) +/****************************************************************************** +** ** +** callbacks for fuse ** +** ** +******************************************************************************/ + +/** + * Look up a directory entry by name and get its attributes + * + *****************************************************************************/ + +static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - return 0; + XRDP_INODE *xinode; + struct fuse_entry_param e; + + log_debug("looking for parent=%d name=%s", (int) parent, name); + xfuse_dump_fs(); + + if (!xfuse_is_inode_valid(parent)) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; + } + + xinode = xfuse_get_inode_from_pinode_name(parent, name); + if (xinode == NULL) + { + log_debug("did not find entry for parent=%d name=%s", parent, name); + fuse_reply_err(req, ENOENT); + return; + } + + memset(&e, 0, sizeof(e)); + e.ino = xinode->inode; + e.attr_timeout = XFUSE_ATTR_TIMEOUT; + e.entry_timeout = XFUSE_ENTRY_TIMEOUT; + e.attr.st_ino = xinode->inode; + e.attr.st_mode = xinode->mode; + e.attr.st_nlink = xinode->nlink; + e.attr.st_uid = xinode->uid; + e.attr.st_gid = xinode->gid; + e.attr.st_size = xinode->size; + e.attr.st_atime = xinode->atime; + e.attr.st_mtime = xinode->mtime; + e.attr.st_ctime = xinode->ctime; + e.generation = 1; + + fuse_reply_entry(req, &e); + log_debug("found entry for parent=%d name=%s uid=%d gid=%d", + parent, name, xinode->uid, xinode->gid); + return; } -/*****************************************************************************/ -int APP_CC -fuse_init(void) +/** + * Get file attributes + *****************************************************************************/ + +static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) { - return 0; + struct xrdp_inode *xino; + struct stat stbuf; + + (void) fi; + + log_debug("req=%p ino=%d", req, (int) ino); + + /* if ino is not valid, just return */ + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + xino = g_xrdp_fs.inode_table[ino]; + + 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"); } -/*****************************************************************************/ -int APP_CC -fuse_deinit(void) +/** + * + *****************************************************************************/ + +static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, + const char *name, fuse_ino_t ino) { - return 0; + struct stat stbuf; + size_t oldsize = b->size; + + log_debug("adding ino=%d name=%s", (int) ino, name); + + b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0); + b->p = (char *) realloc(b->p, b->size); + + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, + b->size); } -/*****************************************************************************/ -int APP_CC -fuse_clear_clip_dir(void) +static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, + const char *name, fuse_ino_t ino) { + struct stat stbuf; + int len; + + len = fuse_add_direntry(req, NULL, 0, name, NULL, 0); + if (b->bytes_in_buf + len > 4096) + { + log_debug("not adding entry because dirbuf overflow would occur"); + return -1; + } + + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + + fuse_add_direntry(req, + &b->buf[b->bytes_in_buf], /* index where new entry will be added to buf */ + 4096 - len, /* remaining size of buf */ + name, /* name of entry */ + &stbuf, /* file attributes */ + b->bytes_in_buf + len /* offset of next entry */ + ); + + b->bytes_in_buf += len; return 0; } -/*****************************************************************************/ -int APP_CC -fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +/** + * + *****************************************************************************/ + +static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) { - return 0; + XRDP_INODE *xinode; + XFUSE_INFO *fip; + tui32 device_id; + char full_path[4096]; + char *cptr; + + log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + if (ino == 1) + { + /* special case; enumerate top level dir */ + log_debug("enumerating top level dir"); + xfuse_enum_dir(req, ino, size, off, fi); + return; + } + + xinode = g_xrdp_fs.inode_table[ino]; + if (xinode->is_loc_resource) + { + /* enumerate local resources */ + xfuse_enum_dir(req, ino, size, off, fi); + return; + } + + /* enumerate resources on a remote device */ + +#ifdef USE_SYNC_FLAG + if (xinode->is_synced) + { + xfuse_enum_dir(req, ino, size, off, fi); + return; + } + else + { + goto do_remote_lookup; + } +#endif + +do_remote_lookup: + + log_debug("did not find entry; redirecting call to dev_redir"); + device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path); + log_debug("dev_id=%d ino=%d full_path=%s", device_id, ino, full_path); + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->inode = ino; + fip->size = size; + fip->off = off; + fip->fi = fi; + fip->dirbuf1.first_time = 1; + fip->dirbuf1.bytes_in_buf = 0; + + fip->invoke_fuse = 1; + fip->device_id = device_id; + + log_debug("fip->req=%p", fip->req); + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) + { + /* enumerate root dir */ + if (dev_redir_get_dir_listing((void *) fip, device_id, "\\")) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_buf(req, NULL, 0); + } + } + else + { + if (dev_redir_get_dir_listing((void *) fip, device_id, cptr)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_buf(req, NULL, 0); + } + } } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_size(int stream_id, int file_size) +/** + * Create a directory + *****************************************************************************/ + +static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode) { - return 0; + XRDP_INODE *xinode; + struct fuse_entry_param e; + + log_debug("entered: parent_inode=%d name=%s", (int) parent, name); + + if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL) + { + /* dir already exists, just return it */ + memset(&e, 0, sizeof(struct fuse_entry_param)); + + e.ino = xinode->inode; + e.attr_timeout = XFUSE_ATTR_TIMEOUT; + e.entry_timeout = XFUSE_ENTRY_TIMEOUT; + e.attr.st_ino = xinode->inode; + e.attr.st_mode = xinode->mode; + e.attr.st_nlink = xinode->nlink; + e.attr.st_uid = xinode->uid; + e.attr.st_gid = xinode->gid; + e.attr.st_size = xinode->size; + e.attr.st_atime = xinode->atime; + e.attr.st_mtime = xinode->mtime; + e.attr.st_ctime = xinode->ctime; + e.generation = 1; + + fuse_reply_entry(req, &e); + return; + } + + /* dir does not exist, create it */ + xfuse_create_dir_or_file(req, parent, name, mode, NULL, S_IFDIR); } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_range(int stream_id, char *data, int data_bytes) +/** + * Remove specified dir + *****************************************************************************/ + +static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, + const char *name) { - return 0; + xfuse_remove_dir_or_file(req, parent, name, 1); } -#endif +static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + xfuse_remove_dir_or_file(req, parent, name, 2); +} + +/** + * Remove a dir or file + * + * @param type 1=dir, 2=file + *****************************************************************************/ + +static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent, + const char *name, int type) +{ + XFUSE_INFO *fip; + XRDP_INODE *xinode; + char *cptr; + char full_path[4096]; + tui32 device_id; + + log_debug("entered: parent=%d name=%s", parent, name); + + /* is parent inode valid? */ + if (!xfuse_is_inode_valid(parent)) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; + } + + if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) == NULL) + { + log_error("did not find file with pinode=%d name=%s", parent, name); + fuse_reply_err(req, EBADF); + return; + } + + device_id = xfuse_get_device_id_for_inode(parent, full_path); + + log_debug("path=%s nentries=%d", full_path, xinode->nentries); + + if ((type == 1) && (xinode->nentries != 0)) + { + log_debug("cannot rmdir; lookup count is %d", xinode->nentries); + fuse_reply_err(req, ENOTEMPTY); + return; + } + else if (type == 2) + { + if ((xinode->nopen > 1) || ((xinode->nopen == 1) && + (xinode->close_in_progress == 0))) + { + log_debug("cannot unlink; open count is %d", xinode->nopen); + fuse_reply_err(req, EBUSY); + return; + } + } + + strcat(full_path, "/"); + strcat(full_path, name); + + if (xinode->is_loc_resource) + { + /* specified file is a local resource */ + //XFUSE_HANDLE *fh; + + log_debug("LK_TODO: this is still a TODO"); + fuse_reply_err(req, EINVAL); + return; + } + + /* specified file resides on redirected share */ + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->inode = parent; + fip->invoke_fuse = 1; + fip->device_id = device_id; + strncpy(fip->name, name, 1024); + fip->name[1023] = 0; + fip->type = type; + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) + { + /* get dev_redir to open the remote file */ + if (devredir_rmdir_or_file((void *) fip, device_id, "\\", O_RDWR)) + { + log_error("failed to send dev_redir_open_file() cmd"); + fuse_reply_err(req, EREMOTEIO); + free(fip); + return; + } + } + else + { + if (devredir_rmdir_or_file((void *) fip, device_id, cptr, O_RDWR)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_err(req, EREMOTEIO); + free(fip); + return; + } + } +} + +static void xfuse_cb_rename(fuse_req_t req, + fuse_ino_t old_parent, const char *old_name, + fuse_ino_t new_parent, const char *new_name) +{ + XRDP_INODE *old_xinode; + XFUSE_INFO *fip; + tui32 new_device_id; + char *cptr; + char old_full_path[1024]; + char new_full_path[1024]; + char *cp; + + tui32 device_id; + + log_debug("entered: old_parent=%d old_name=%s new_parent=%d new_name=%s", + old_parent, old_name, new_parent, new_name); + xfuse_dump_fs(); + + /* is old_parent inode valid? */ + if (!xfuse_is_inode_valid(old_parent)) + { + log_error("inode %d is not valid", old_parent); + fuse_reply_err(req, EINVAL); + return; + } + + /* is new_parent inode valid? */ + if (!xfuse_is_inode_valid(new_parent)) + { + log_error("inode %d is not valid", new_parent); + fuse_reply_err(req, EINVAL); + return; + } + + if ((old_name == NULL) || (strlen(old_name) == 0)) + { + fuse_reply_err(req, EINVAL); + return; + } + + if ((new_name == NULL) || (strlen(new_name) == 0)) + { + fuse_reply_err(req, EINVAL); + return; + } + + old_xinode = xfuse_get_inode_from_pinode_name(old_parent, old_name); + if (old_xinode == NULL) + { + log_error("did not find file with pinode=%d name=%s", + old_parent, old_name); + fuse_reply_err(req, EBADF); + return; + } + + /* if file is open, cannot rename */ + if (old_xinode->nopen != 0) + { + fuse_reply_err(req, EBUSY); + return; + } + + /* rename across file systems not yet supported */ + new_device_id = xfuse_get_device_id_for_inode(new_parent, new_full_path); + strcat(new_full_path, "/"); + strcat(new_full_path, new_name); + + if (new_device_id != old_xinode->device_id) + { + log_error("rename across file systems not supported"); + fuse_reply_err(req, EINVAL); + return; + } + + if (old_xinode->is_loc_resource) + { + /* specified file is a local resource */ + log_debug("LK_TODO: this is still a TODO"); + fuse_reply_err(req, EINVAL); + return; + } + + /* resource is on a redirected share */ + + device_id = old_xinode->device_id; + + xfuse_get_device_id_for_inode(old_parent, old_full_path); + strcat(old_full_path, "/"); + strcat(old_full_path, old_name); + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->inode = old_parent; + fip->new_inode = new_parent; + strncpy(fip->name, old_name, 1024); + strncpy(fip->new_name, new_name, 1024); + fip->name[1023] = 0; + fip->new_name[1023] = 0; + fip->invoke_fuse = 1; + fip->device_id = device_id; + + if ((cp = strchr(new_full_path, '/')) == NULL) + cp = "\\"; + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(old_full_path, '/')) == NULL) + { + /* get dev_redir to open the remote file */ + if (dev_redir_file_open((void *) fip, device_id, "\\", + O_RDWR, S_IFREG | OP_RENAME_FILE, cp)) + { + log_error("failed to send dev_redir_file_open() cmd"); + fuse_reply_err(req, EREMOTEIO); + free(fip); + return; + } + } + else + { + if (dev_redir_file_open((void *) fip, device_id, cptr, + O_RDWR, S_IFREG | OP_RENAME_FILE, cp)) + { + log_error("failed to send dev_redir_file_open() cmd"); + fuse_reply_err(req, EREMOTEIO); + free(fip); + return; + } + } +} + +/** + * Create a directory or file + * + * @param req opaque FUSE object + * @param parent parent inode + * @param name name of dir or file to create + * @param mode creation mode + * @param fi for storing file handles + * @param type S_IFDIR for dir and S_IFREG for file + *****************************************************************************/ + +static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi, int type) +{ + XFUSE_INFO *fip; + char *cptr; + char full_path[1024]; + tui32 device_id; + + full_path[0] = 0; + + log_debug("entered: parent_ino=%d name=%s type=%s", + (int) parent, name, (type == S_IFDIR) ? "dir" : "file"); + + /* name must be valid */ + if ((name == NULL) || (strlen(name) == 0)) + { + log_error("invalid name"); + fuse_reply_err(req, EBADF); + return; + } + + /* is parent inode valid? */ + if ((parent == 1) || (!xfuse_is_inode_valid(parent))) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; + } + + device_id = xfuse_get_device_id_for_inode(parent, full_path); + strcat(full_path, "/"); + strcat(full_path, name); + + XRDP_INODE *xinode = g_xrdp_fs.inode_table[parent]; + if (xinode->is_loc_resource) + { + /* specified file is a local resource */ + //XFUSE_HANDLE *fh; + + log_debug("LK_TODO: this is still a TODO"); + fuse_reply_err(req, EINVAL); + return; + } + + /* specified file resides on redirected share */ + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->fi = fi; + fip->inode = parent; + fip->invoke_fuse = 1; + fip->device_id = device_id; + fip->mode = type; + fip->reply_type = RT_FUSE_REPLY_CREATE; + strncpy(fip->name, name, 1024); + fip->name[1023] = 0; + + log_debug("+++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p", fip, fip->fi); + + /* LK_TODO need to handle open permissions */ + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) + { + /* get dev_redir to open the remote file */ + if (dev_redir_file_open((void *) fip, device_id, "\\", + O_CREAT, type, NULL)) + { + log_error("failed to send dev_redir_open_file() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } + else + { + if (dev_redir_file_open((void *) fip, device_id, cptr, + O_CREAT, type, NULL)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } +} + +/** + * Open specified file + *****************************************************************************/ + +static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + XRDP_INODE *xinode; + XFUSE_INFO *fip; + char *cptr; + char full_path[4096]; + tui32 device_id; + + log_debug("entered: ino=%d", (int) ino); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + /* if ino points to a dir, fail the open request */ + xinode = g_xrdp_fs.inode_table[ino]; + if (xinode->mode & S_IFDIR) + { + log_debug("reading a dir not allowed!"); + fuse_reply_err(req, EISDIR); + return; + } + + device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path); + + if (xinode->is_loc_resource) + { + /* specified file is a local resource */ + XFUSE_HANDLE *fh = calloc(1, sizeof(XFUSE_HANDLE)); + fh->is_loc_resource = 1; + fi->fh = (uint64_t) ((long) fh); + fuse_reply_open(req, fi); + return; + } + + /* specified file resides on redirected share */ + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->inode = ino; + fip->invoke_fuse = 1; + fip->device_id = device_id; + fip->fi = fi; + + log_debug("LK_TODO: fip->fi = %p", fip->fi); + + strncpy(fip->name, full_path, 1024); + 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) + { + /* get dev_redir to open the remote file */ + if (dev_redir_file_open((void *) fip, device_id, "\\", + fi->flags, S_IFREG, NULL)) + { + log_error("failed to send dev_redir_open_file() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } + else + { + if (dev_redir_file_open((void *) fip, device_id, cptr, + fi->flags, S_IFREG, NULL)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } +} + +static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct + fuse_file_info *fi) +{ + XFUSE_INFO *fip = NULL; + XFUSE_HANDLE *handle = (XFUSE_HANDLE *) (tintptr) (fi->fh); + tui32 FileId; + + log_debug("entered: ino=%d fi=%p fi->fh=%p", (int) ino, fi, fi->fh); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + XRDP_INODE *xinode = g_xrdp_fs.inode_table[ino]; + if (xinode->is_loc_resource) + { + /* specified file is a local resource */ + fuse_reply_err(req, 0); + return; + } + + /* specified file resides on redirected share */ + + log_debug("nopen=%d", xinode->nopen); + + /* if file is not opened, just return */ + if (xinode->nopen == 0) + { + log_debug("cannot close because file not opened"); + fuse_reply_err(req, 0); + return; + } + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fip->req = req; + fip->inode = ino; + fip->invoke_fuse = 1; + fip->device_id = handle->DeviceId; + fip->fi = fi; + + log_debug(" +++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=%p", + fip, fip->fi, fip->fi->fh); + + FileId = handle->FileId; + free(handle); + fip->fi->fh = NULL; + xinode->close_in_progress = 1; + + if (devredir_file_close((void *) fip, fip->device_id, handle->FileId)) + { + log_error("failed to send devredir_close_file() cmd"); + fuse_reply_err(req, EREMOTEIO); + } +} + +/** + *****************************************************************************/ + +static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + XFUSE_HANDLE *fh; + XFUSE_INFO *fusep; + XRDP_INODE *xinode; + struct req_list_item *rli; + long handle; + + log_debug("want_bytes %ld bytes at off %ld", size, off); + + if (fi->fh == 0) + { + fuse_reply_err(req, EINVAL); + return; + } + + handle = fi->fh; + fh = (XFUSE_HANDLE *) handle; + + if (fh->is_loc_resource) + { + /* target file is in .clipboard dir */ + + log_debug("target file is in .clipboard dir"); + + if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL) + { + log_error("ino does not exist in xrdp_fs"); + fuse_reply_buf(req, 0, 0); + return; + } + + rli = (struct req_list_item *) + g_malloc(sizeof(struct req_list_item), 1); + + rli->stream_id = 0; + rli->req = req; + rli->lindex = xinode->lindex; + rli->off = off; + rli->size = size; + list_add_item(g_req_list, (tbus) rli); + + if (g_req_list->count == 1) + { + log_debug("requesting clipboard file data lindex = %d off = %d size = %d", + rli->lindex, (int) off, (int) size); + + clipboard_request_file_data(rli->stream_id, rli->lindex, + (int) off, (int) size); + } + + return; + } + + /* target file is on a remote device */ + + if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + fusep->req = req; + fusep->inode = ino; + fusep->invoke_fuse = 1; + fusep->device_id = fh->DeviceId; + fusep->fi = fi; + + dev_redir_file_read(fusep, fh->DeviceId, fh->FileId, size, off); +} + +/** + *****************************************************************************/ + +static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi) +{ + XFUSE_HANDLE *fh; + XFUSE_INFO *fusep; + long handle; + + log_debug("write %d bytes at off %d to inode=%d", + (int) size, (int) off, (int) ino); + + if (fi->fh == 0) + { + log_error("file handle fi->fh is NULL"); + fuse_reply_err(req, EINVAL); + return; + } + + handle = fi->fh; + fh = (XFUSE_HANDLE *) handle; + + if (fh->is_loc_resource) + { + /* target file is in .clipboard dir */ + log_debug("THIS IS STILL A TODO!"); + return; + } + + /* target file is on a remote device */ + + if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + + fusep->req = req; + fusep->inode = ino; + fusep->invoke_fuse = 1; + fusep->device_id = fh->DeviceId; + fusep->fi = fi; + + log_debug("+++ created XFUSE_INFO=%p XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=%p", + fusep, fusep->fi, fusep->fi->fh); + + dev_redir_file_write(fusep, fh->DeviceId, fh->FileId, buf, size, off); + log_debug("exiting"); +} + +/** + *****************************************************************************/ + +static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi) +{ + log_debug("entered: parent_inode=%d, name=%s fi=%p", + (int) parent, name, fi); + + xfuse_create_dir_or_file(req, parent, name, mode, fi, S_IFREG); +} + +/** + *****************************************************************************/ + +static void xfuse_cb_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi) +{ + log_debug("#################### entered: ino=%d datasync=%d", (int) ino, datasync); + log_debug("function not required"); + fuse_reply_err(req, EINVAL); +} + +/** + *****************************************************************************/ + +static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi) +{ + XRDP_INODE *xinode; + struct stat st; + + log_debug("entered to_set=0x%x", to_set); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + xinode = g_xrdp_fs.inode_table[ino]; + + if (to_set & FUSE_SET_ATTR_MODE) + { + xinode->mode = attr->st_mode; + log_debug("FUSE_SET_ATTR_MODE"); + + } + + if (to_set & FUSE_SET_ATTR_UID) + { + xinode->uid = attr->st_uid; + log_debug("FUSE_SET_ATTR_UID"); + } + + if (to_set & FUSE_SET_ATTR_GID) + { + xinode->gid = attr->st_gid; + log_debug("FUSE_SET_ATTR_GID"); + } + + if (to_set & FUSE_SET_ATTR_SIZE) + { + log_debug("previous file size: %d", attr->st_size); + xinode->size = attr->st_size; + log_debug("returning file size: %d", xinode->size); + } + + if (to_set & FUSE_SET_ATTR_ATIME) + { + xinode->atime = attr->st_atime; + log_debug("FUSE_SET_ATTR_ATIME"); + } + + if (to_set & FUSE_SET_ATTR_MTIME) + { + xinode->mtime = attr->st_mtime; + log_debug("FUSE_SET_ATTR_MTIME"); + } + + if (to_set & FUSE_SET_ATTR_ATIME_NOW) + { + xinode->atime = attr->st_atime; + log_debug("FUSE_SET_ATTR_ATIME_NOW"); + } + + if (to_set & FUSE_SET_ATTR_MTIME_NOW) + { + xinode->mtime = attr->st_mtime; + log_debug("FUSE_SET_ATTR_MTIME_NOW"); + } + + memset(&st, 0, sizeof(st)); + st.st_ino = xinode->inode; + st.st_mode = xinode->mode; + st.st_size = xinode->size; + st.st_uid = xinode->uid; + st.st_gid = xinode->gid; + st.st_atime = xinode->atime; + st.st_mtime = xinode->mtime; + st.st_ctime = xinode->ctime; + + fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */ +} + +#endif /* end else #ifndef XRDP_FUSE */ diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h index 0ccde368..912a0b22 100644 --- a/sesman/chansrv/chansrv_fuse.h +++ b/sesman/chansrv/chansrv_fuse.h @@ -1,23 +1,67 @@ +/** + * 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. + */ -#if !defined(CHANSRV_FUSE_H) -#define CHANSRV_FUSE_H +#ifndef _CHANSRV_FUSE_H +#define _CHANSRV_FUSE_H -int APP_CC -fuse_clear_clip_dir(void); -int APP_CC -fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex); -int APP_CC -fuse_get_wait_objs(tbus *objs, int *count, int *timeout); -int APP_CC -fuse_check_wait_objs(void); -int APP_CC -fuse_init(void); -int APP_CC -fuse_deinit(void); +/* a file or dir entry in the xrdp file system */ +struct xrdp_inode +{ + tui32 parent_inode; /* Parent serial number. */ + tui32 inode; /* File serial number. */ + tui32 mode; /* File mode. */ + tui32 nlink; /* symbolic link count. */ + tui32 nentries; /* number of entries in a dir */ + tui32 nopen; /* number of simultaneous opens */ + tui32 uid; /* User ID of the file's owner. */ + tui32 gid; /* Group ID of the file's group. */ + size_t size; /* Size of file, in bytes. */ + time_t atime; /* Time of last access. */ + time_t mtime; /* Time of last modification. */ + time_t ctime; /* Time of last status change. */ + char name[256]; /* Dir or filename */ + tui32 device_id; /* for file system redirection */ + char is_synced; /* dir struct has been read from */ + /* remote device, done just once */ + int lindex; /* used in clipboard operations */ + int is_loc_resource; /* this is not a redirected resource */ + int close_in_progress; /* close cmd sent to client */ +}; +typedef struct xrdp_inode XRDP_INODE; // LK_TODO use this instead of using struct xrdp_inode -int APP_CC -fuse_file_contents_size(int stream_id, int file_size); -int APP_CC -fuse_file_contents_range(int stream_id, char *data, int data_bytes); +int xfuse_init(); +int xfuse_deinit(); +int xfuse_check_wait_objs(void); +int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout); +int xfuse_create_share(tui32 share_id, char *dirname); + +int xfuse_clear_clip_dir(void); +int xfuse_file_contents_range(int stream_id, char *data, int data_bytes); +int xfuse_file_contents_size(int stream_id, int file_size); +int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex); + +/* functions that are invoked from devredir */ +void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode); +void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus); +void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId); +void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length); +void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus); +void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus); +void xfuse_devredir_cb_file_close(void *vp); #endif diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index 67afbd49..27c45fff 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -247,7 +247,7 @@ static int g_cliprdr_flags = CB_USE_LONG_FORMAT_NAMES | static int g_formatIds[16]; static int g_num_formatIds = 0; -static int g_file_format_id = 0; +static int g_file_format_id = -1; /*****************************************************************************/ /* this is one way to get the current time from the x server */ @@ -320,7 +320,7 @@ clipboard_init(void) return 0; } - fuse_init(); + xfuse_init(); xcommon_init(); g_incr_max_req_size = XMaxRequestSize(g_display) * 4 - 24; g_memset(&g_clip_c2s, 0, sizeof(g_clip_c2s)); @@ -464,7 +464,7 @@ clipboard_deinit(void) g_wnd = 0; } - fuse_deinit(); + xfuse_deinit(); g_free(g_clip_c2s.data); g_clip_c2s.data = 0; @@ -968,7 +968,7 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status, LLOGLN(10, ("clipboard_process_format_announce %d", clip_msg_len)); clipboard_send_format_ack(); - fuse_clear_clip_dir(); + xfuse_clear_clip_dir(); g_clip_c2s.converted = 0; desc[0] = 0; diff --git a/sesman/chansrv/clipboard_file.c b/sesman/chansrv/clipboard_file.c index 54a7b46a..42b5d4a3 100644 --- a/sesman/chansrv/clipboard_file.c +++ b/sesman/chansrv/clipboard_file.c @@ -53,7 +53,7 @@ extern int g_cliprdr_chan_id; /* in chansrv.c */ extern struct clip_s2c g_clip_s2c; /* in clipboard.c */ extern struct clip_c2s g_clip_c2s; /* in clipboard.c */ -extern char g_fuse_root_path[]; /* in chansrv_fuse.c */ +extern char g_fuse_clipboard_path[]; struct cb_file_info { @@ -454,7 +454,9 @@ clipboard_request_file_data(int stream_id, int lindex, int offset, int size; int rv; - LLOGLN(10, ("clipboard_request_file_data:")); + LLOGLN(10, ("clipboard_request_file_data: stream_id=%d lindex=%d off=%d request_bytes=%d", + stream_id, lindex, offset, request_bytes)); + if (g_file_request_sent_type != 0) { LLOGLN(0, ("clipboard_request_file_data: warning, still waiting " @@ -534,13 +536,13 @@ clipboard_process_file_response(struct stream *s, int clip_msg_status, in_uint32_le(s, file_size); LLOGLN(10, ("clipboard_process_file_response: streamId %d " "file_size %d", streamId, file_size)); - fuse_file_contents_size(streamId, file_size); + xfuse_file_contents_size(streamId, file_size); } else if (g_file_request_sent_type == CB_FILECONTENTS_RANGE) { g_file_request_sent_type = 0; in_uint32_le(s, streamId); - fuse_file_contents_range(streamId, s->p, clip_msg_len - 4); + xfuse_file_contents_range(streamId, s->p, clip_msg_len - 4); } else { @@ -593,8 +595,18 @@ clipboard_c2s_in_files(struct stream *s, char *file_list) struct clip_file_desc *cfd; char *ptr; + if (!s_check_rem(s, 4)) + { + LLOGLN(0, ("clipboard_c2s_in_files: parse error")); + return 1; + } in_uint32_le(s, cItems); - fuse_clear_clip_dir(); + if (cItems > 64 * 1024) /* sanity check */ + { + LLOGLN(0, ("clipboard_c2s_in_files: error cItems %d too big", cItems)); + return 1; + } + xfuse_clear_clip_dir(); LLOGLN(10, ("clipboard_c2s_in_files: cItems %d", cItems)); cfd = (struct clip_file_desc *) g_malloc(sizeof(struct clip_file_desc), 0); @@ -610,13 +622,13 @@ clipboard_c2s_in_files(struct stream *s, char *file_list) "supported [%s]", cfd->cFileName)); continue; } - fuse_add_clip_dir_item(cfd->cFileName, 0, cfd->fileSizeLow, lindex); + xfuse_add_clip_dir_item(cfd->cFileName, 0, cfd->fileSizeLow, lindex); g_strcpy(ptr, "file://"); ptr += 7; - str_len = g_strlen(g_fuse_root_path); - g_strcpy(ptr, g_fuse_root_path); + str_len = g_strlen(g_fuse_clipboard_path); + g_strcpy(ptr, g_fuse_clipboard_path); ptr += str_len; *ptr = '/'; diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index e6407211..08f28a0d 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -1,7 +1,9 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 + * xrdp device redirection - only drive redirection is currently supported + * + * 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. @@ -16,16 +18,133 @@ * limitations under the License. */ +/* + * TODO + * o there is one difference in the protocol initialization + * sequence upon reconnection: if a user is already logged on, + * send a SERVER_USER_LOGGED_ON msg as per section 3.3.5.1.5 + * + * o how to announce / delete a drive after a connection has been + * established? + * + * o need to support multiple drives; + * o for multiple drives, we cannot have global device_id's and file_id's + * and all functions must be reenterant + * o replace printf's with log_xxx + * o mark local funcs with static + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + #include "arch.h" #include "parse.h" #include "os_calls.h" +#include "log.h" +#include "chansrv_fuse.h" +#include "devredir.h" +#include "smartcard.h" + +/* module based logging */ +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 + +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_ERROR +#endif + +#define log_error(_params...) \ +{ \ + g_write("[%10.10u]: DEV_REDIR %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + +#define log_info(_params...) \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} +#define log_debug(_params...) \ +{ \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: DEV_REDIR %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +/* globals */ extern int g_rdpdr_chan_id; /* in chansrv.c */ +int g_is_printer_redir_supported = 0; +int g_is_port_redir_supported = 0; +int g_is_drive_redir_supported = 0; +int g_is_smartcard_redir_supported = 0; +int g_drive_redir_version = 1; +char g_full_name_for_filesystem[1024]; +tui32 g_completion_id = 1; + +tui32 g_clientID; /* unique client ID - announced by client */ +tui32 g_device_id; /* unique device ID - announced by client */ +tui16 g_client_rdp_version; /* returned by client */ +struct stream *g_input_stream = NULL; + +void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length); /*****************************************************************************/ int APP_CC dev_redir_init(void) { + struct stream *s; + int bytes; + int fd; + + union _u + { + tui32 clientID; + char buf[4]; + } u; + + /* get a random number that will act as a unique clientID */ + if ((fd = open("/dev/urandom", O_RDONLY))) + { + read(fd, u.buf, 4); + close(fd); + } + else + { + /* /dev/urandom did not work - use address of struct s */ + tui64 u64 = (tui64) &s; + u.clientID = (tui32) u64; + } + + /* setup stream */ + xstream_new(s, 1024); + + /* initiate drive redirection protocol by sending Server Announce Req */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_SERVER_ANNOUNCE); + xstream_wr_u16_le(s, 0x0001); /* server major ver */ + xstream_wr_u16_le(s, 0x000C); /* server minor ver - pretend 2 b Win 7 */ + xstream_wr_u32_le(s, u.clientID); /* unique ClientID */ + + /* send data to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); return 0; } @@ -36,12 +155,127 @@ dev_redir_deinit(void) return 0; } -/*****************************************************************************/ +/** + * @brief process incoming data + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + int APP_CC dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { - return 0; + struct stream *ls; + tui16 comp_type; + tui16 pktID; + tui16 minor_ver; + int rv = 0; + + /* + * handle packet fragmentation + */ + if ((chan_flags & 3) == 3) + { + /* all data contained in one packet */ + ls = s; + } + else + { + /* is this is the first packet? */ + if (chan_flags & 1) + xstream_new(g_input_stream, total_length); + + xstream_copyin(g_input_stream, s->p, length); + + /* in last packet, chan_flags & 0x02 will be true */ + if ((chan_flags & 2) == 0) + return 0; + + g_input_stream->p = g_input_stream->data; + ls = g_input_stream; + } + + /* read header from incoming data */ + xstream_rd_u16_le(ls, comp_type); + xstream_rd_u16_le(ls, pktID); + + /* for now we only handle core type, not printers */ + if (comp_type != RDPDR_CTYP_CORE) + { + log_error("invalid component type in response; expected 0x%x got 0x%x", + RDPDR_CTYP_CORE, comp_type); + + rv = -1; + goto done; + } + + /* figure out what kind of response we have gotten */ + switch (pktID) + { + case PAKID_CORE_CLIENTID_CONFIRM: + xstream_seek(ls, 2); /* major version, we ignore it */ + xstream_rd_u16_le(ls, minor_ver); + xstream_rd_u32_le(ls, g_clientID); + + g_client_rdp_version = minor_ver; + + switch (minor_ver) + { + case RDP_CLIENT_50: + break; + + case RDP_CLIENT_51: + break; + + case RDP_CLIENT_52: + break; + + case RDP_CLIENT_60_61: + break; + } + // LK_TODO dev_redir_send_server_clientID_confirm(); + break; + + case PAKID_CORE_CLIENT_NAME: + /* client is telling us its computer name; do we even care? */ + + /* let client know loggin was successful */ + dev_redir_send_server_user_logged_on(); + usleep(1000 * 100); + + /* let client know our capabilites */ + dev_redir_send_server_core_cap_req(); + + /* send confirm clientID */ + dev_redir_send_server_clientID_confirm(); + break; + + case PAKID_CORE_CLIENT_CAPABILITY: + dev_redir_proc_client_core_cap_resp(ls); + break; + + case PAKID_CORE_DEVICELIST_ANNOUNCE: + devredir_proc_client_devlist_announce_req(ls); + break; + + case PAKID_CORE_DEVICE_IOCOMPLETION: + dev_redir_proc_device_iocompletion(ls); + break; + + default: + log_error("got unknown response 0x%x", pktID); + break; + } + +done: + + if (g_input_stream) + { + xstream_free(g_input_stream); + g_input_stream = NULL; + } + + return rv; } /*****************************************************************************/ @@ -57,3 +291,1273 @@ dev_redir_check_wait_objs(void) { return 0; } + +/** + * @brief let client know our capabilities + *****************************************************************************/ + +void dev_redir_send_server_core_cap_req() +{ + struct stream *s; + int bytes; + + xstream_new(s, 1024); + + /* setup header */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_SERVER_CAPABILITY); + + xstream_wr_u16_le(s, 5); /* num of caps we are sending */ + xstream_wr_u16_le(s, 0x0000); /* padding */ + + /* setup general capability */ + xstream_wr_u16_le(s, CAP_GENERAL_TYPE); /* CapabilityType */ + xstream_wr_u16_le(s, 44); /* CapabilityLength - len of this */ + /* CAPABILITY_SET in bytes, inc */ + /* the header */ + xstream_wr_u32_le(s, 2); /* Version */ + xstream_wr_u32_le(s, 2); /* O.S type */ + xstream_wr_u32_le(s, 0); /* O.S version */ + xstream_wr_u16_le(s, 1); /* protocol major version */ + xstream_wr_u16_le(s, g_client_rdp_version); /* protocol minor version */ + xstream_wr_u32_le(s, 0xffff); /* I/O code 1 */ + xstream_wr_u32_le(s, 0); /* I/O code 2 */ + xstream_wr_u32_le(s, 7); /* Extended PDU */ + xstream_wr_u32_le(s, 0); /* extra flags 1 */ + xstream_wr_u32_le(s, 0); /* extra flags 2 */ + xstream_wr_u32_le(s, 2); /* special type device cap */ + + /* setup printer capability */ + xstream_wr_u16_le(s, CAP_PRINTER_TYPE); + xstream_wr_u16_le(s, 8); + xstream_wr_u32_le(s, 1); + + /* setup serial port capability */ + xstream_wr_u16_le(s, CAP_PORT_TYPE); + xstream_wr_u16_le(s, 8); + xstream_wr_u32_le(s, 1); + + /* setup file system capability */ + xstream_wr_u16_le(s, CAP_DRIVE_TYPE); /* CapabilityType */ + xstream_wr_u16_le(s, 8); /* CapabilityLength - len of this */ + /* CAPABILITY_SET in bytes, inc */ + /* the header */ + xstream_wr_u32_le(s, 2); /* Version */ + + /* setup smart card capability */ + xstream_wr_u16_le(s, CAP_SMARTCARD_TYPE); + xstream_wr_u16_le(s, 8); + xstream_wr_u32_le(s, 1); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); +} + +void dev_redir_send_server_clientID_confirm() +{ + struct stream *s; + int bytes; + + xstream_new(s, 1024); + + /* setup stream */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_CLIENTID_CONFIRM); + xstream_wr_u16_le(s, 0x0001); + xstream_wr_u16_le(s, g_client_rdp_version); + xstream_wr_u32_le(s, g_clientID); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); +} + +void dev_redir_send_server_user_logged_on() +{ + struct stream *s; + int bytes; + + xstream_new(s, 1024); + + /* setup stream */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_USER_LOGGEDON); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); +} + +void devredir_send_server_device_announce_resp(tui32 device_id) +{ + struct stream *s; + int bytes; + + xstream_new(s, 1024); + + /* setup stream */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY); + xstream_wr_u32_le(s, device_id); + xstream_wr_u32_le(s, 0); /* ResultCode */ + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); +} + +/** + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int dev_redir_send_drive_create_request(tui32 device_id, char *path, + tui32 DesiredAccess, + tui32 CreateOptions, + tui32 CreateDisposition, + tui32 completion_id) +{ + struct stream *s; + int bytes; + int len; + + log_debug("DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", + DesiredAccess, CreateDisposition, CreateOptions); + + /* to store path as unicode */ + len = strlen(path) * 2 + 2; + + xstream_new(s, 1024 + len); + + devredir_insert_DeviceIoRequest(s, + device_id, + 0, + completion_id, + IRP_MJ_CREATE, + 0); + + xstream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */ + xstream_wr_u32_le(s, 0); /* AllocationSize high unused */ + xstream_wr_u32_le(s, 0); /* AllocationSize low unused */ + xstream_wr_u32_le(s, 0); /* FileAttributes */ + xstream_wr_u32_le(s, 3); /* SharedAccess LK_TODO */ + xstream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */ + xstream_wr_u32_le(s, CreateOptions); /* CreateOptions */ + xstream_wr_u32_le(s, len); /* PathLength */ + devredir_cvt_to_unicode(s->p, path); /* path in unicode */ + xstream_seek(s, len); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); + return 0; +} + +/** + * Close a request previously created by dev_redir_send_drive_create_request() + *****************************************************************************/ + +int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunc, + int pad_len) +{ + struct stream *s; + int bytes; + + xstream_new(s, 1024); + + devredir_insert_DeviceIoRequest(s, DeviceId, FileId, CompletionId, + MajorFunction, MinorFunc); + + if (pad_len) + xstream_seek(s, pad_len); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); + log_debug("sent close request; expect CID_FILE_CLOSE"); + return 0; +} + +/** + * @brief ask client to enumerate directory + * + * Server Drive Query Directory Request + * DR_DRIVE_QUERY_DIRECTORY_REQ + * + *****************************************************************************/ +// LK_TODO Path needs to be Unicode +void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, + tui32 InitialQuery, char *Path) +{ + struct stream *s; + int bytes; + char upath[4096]; // LK_TODO need to malloc this + int path_len = 0; + + /* during Initial Query, Path cannot be NULL */ + if (InitialQuery) + { + if (Path == NULL) + return; + + path_len = strlen(Path) * 2 + 2; + devredir_cvt_to_unicode(upath, Path); + } + + xstream_new(s, 1024 + path_len); + + irp->completion_type = CID_DIRECTORY_CONTROL; + devredir_insert_DeviceIoRequest(s, + device_id, + irp->FileId, + irp->CompletionId, + IRP_MJ_DIRECTORY_CONTROL, + IRP_MN_QUERY_DIRECTORY); + +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + xstream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */ +#else + xstream_wr_u32_le(s, FileDirectoryInformation); /* FsInformationClass */ +#endif + xstream_wr_u8(s, InitialQuery); /* InitialQuery */ + + if (!InitialQuery) + { + xstream_wr_u32_le(s, 0); /* PathLength */ + xstream_seek(s, 23); + } + else + { + xstream_wr_u32_le(s, path_len); /* PathLength */ + xstream_seek(s, 23); /* Padding */ + xstream_wr_string(s, upath, path_len); + } + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + + xstream_free(s); +} + +/****************************************************************************** +** process data received from client ** +******************************************************************************/ + +/** + * @brief process client's repsonse to our core_capability_req() msg + * + * @param s stream containing client's response + *****************************************************************************/ +void dev_redir_proc_client_core_cap_resp(struct stream *s) +{ + int i; + tui16 num_caps; + tui16 cap_type; + tui16 cap_len; + tui32 cap_version; + + xstream_rd_u16_le(s, num_caps); + xstream_seek(s, 2); /* padding */ + + for (i = 0; i < num_caps; i++) + { + 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; + xstream_seek(s, cap_len); + break; + } + } +} + +void devredir_proc_client_devlist_announce_req(struct stream *s) +{ + int i; + int j; + tui32 device_count; + tui32 device_type; + tui32 device_data_len; + char preferred_dos_name[9]; + + /* get number of devices being announced */ + xstream_rd_u32_le(s, device_count); + + log_debug("num of devices announced: %d", device_count); + + for (i = 0; i < device_count; i++) + { + xstream_rd_u32_le(s, device_type); + xstream_rd_u32_le(s, g_device_id); + + switch (device_type) + { + case RDPDR_DTYP_FILESYSTEM: + /* get preferred DOS name */ + for (j = 0; j < 8; j++) + { + preferred_dos_name[j] = *s->p++; + } + + /* DOS names that are 8 chars long are not NULL terminated */ + preferred_dos_name[8] = 0; + + /* get device data len */ + xstream_rd_u32_le(s, device_data_len); + if (device_data_len) + { + xstream_rd_string(g_full_name_for_filesystem, s, + device_data_len); + } + + log_debug("device_type=FILE_SYSTEM device_id=0x%x dosname=%s " + "device_data_len=%d full_name=%s", g_device_id, + preferred_dos_name, + device_data_len, g_full_name_for_filesystem); + + devredir_send_server_device_announce_resp(g_device_id); + + /* create share directory in xrdp file system; */ + /* think of this as the mount point for this share */ + xfuse_create_share(g_device_id, preferred_dos_name); + break; + + case RDPDR_DTYP_SMARTCARD: + /* get preferred DOS name */ + for (j = 0; j < 8; j++) + { + preferred_dos_name[j] = *s->p++; + } + + /* DOS names that are 8 chars long are not NULL terminated */ + preferred_dos_name[8] = 0; + + /* for smart cards, device data len always 0 */ + + log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s " + "device_data_len=%d", + g_device_id, preferred_dos_name, device_data_len); + + devredir_send_server_device_announce_resp(g_device_id); + scard_device_announce(g_device_id); + break; + + /* we don't yet support these devices */ + case RDPDR_DTYP_SERIAL: + case RDPDR_DTYP_PARALLEL: + case RDPDR_DTYP_PRINT: + log_debug("unsupported dev: 0x%x", device_type); + break; + } + } +} + +void dev_redir_proc_device_iocompletion(struct stream *s) +{ + FUSE_DATA *fuse_data = NULL; + IRP *irp = NULL; + + tui32 DeviceId; + tui32 CompletionId; + tui32 IoStatus; + tui32 Length; + + xstream_rd_u32_le(s, DeviceId); + xstream_rd_u32_le(s, CompletionId); + xstream_rd_u32_le(s, IoStatus); + + /* LK_TODO need to check for IoStatus */ + + log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId); + + if ((irp = devredir_irp_find(CompletionId)) == NULL) + { + log_error("IRP with completion ID %d not found", CompletionId); + return; + } + + /* if callback has been set, call it */ + if (irp->callback) + { + (*irp->callback)(s, irp, DeviceId, CompletionId, IoStatus); + goto done; + } + + switch (irp->completion_type) + { + case CID_CREATE_DIR_REQ: + log_debug("got CID_CREATE_DIR_REQ"); + if (IoStatus != NT_STATUS_SUCCESS) + { + /* we were trying to create a request to enumerate a dir */ + /* that does not exist; let FUSE know */ + fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data) + { + xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, + IoStatus); + free(fuse_data); + } + devredir_irp_delete(irp); + return; + } + + xstream_rd_u32_le(s, irp->FileId); + log_debug("got CID_CREATE_DIR_REQ IoStatus=0x%x FileId=%d", + IoStatus, irp->FileId); + + dev_redir_send_drive_dir_request(irp, DeviceId, 1, irp->pathname); + break; + + case CID_CREATE_OPEN_REQ: + xstream_rd_u32_le(s, irp->FileId); + log_debug("got CID_CREATE_OPEN_REQ IoStatus=0x%x FileId=%d", + IoStatus, irp->FileId); + fuse_data = devredir_fuse_data_dequeue(irp); + xfuse_devredir_cb_open_file(fuse_data->data_ptr, + DeviceId, irp->FileId); + if (irp->type == S_IFDIR) + devredir_irp_delete(irp); + break; + + case CID_READ: + log_debug("got CID_READ"); + xstream_rd_u32_le(s, Length); + fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data == NULL) + log_error("fuse_data is NULL"); + xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length); + break; + + case CID_WRITE: + log_debug("got CID_WRITE"); + xstream_rd_u32_le(s, Length); + fuse_data = devredir_fuse_data_dequeue(irp); + xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length); + break; + + case CID_CLOSE: + log_debug("got CID_CLOSE"); + log_debug("deleting irp with completion_id=%d comp_type=%d", + irp->CompletionId, irp->completion_type); + devredir_irp_delete(irp); + break; + + case CID_FILE_CLOSE: + log_debug("got CID_FILE_CLOSE"); + fuse_data = devredir_fuse_data_dequeue(irp); + xfuse_devredir_cb_file_close(fuse_data->data_ptr); + devredir_irp_delete(irp); + break; + + case CID_DIRECTORY_CONTROL: + log_debug("got CID_DIRECTORY_CONTROL"); + + dev_redir_proc_query_dir_response(irp, s, DeviceId, + CompletionId, IoStatus); + break; + + case CID_RMDIR_OR_FILE: + log_debug("got CID_RMDIR_OR_FILE"); + xstream_rd_u32_le(s, irp->FileId); + devredir_proc_cid_rmdir_or_file(irp, IoStatus); + return; + break; + + case CID_RMDIR_OR_FILE_RESP: + log_debug("got CID_RMDIR_OR_FILE_RESP"); + devredir_proc_cid_rmdir_or_file_resp(irp, IoStatus); + break; + + case CID_RENAME_FILE: + log_debug("got CID_RENAME_FILE"); + xstream_rd_u32_le(s, irp->FileId); + devredir_proc_cid_rename_file(irp, IoStatus); + return; + break; + + case CID_RENAME_FILE_RESP: + log_debug("got CID_RENAME_FILE_RESP"); + devredir_proc_cid_rename_file_resp(irp, IoStatus); + break; + + default: + log_error("got unknown CompletionID: DeviceId=0x%x " + "CompletionId=0x%x IoStatus=0x%x", + DeviceId, CompletionId, IoStatus); + break; + } + +done: + + if (fuse_data) + { + log_debug("free FUSE_DATA=%p", fuse_data); + free(fuse_data); + } + + log_debug("exiting"); +} + +void dev_redir_proc_query_dir_response(IRP *irp, + struct stream *s_in, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus) +{ + FUSE_DATA *fuse_data = NULL; + XRDP_INODE *xinode = NULL; + + tui32 Length; + tui32 NextEntryOffset; + tui64 CreationTime; + tui64 LastAccessTime; + tui64 LastWriteTime; + tui64 ChangeTime; + tui64 EndOfFile; + tui32 FileAttributes; + tui32 FileNameLength; + tui32 status; + +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + tui32 EaSize; + tui8 ShortNameLength; + tui8 Reserved; +#endif + + char filename[256]; + int i = 0; + + xstream_rd_u32_le(s_in, Length); + + if ((IoStatus == NT_STATUS_UNSUCCESSFUL) || + (IoStatus == STATUS_NO_MORE_FILES)) + { + status = (IoStatus == STATUS_NO_MORE_FILES) ? 0 : IoStatus; + fuse_data = devredir_fuse_data_dequeue(irp); + xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, status); + irp->completion_type = CID_CLOSE; + dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, + PAKID_CORE_DEVICE_IOREQUEST, + DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_CLOSE, 0, 32); + free(fuse_data); + return; + } + + /* TODO check status for errors */ + + /* process FILE_DIRECTORY_INFORMATION structures */ + while (i < Length) + { + log_debug("processing FILE_DIRECTORY_INFORMATION structs"); + + xstream_rd_u32_le(s_in, NextEntryOffset); + xstream_seek(s_in, 4); /* FileIndex */ + xstream_rd_u64_le(s_in, CreationTime); + xstream_rd_u64_le(s_in, LastAccessTime); + xstream_rd_u64_le(s_in, LastWriteTime); + xstream_rd_u64_le(s_in, ChangeTime); + xstream_rd_u64_le(s_in, EndOfFile); + xstream_seek(s_in, 8); /* AllocationSize */ + xstream_rd_u32_le(s_in, FileAttributes); + xstream_rd_u32_le(s_in, FileNameLength); + +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + xstream_rd_u32_le(s_in, EaSize); + xstream_rd_u8(s_in, ShortNameLength); + xstream_rd_u8(s_in, Reserved); + xstream_seek(s_in, 23); /* ShortName in Unicode */ +#endif + devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength); + +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + i += 70 + 23 + FileNameLength; +#else + i += 64 + FileNameLength; +#endif + //log_debug("NextEntryOffset: 0x%x", NextEntryOffset); + //log_debug("CreationTime: 0x%llx", CreationTime); + //log_debug("LastAccessTime: 0x%llx", LastAccessTime); + //log_debug("LastWriteTime: 0x%llx", LastWriteTime); + //log_debug("ChangeTime: 0x%llx", ChangeTime); + //log_debug("EndOfFile: %lld", EndOfFile); + //log_debug("FileAttributes: 0x%x", FileAttributes); +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + //log_debug("ShortNameLength: %d", ShortNameLength); +#endif + //log_debug("FileNameLength: %d", FileNameLength); + log_debug("FileName: %s", filename); + + if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) + { + log_error("system out of memory"); + fuse_data = devredir_fuse_data_peek(irp); + xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, NULL); + return; + } + + strcpy(xinode->name, filename); + xinode->size = (size_t) EndOfFile; + xinode->mode = WINDOWS_TO_LINUX_FILE_PERM(FileAttributes); + xinode->atime = WINDOWS_TO_LINUX_TIME(LastAccessTime); + xinode->mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime); + xinode->ctime = WINDOWS_TO_LINUX_TIME(CreationTime); + + /* add this entry to xrdp file system */ + fuse_data = devredir_fuse_data_peek(irp); + xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, xinode); + } + + dev_redir_send_drive_dir_request(irp, DeviceId, 0, NULL); +} + +/** + * FUSE calls this function whenever it wants us to enumerate a dir + * + * @param fusep opaque data struct that we just pass back to FUSE when done + * @param device_id device_id of the redirected share + * @param path the dir path to enumerate + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path) +{ + tui32 DesiredAccess; + tui32 CreateOptions; + tui32 CreateDisposition; + int rval; + IRP *irp; + + log_debug("fusep=%p", fusep); + + if ((irp = devredir_irp_new()) == NULL) + return -1; + + /* cvt / to windows compatible \ */ + devredir_cvt_slash(path); + + irp->CompletionId = g_completion_id++; + irp->completion_type = CID_CREATE_DIR_REQ; + irp->DeviceId = device_id; + strcpy(irp->pathname, path); + devredir_fuse_data_enqueue(irp, fusep); + + DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; + CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT; + CreateDisposition = CD_FILE_OPEN; + + rval = dev_redir_send_drive_create_request(device_id, path, + DesiredAccess, CreateOptions, + CreateDisposition, + irp->CompletionId); + + log_debug("looking for device_id=%d path=%s", device_id, path); + + /* when we get a respone to dev_redir_send_drive_create_request(), we */ + /* call dev_redir_send_drive_dir_request(), which needs the following */ + /* at the end of the path argument */ + if (dev_redir_string_ends_with(irp->pathname, '\\')) + strcat(irp->pathname, "*"); + else + strcat(irp->pathname, "\\*"); + + return rval; +} + +int dev_redir_file_open(void *fusep, tui32 device_id, char *path, + int mode, int type, char *gen_buf) +{ + tui32 DesiredAccess; + tui32 CreateOptions; + tui32 CreateDisposition; + int rval; + IRP *irp; + + log_debug("device_id=%d path=%s mode=0x%x", device_id, path, mode); + + if ((irp = devredir_irp_new()) == NULL) + return -1; + + if (type & OP_RENAME_FILE) + { + irp->completion_type = CID_RENAME_FILE; + strcpy(irp->gen_buf, gen_buf); + } + else + { + irp->completion_type = CID_CREATE_OPEN_REQ; + } + + irp->CompletionId = g_completion_id++; + irp->DeviceId = device_id; + strcpy(irp->pathname, path); + devredir_fuse_data_enqueue(irp, fusep); + + if (mode & O_CREAT) + { + log_debug("open file in O_CREAT"); + DesiredAccess = 0x0016019f; /* got this value from windows */ + + if (type & S_IFDIR) + { + log_debug("creating dir"); + CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT; + irp->type = S_IFDIR; + } + else + { + log_debug("creating file"); + CreateOptions = 0x44; /* got this value from windows */ + } + + //CreateDisposition = CD_FILE_CREATE; + CreateDisposition = 0x02; /* got this value from windows */ + } + else + { + log_debug("open file in O_RDWR"); +#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; + CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; + CreateDisposition = CD_FILE_OPEN; // WAS 1 +#else + /* got this value from windows; the 0x00000010 was added by LK; */ + /* without this rdesktop opens files in O_RDONLY instead of */ + /* O_RDWR mode */ + DesiredAccess = 0x00120089 | 0x00000010; + CreateOptions = 0x20060; + CreateDisposition = 0x01; +#endif + } + + rval = dev_redir_send_drive_create_request(device_id, path, + DesiredAccess, CreateOptions, + CreateDisposition, + irp->CompletionId); + + return rval; +} + +int devredir_file_close(void *fusep, tui32 device_id, tui32 FileId) +{ + IRP *irp; + + log_debug("entered: fusep=%p device_id=%d FileId=%d", + fusep, device_id, FileId); + +#if 0 + if ((irp = devredir_irp_new()) == NULL) + return -1; + + irp->CompletionId = g_completion_id++; +#else + if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) + { + log_error("no IRP found with FileId = %d", FileId); + return -1; + } +#endif + irp->completion_type = CID_FILE_CLOSE; + irp->DeviceId = device_id; + devredir_fuse_data_enqueue(irp, fusep); + + return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, + PAKID_CORE_DEVICE_IOREQUEST, + device_id, + FileId, + irp->CompletionId, + IRP_MJ_CLOSE, + 0, 32); +} + +/** + * Remove (delete) a directory or file + *****************************************************************************/ + +int devredir_rmdir_or_file(void *fusep, tui32 device_id, char *path, int mode) +{ + tui32 DesiredAccess; + tui32 CreateOptions; + tui32 CreateDisposition; + int rval; + IRP *irp; + + if ((irp = devredir_irp_new()) == NULL) + return -1; + + irp->CompletionId = g_completion_id++; + irp->completion_type = CID_RMDIR_OR_FILE; + irp->DeviceId = device_id; + strcpy(irp->pathname, path); + devredir_fuse_data_enqueue(irp, fusep); + + //DesiredAccess = DA_DELETE | DA_FILE_READ_ATTRIBUTES | DA_SYNCHRONIZE; + DesiredAccess = 0x00100080; /* got this value from windows */ + + //CreateOptions = CO_FILE_DELETE_ON_CLOSE | CO_FILE_DIRECTORY_FILE | + // CO_FILE_SYNCHRONOUS_IO_NONALERT; + CreateOptions = 0x020; /* got this value from windows */ + + //CreateDisposition = CD_FILE_OPEN; // WAS 1 + CreateDisposition = 0x01; /* got this value from windows */ + + rval = dev_redir_send_drive_create_request(device_id, path, + DesiredAccess, CreateOptions, + CreateDisposition, + irp->CompletionId); + + return rval; +} + +/** + * Read data from previously opened file + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int dev_redir_file_read(void *fusep, tui32 DeviceId, tui32 FileId, + tui32 Length, tui64 Offset) +{ + struct stream *s; + IRP *irp; + int bytes; + + xstream_new(s, 1024); + + if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) + { + log_error("no IRP found with FileId = %d", FileId); + xfuse_devredir_cb_read_file(fusep, NULL, 0); + return -1; + } + + irp->completion_type = CID_READ; + devredir_fuse_data_enqueue(irp, fusep); + devredir_insert_DeviceIoRequest(s, + DeviceId, + FileId, + irp->CompletionId, + IRP_MJ_READ, + 0); + + xstream_wr_u32_le(s, Length); + xstream_wr_u64_le(s, Offset); + xstream_seek(s, 20); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + + return 0; +} + +int dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, + const char *buf, tui32 Length, tui64 Offset) +{ + struct stream *s; + IRP *irp; + int bytes; + + log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld", + DeviceId, FileId, Length, Offset); + + xstream_new(s, 1024 + Length); + + if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL) + { + log_error("no IRP found with FileId = %d", FileId); + xfuse_devredir_cb_write_file(fusep, NULL, 0); + return -1; + } + + irp->completion_type = CID_WRITE; + devredir_fuse_data_enqueue(irp, fusep); + devredir_insert_DeviceIoRequest(s, + DeviceId, + FileId, + irp->CompletionId, + IRP_MJ_WRITE, + 0); + + xstream_wr_u32_le(s, Length); + xstream_wr_u64_le(s, Offset); + xstream_seek(s, 20); /* padding */ + + /* now insert real data */ + xstream_copyin(s, buf, Length); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + + return 0; +} + +/****************************************************************************** +** FIFO for FUSE_DATA ** +******************************************************************************/ + +/** + * Return FUSE_DATA at the head of the queue without removing it + * + * @return FUSE_DATA on success, or NULL on failure + *****************************************************************************/ + +void *devredir_fuse_data_peek(IRP *irp) +{ + log_debug("returning %p", irp->fd_head); + return irp->fd_head; +} + +/** + * Return oldest FUSE_DATA from queue + * + * @return FUSE_DATA on success, NULL on failure + *****************************************************************************/ + +void *devredir_fuse_data_dequeue(IRP *irp) +{ + FUSE_DATA *head; + + if ((irp == NULL) || (irp->fd_head == NULL)) + { + log_debug("+++ returning NULL"); + return NULL; + } + + if (irp->fd_head->next == NULL) + { + /* only one element in queue */ + head = irp->fd_head; + irp->fd_head = NULL; + irp->fd_tail = NULL; + log_debug("+++ returning FUSE_DATA=%p containing FUSE_INFO=%p", + head, head->data_ptr); + return head; + } + + /* more than one element in queue */ + head = irp->fd_head; + irp->fd_head = head->next; + log_debug("+++ returning FUSE_DATA=%p containing FUSE_INFO=%p", + head, head->data_ptr); + return head; +} + +/** + * Insert specified FUSE_DATA at the end of our queue + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int devredir_fuse_data_enqueue(IRP *irp, void *vp) +{ + FUSE_DATA *fd; + FUSE_DATA *tail; + + if (irp == NULL) + return -1; + + if ((fd = calloc(1, sizeof(FUSE_DATA))) == NULL) + return -1; + + fd->data_ptr = vp; + fd->next = NULL; + + if (irp->fd_tail == NULL) + { + /* queue is empty, insert at head */ + irp->fd_head = fd; + irp->fd_tail = fd; + log_debug("+++ inserted FUSE_DATA=%p containing FUSE_INFO=%p at head", + fd, vp); + return 0; + } + + /* queue is not empty, insert at tail end */ + tail = irp->fd_tail; + tail->next = fd; + irp->fd_tail = fd; + log_debug("+++ inserted FUSE_DATA=%p containing FUSE_INFO=%p at tail", + fd, vp); + return 0; +} + +/****************************************************************************** +** miscellaneous stuff ** +******************************************************************************/ + +void devredir_insert_DeviceIoRequest(struct stream *s, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunction) +{ + /* setup DR_DEVICE_IOREQUEST header */ + xstream_wr_u16_le(s, RDPDR_CTYP_CORE); + xstream_wr_u16_le(s, PAKID_CORE_DEVICE_IOREQUEST); + xstream_wr_u32_le(s, DeviceId); + xstream_wr_u32_le(s, FileId); + xstream_wr_u32_le(s, CompletionId); + xstream_wr_u32_le(s, MajorFunction); + xstream_wr_u32_le(s, MinorFunction); +} + +/** + * Convert / to windows compatible \ + *****************************************************************************/ + +void devredir_cvt_slash(char *path) +{ + char *cptr = path; + + while (*cptr != 0) + { + if (*cptr == '/') + *cptr = '\\'; + cptr++; + } +} + +void devredir_cvt_to_unicode(char *unicode, char *path) +{ + int len = strlen(path); + int i; + int j = 0; + + for (i = 0; i < len; i++) + { + unicode[j++] = path[i]; + unicode[j++] = 0x00; + } + unicode[j++] = 0x00; + unicode[j++] = 0x00; +} + +void devredir_cvt_from_unicode_len(char *path, char *unicode, int len) +{ + int i; + int j; + + for (i = 0, j = 0; i < len; i += 2) + { + path[j++] = unicode[i]; + } + path[j] = 0; +} + +int dev_redir_string_ends_with(char *string, char c) +{ + int len; + + len = strlen(string); + return (string[len - 1] == c) ? 1 : 0; +} + +void devredir_insert_RDPDR_header(struct stream *s, tui16 Component, + tui16 PacketId) +{ + xstream_wr_u16_le(s, Component); + xstream_wr_u16_le(s, PacketId); +} + +void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus) +{ + struct stream *s; + int bytes; + + if (IoStatus != NT_STATUS_SUCCESS) + { + FUSE_DATA *fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data) + { + xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); + free(fuse_data); + } + devredir_irp_delete(irp); + return; + } + + xstream_new(s, 1024); + + irp->completion_type = CID_RMDIR_OR_FILE_RESP; + devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, + irp->CompletionId, + IRP_MJ_SET_INFORMATION, 0); + + xstream_wr_u32_le(s, FileDispositionInformation); + xstream_wr_u32_le(s, 0); /* length is zero */ + xstream_seek(s, 24); /* padding */ + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + + return; +} + +void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus) +{ + FUSE_DATA *fuse_data; + + fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data) + { + xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus); + free(fuse_data); + } + + if (IoStatus != NT_STATUS_SUCCESS) + { + devredir_irp_delete(irp); + return; + } + + irp->completion_type = CID_CLOSE; + dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, + PAKID_CORE_DEVICE_IOREQUEST, + irp->DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_CLOSE, 0, 32); +} + +void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus) +{ + struct stream *s; + int bytes; + int sblen; /* SetBuffer length */ + int flen; /*FileNameLength */ + + + if (IoStatus != NT_STATUS_SUCCESS) + { + log_debug("rename returned with IoStatus=0x%x", IoStatus); + + FUSE_DATA *fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data) + { + xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); + free(fuse_data); + } + devredir_irp_delete(irp); + return; + } + + xstream_new(s, 1024); + + irp->completion_type = CID_RENAME_FILE_RESP; + devredir_insert_DeviceIoRequest(s, irp->DeviceId, irp->FileId, + irp->CompletionId, + IRP_MJ_SET_INFORMATION, 0); + + flen = strlen(irp->gen_buf) * 2 + 2; + sblen = 6 + flen; + + xstream_wr_u32_le(s, FileRenameInformation); + xstream_wr_u32_le(s, sblen); /* Length */ + xstream_seek(s, 24); /* padding */ + xstream_wr_u8(s, 1); /* ReplaceIfExists */ + xstream_wr_u8(s, 0); /* RootDirectory */ + xstream_wr_u32_le(s, flen); /* FileNameLength */ + + /* filename in unicode */ + devredir_cvt_to_unicode(s->p, irp->gen_buf); + xstream_seek(s, flen); + + /* send to client */ + bytes = xstream_len(s); + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + + return; +} + +void devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus) +{ + FUSE_DATA *fuse_data; + + log_debug("entered"); + + fuse_data = devredir_fuse_data_dequeue(irp); + if (fuse_data) + { + xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus); + free(fuse_data); + } + + if (IoStatus != NT_STATUS_SUCCESS) + { + devredir_irp_delete(irp); + return; + } + + irp->completion_type = CID_CLOSE; + dev_redir_send_drive_close_request(RDPDR_CTYP_CORE, + PAKID_CORE_DEVICE_IOREQUEST, + irp->DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_CLOSE, 0, 32); +} diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 3ec08a51..da49350b 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -1,7 +1,9 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 + * xrdp device redirection - we mainly use it for drive redirection + * + * 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. @@ -16,22 +18,322 @@ * limitations under the License. */ +// LK_TODO dev_redir_xxx should become devredir_xxx + #if !defined(DEVREDIR_H) #define DEVREDIR_H -#include "arch.h" -#include "parse.h" - -int APP_CC -dev_redir_init(void); -int APP_CC -dev_redir_deinit(void); -int APP_CC -dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length, - int total_length); -int APP_CC -dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout); -int APP_CC -dev_redir_check_wait_objs(void); +#include "irp.h" + +#define USE_SHORT_NAMES_IN_DIR_LISTING + +void *devredir_fuse_data_peek(IRP *irp); +void *devredir_fuse_data_dequeue(IRP *irp); +int devredir_fuse_data_enqueue(IRP *irp, void *vp); + +int APP_CC dev_redir_init(void); +int APP_CC dev_redir_deinit(void); + +int APP_CC dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, + int length, int total_length); + +int APP_CC dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout); +int APP_CC dev_redir_check_wait_objs(void); + +void dev_redir_send_server_core_cap_req(); +void dev_redir_send_server_clientID_confirm(); +void dev_redir_send_server_user_logged_on(); +void devredir_send_server_device_announce_resp(tui32 device_id); + +void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, + tui32 InitialQuery, char *Path); + +int dev_redir_send_drive_create_request(tui32 device_id, char *path, + tui32 DesiredAccess, + tui32 CreateOptions, + tui32 CreateDisposition, + tui32 completion_id); + +int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunc, + int pad_len); + +void devredir_proc_client_devlist_announce_req(struct stream *s); +void dev_redir_proc_client_core_cap_resp(struct stream *s); +void dev_redir_proc_device_iocompletion(struct stream *s); + +void dev_redir_proc_query_dir_response(IRP *irp, + struct stream *s, + tui32 DeviceId, + tui32 CompletionId, + tui32 IoStatus); + +/* misc stuff */ +void devredir_insert_DeviceIoRequest(struct stream *s, + tui32 DeviceId, + tui32 FileId, + tui32 CompletionId, + tui32 MajorFunction, + tui32 MinorFunction); + +void devredir_cvt_slash(char *path); +void devredir_cvt_to_unicode(char *unicode, char *path); +void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); +int dev_redir_string_ends_with(char *string, char c); + +void devredir_insert_RDPDR_header(struct stream *s, tui16 Component, + tui16 PacketId); + +void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus); +void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus); +void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus); +void devredir_proc_cid_rename_file_resp(IRP *irp, tui32 IoStatus); + +/* called from FUSE module */ +int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path); + +int dev_redir_file_open(void *fusep, tui32 device_id, char *path, + int mode, int type, char *gen_buf); + +int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id); + +int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId, + tui32 Length, tui64 Offset); + +int send_channel_data(int chan_id, char *data, int size); + +/* + * RDPDR_HEADER definitions + */ + +/* device redirector core component; most of the packets in this protocol */ +/* are sent under this component ID */ +#define RDPDR_CTYP_CORE 0x4472 + +/* printing component. the packets that use this ID are typically about */ +/* printer cache management and identifying XPS printers */ +#define RDPDR_CTYP_PRN 0x5052 + +/* Server Announce Request, as specified in section 2.2.2.2 */ +#define PAKID_CORE_SERVER_ANNOUNCE 0x496E + +/* Client Announce Reply and Server Client ID Confirm, as specified in */ +/* sections 2.2.2.3 and 2.2.2.6. */ +#define PAKID_CORE_CLIENTID_CONFIRM 0x4343 + +/* Client Name Request, as specified in section 2.2.2.4 */ +#define PAKID_CORE_CLIENT_NAME 0x434E + +/* Client Device List Announce Request, as specified in section 2.2.2.9 */ +#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441 + +/* Server Device Announce Response, as specified in section 2.2.2.1 */ +#define PAKID_CORE_DEVICE_REPLY 0x6472 + +/* Device I/O Request, as specified in section 2.2.1.4 */ +#define PAKID_CORE_DEVICE_IOREQUEST 0x4952 + +/* Device I/O Response, as specified in section 2.2.1.5 */ +#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 + +/* Server Core Capability Request, as specified in section 2.2.2.7 */ +#define PAKID_CORE_SERVER_CAPABILITY 0x5350 + +/* Client Core Capability Response, as specified in section 2.2.2.8 */ +#define PAKID_CORE_CLIENT_CAPABILITY 0x4350 + +/* Client Drive Device List Remove, as specified in section 2.2.3.2 */ +#define PAKID_CORE_DEVICELIST_REMOVE 0x444D + +/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */ +#define PAKID_PRN_CACHE_DATA 0x5043 + +/* Server User Logged On, as specified in section 2.2.2.5 */ +#define PAKID_CORE_USER_LOGGEDON 0x554C + +/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */ +#define PAKID_PRN_USING_XPS 0x5543 + +/* + * Capability header definitions + */ + +#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */ +#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */ +#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */ +#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */ +#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */ + +/* client minor versions */ +#define RDP_CLIENT_50 0x0002 +#define RDP_CLIENT_51 0x0005 +#define RDP_CLIENT_52 0x000a +#define RDP_CLIENT_60_61 0x000c + +/* used in device announce list */ +#define RDPDR_DTYP_SERIAL 0x0001 +#define RDPDR_DTYP_PARALLEL 0x0002 +#define RDPDR_DTYP_PRINT 0x0004 +#define RDPDR_DTYP_FILESYSTEM 0x0008 +#define RDPDR_DTYP_SMARTCARD 0x0020 + +/* + * DesiredAccess Mask [MS-SMB2] section 2.2.13.1.1 + */ + +#define DA_FILE_READ_DATA 0x00000001 +#define DA_FILE_WRITE_DATA 0x00000002 +#define DA_FILE_APPEND_DATA 0x00000004 +#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */ +#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */ +#define DA_FILE_EXECUTE 0x00000020 +#define DA_FILE_READ_ATTRIBUTES 0x00000080 +#define DA_FILE_WRITE_ATTRIBUTES 0x00000100 +#define DA_DELETE 0x00010000 +#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */ +#define DA_WRITE_DAC 0x00040000 +#define DA_WRITE_OWNER 0x00080000 +#define DA_SYNCHRONIZE 0x00100000 +#define DA_ACCESS_SYSTEM_SECURITY 0x01000000 +#define DA_MAXIMUM_ALLOWED 0x02000000 +#define DA_GENERIC_ALL 0x10000000 +#define DA_GENERIC_EXECUTE 0x20000000 +#define DA_GENERIC_WRITE 0x40000000 +#define DA_GENERIC_READ 0x80000000 + +/* + * CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request + */ + +enum CREATE_OPTIONS +{ + CO_FILE_DIRECTORY_FILE = 0x00000001, + CO_FILE_WRITE_THROUGH = 0x00000002, + CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020, + CO_FILE_DELETE_ON_CLOSE = 0x00001000 +}; + +/* + * CreateDispositions Mask [MS-SMB2] section 2.2.13 + */ + +#define CD_FILE_SUPERSEDE 0x00000000 +#define CD_FILE_OPEN 0x00000001 +#define CD_FILE_CREATE 0x00000002 +#define CD_FILE_OPEN_IF 0x00000003 +#define CD_FILE_OVERWRITE 0x00000004 +#define CD_FILE_OVERWRITE_IF 0x00000005 + +/* + * Device I/O Request MajorFunction definitions + */ + +#define IRP_MJ_CREATE 0x00000000 +#define IRP_MJ_CLOSE 0x00000002 +#define IRP_MJ_READ 0x00000003 +#define IRP_MJ_WRITE 0x00000004 +#define IRP_MJ_DEVICE_CONTROL 0x0000000E +#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0000000A +#define IRP_MJ_SET_VOLUME_INFORMATION 0x0000000B +#define IRP_MJ_QUERY_INFORMATION 0x00000005 +#define IRP_MJ_SET_INFORMATION 0x00000006 +#define IRP_MJ_DIRECTORY_CONTROL 0x0000000C +#define IRP_MJ_LOCK_CONTROL 0x00000011 + +/* + * Device I/O Request MinorFunction definitions + * + * Only valid when MajorFunction code = IRP_MJ_DIRECTORY_CONTROL + */ + +#define IRP_MN_QUERY_DIRECTORY 0x00000001 +#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x00000002 + +/* + * NTSTATUS codes (used by IoStatus) + */ + +#define NT_STATUS_SUCCESS 0x00000000 +#define NT_STATUS_UNSUCCESSFUL 0xC0000001 + +/* + * File system ioctl codes + * MS-FSCC section 2.3 FSCTL Structures + */ +#define FSCTL_DELETE_OBJECT_ID 0x900a0 + + +/* + * CompletionID types, used in IRPs to indicate I/O operation + */ + +enum COMPLETION_ID +{ + CID_CREATE_DIR_REQ = 1, + CID_DIRECTORY_CONTROL, + CID_CREATE_OPEN_REQ, + CID_READ, + CID_WRITE, + CID_CLOSE, + CID_FILE_CLOSE, + CID_RMDIR_OR_FILE, + CID_RMDIR_OR_FILE_RESP, + CID_RENAME_FILE, + CID_RENAME_FILE_RESP +}; + +enum FS_INFORMATION_CLASS +{ + FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */ + FileEndOfFileInformation = 0x00000014, /* set EOF info */ + FileDispositionInformation = 0x0000000D, /* mark a file for deletion */ + FileRenameInformation = 0x0000000A, /* rename a file */ + FileAllocationInformation = 0x00000013 /* set file allocation size */ +}; + +/* + * constants for drive dir query + */ + +/* Basic information about a file or directory. Basic information is */ +/* defined as the file's name, time stamp, and size, or its attributes */ +#define FileDirectoryInformation 0x00000001 + +/* Full information about a file or directory. Full information is defined */ +/* as all the basic information, plus extended attribute size. */ +#define FileFullDirectoryInformation 0x00000002 + +/* Basic information plus extended attribute size and short name */ +/* about a file or directory. */ +#define FileBothDirectoryInformation 0x00000003 + +/* Detailed information on the names of files in a directory. */ +#define FileNamesInformation 0x0000000C + +/* + * NTSTATUS Codes of interest to us + */ + +/* No more files were found which match the file specification */ +#define STATUS_NO_MORE_FILES 0x80000006 + +/* Windows file attributes */ +#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define W_FILE_ATTRIBUTE_READONLY 0x00000001 + +#define WINDOWS_TO_LINUX_FILE_PERM(_a) \ + (((_a) & W_FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | 0100 : S_IFREG) |\ + (((_a) & W_FILE_ATTRIBUTE_READONLY) ? 0444 : 0644) + +/* winodws time starts on Jan 1, 1601 */ +/* Linux time starts on Jan 1, 1970 */ +#define EPOCH_DIFF 11644473600LL +#define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF; + +#define OP_RENAME_FILE 0x01 #endif diff --git a/sesman/chansrv/irp.c b/sesman/chansrv/irp.c new file mode 100644 index 00000000..5c21fe0f --- /dev/null +++ b/sesman/chansrv/irp.c @@ -0,0 +1,241 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * manage I/O for redirected file system and devices + */ + +#include "parse.h" +#include "os_calls.h" +#include "irp.h" + +/* module based logging */ +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 + +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_ERROR +#endif + +#define log_error(_params...) \ +{ \ + g_write("[%10.10u]: IRP %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + +#define log_info(_params...) \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: IRP %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +#define log_debug(_params...) \ +{ \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: IRP %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +IRP *g_irp_head = NULL; + +/** + * Create a new IRP and append to linked list + * + * @return new IRP or NULL on error + *****************************************************************************/ + +IRP * devredir_irp_new() +{ + IRP *irp; + IRP *irp_last; + + log_debug("entered"); + + /* create new IRP */ + if ((irp = g_malloc(sizeof(IRP), 1)) == NULL) + { + log_error("system out of memory!"); + return NULL; + } + + /* insert at end of linked list */ + if ((irp_last = devredir_irp_get_last()) == NULL) + { + /* list is empty, this is the first entry */ + g_irp_head = irp; + } + else + { + irp_last->next = irp; + irp->prev = irp_last; + } + + log_debug("new IRP=%p", irp); + return irp; +} + +/** + * Delete specified IRP from linked list + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int devredir_irp_delete(IRP *irp) +{ + IRP *lirp = g_irp_head; + + if ((irp == NULL) || (lirp == NULL)) + return -1; + + log_debug("irp=%p completion_id=%d type=%d", + irp, irp->CompletionId, irp->completion_type); + + devredir_irp_dump(); // LK_TODO + + while (lirp) + { + if (lirp == irp) + break; + + lirp = lirp->next; + } + + if (lirp == NULL) + return -1; /* did not find specified irp */ + + if (lirp->prev == NULL) + { + /* we are at head of linked list */ + if (lirp->next == NULL) + { + /* only one element in list */ + g_free(lirp); + g_irp_head = NULL; + devredir_irp_dump(); // LK_TODO + return 0; + } + + lirp->next->prev = NULL; + g_irp_head = lirp->next; + g_free(lirp); + } + else if (lirp->next == NULL) + { + /* we are at tail of linked list */ + lirp->prev->next = NULL; + g_free(lirp); + } + else + { + /* we are in between */ + lirp->prev->next = lirp->next; + lirp->next->prev = lirp->prev; + g_free(lirp); + } + + devredir_irp_dump(); // LK_TODO + + return 0; +} + +/** + * Return IRP containing specified completion_id + *****************************************************************************/ + +IRP *devredir_irp_find(tui32 completion_id) +{ + IRP *irp = g_irp_head; + + while (irp) + { + if (irp->CompletionId == completion_id) + { + log_debug("returning irp=%p", irp); + return irp; + } + + irp = irp->next; + } + + log_debug("returning irp=NULL"); + return NULL; +} + +IRP * devredir_irp_find_by_fileid(tui32 FileId) +{ + IRP *irp = g_irp_head; + + while (irp) + { + if (irp->FileId == FileId) + { + log_debug("returning irp=%p", irp); + return irp; + } + + irp = irp->next; + } + + log_debug("returning irp=NULL"); + return NULL; +} + +/** + * Return last IRP in linked list + *****************************************************************************/ + +IRP * devredir_irp_get_last() +{ + IRP *irp = g_irp_head; + + while (irp) + { + if (irp->next == NULL) + break; + + irp = irp->next; + } + + log_debug("returning irp=%p", irp); + return irp; +} + +void devredir_irp_dump() +{ + IRP *irp = g_irp_head; + + log_debug("------- dumping IRPs --------"); + while (irp) + { + log_debug(" completion_id=%d\tcompletion_type=%d\tFileId=%d", + irp->CompletionId, irp->completion_type, irp->FileId); + + irp = irp->next; + } + log_debug("------- dumping IRPs done ---"); +} diff --git a/sesman/chansrv/irp.h b/sesman/chansrv/irp.h new file mode 100644 index 00000000..ccab5801 --- /dev/null +++ b/sesman/chansrv/irp.h @@ -0,0 +1,64 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * manage I/O for redirected file system and devices + */ + +#ifndef __IRP_H +#define __IRP_H + +typedef struct fuse_data FUSE_DATA; +struct fuse_data +{ + void *data_ptr; + FUSE_DATA *next; +}; + +/* An I/O Resource Packet to track I/O calls */ + +typedef struct irp IRP; + +struct irp +{ + tui32 CompletionId; /* unique number */ + tui32 DeviceId; /* identifies remote device */ + tui32 FileId; /* RDP client provided unique number */ + char completion_type; /* describes I/O type */ + char pathname[256]; /* absolute pathname */ + char gen_buf[1024]; /* for general use */ + int type; + FUSE_DATA *fd_head; /* point to first FUSE opaque object */ + FUSE_DATA *fd_tail; /* point to last FUSE opaque object */ + IRP *next; /* point to next IRP */ + IRP *prev; /* point to previous IRP */ + int scard_index; /* used to smart card to locate dev */ + + void (*callback)(struct stream *s, IRP *irp, tui32 DeviceId, + tui32 CompletionId, tui32 IoStatus); +}; + +IRP * devredir_irp_new(); +int devredir_irp_delete(IRP *irp); +IRP * devredir_irp_find(tui32 completion_id); +IRP * devredir_irp_find_by_fileid(tui32 FileId); +IRP * devredir_irp_get_last(); +void devredir_irp_dump(); + +#endif /* end ifndef __IRP_H */ diff --git a/sesman/chansrv/pulse/Makefile b/sesman/chansrv/pulse/Makefile new file mode 100644 index 00000000..6efbfc16 --- /dev/null +++ b/sesman/chansrv/pulse/Makefile @@ -0,0 +1,18 @@ + + +#PULSE_DIR=/home/jay/temp/pulseaudio-0.9.21 +#PULSE_DIR=/home/jay/pulseaudio-0.9.22 +#PULSE_DIR=/home/jay/pulseaudio-0.9.21 +PULSE_DIR=/home/jay/pulseaudio-2.0 + +OBJS = module-xrdp-sink.o + +CFLAGS = -Wall -O2 -I$(PULSE_DIR) -I$(PULSE_DIR)/src -DHAVE_CONFIG_H -fPIC + +all: module-xrdp-sink.so + +module-xrdp-sink.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -o module-xrdp-sink.so $(OBJS) + +clean: + rm -f $(OBJS) module-xrdp-sink.so diff --git a/sesman/chansrv/pulse/module-xrdp-sink-symdef.h b/sesman/chansrv/pulse/module-xrdp-sink-symdef.h new file mode 100644 index 00000000..14443d31 --- /dev/null +++ b/sesman/chansrv/pulse/module-xrdp-sink-symdef.h @@ -0,0 +1,29 @@ +#ifndef foomodulexrdpsinksymdeffoo +#define foomodulexrdpsinksymdeffoo + +#include <pulsecore/core.h> +#include <pulsecore/module.h> +#include <pulsecore/macro.h> + +#define pa__init module_xrdp_sink_LTX_pa__init +#define pa__done module_xrdp_sink_LTX_pa__done +#define pa__get_author module_xrdp_sink_LTX_pa__get_author +#define pa__get_description module_xrdp_sink_LTX_pa__get_description +#define pa__get_usage module_xrdp_sink_LTX_pa__get_usage +#define pa__get_version module_xrdp_sink_LTX_pa__get_version +#define pa__get_deprecated module_xrdp_sink_LTX_pa__get_deprecated +#define pa__load_once module_xrdp_sink_LTX_pa__load_once +#define pa__get_n_used module_xrdp_sink_LTX_pa__get_n_used + +int pa__init(pa_module*m); +void pa__done(pa_module*m); +int pa__get_n_used(pa_module*m); + +const char* pa__get_author(void); +const char* pa__get_description(void); +const char* pa__get_usage(void); +const char* pa__get_version(void); +const char* pa__get_deprecated(void); +pa_bool_t pa__load_once(void); + +#endif diff --git a/sesman/chansrv/pulse/module-xrdp-sink.c b/sesman/chansrv/pulse/module-xrdp-sink.c new file mode 100644 index 00000000..f6650635 --- /dev/null +++ b/sesman/chansrv/pulse/module-xrdp-sink.c @@ -0,0 +1,581 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * pulse sink + * + * Copyright (C) Jay Sorg 2013 + * + * 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. + */ + +/* + * see pulse-notes.txt +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <errno.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/types.h> + +#include <stdlib.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <sys/ioctl.h> +#include <poll.h> + +#include <pulse/rtclock.h> +#include <pulse/timeval.h> +#include <pulse/xmalloc.h> +//#include <pulse/i18n.h> + +#include <pulsecore/core-error.h> +#include <pulsecore/sink.h> +#include <pulsecore/module.h> +#include <pulsecore/core-util.h> +#include <pulsecore/modargs.h> +#include <pulsecore/log.h> +#include <pulsecore/thread.h> +#include <pulsecore/thread-mq.h> +#include <pulsecore/rtpoll.h> + +#include "module-xrdp-sink-symdef.h" + +PA_MODULE_AUTHOR("Jay Sorg"); +PA_MODULE_DESCRIPTION("xrdp sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE( + "sink_name=<name for the sink> " + "sink_properties=<properties for the sink> " + "format=<sample format> " + "rate=<sample rate>" + "channels=<number of channels> " + "channel_map=<channel map>"); + +#define DEFAULT_SINK_NAME "xrdp" +#define BLOCK_USEC 30000 +//#define BLOCK_USEC (PA_USEC_PER_SEC * 2) +#define CHANSRV_PORT_STR "/tmp/.xrdp/xrdp_chansrv_audio_socket_%d" + +struct userdata { + pa_core *core; + pa_module *module; + pa_sink *sink; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + + pa_usec_t block_usec; + pa_usec_t timestamp; + pa_usec_t failed_connect_time; + pa_usec_t last_send_time; + + int fd; /* unix domain socket connection to xrdp chansrv */ + int display_num; + int skip_bytes; + int got_max_latency; + +}; + +static const char* const valid_modargs[] = { + "sink_name", + "sink_properties", + "format", + "rate", + "channels", + "channel_map", + NULL +}; + +static int close_send(struct userdata *u); + +static int sink_process_msg(pa_msgobject *o, int code, void *data, + int64_t offset, pa_memchunk *chunk) { + + struct userdata *u = PA_SINK(o)->userdata; + pa_usec_t now; + long lat; + + pa_log_debug("sink_process_msg: code %d", code); + + switch (code) { + + case PA_SINK_MESSAGE_SET_VOLUME: /* 3 */ + break; + + case PA_SINK_MESSAGE_SET_MUTE: /* 6 */ + break; + + case PA_SINK_MESSAGE_GET_LATENCY: /* 7 */ + now = pa_rtclock_now(); + lat = u->timestamp > now ? u->timestamp - now : 0ULL; + pa_log_debug("sink_process_msg: lat %ld", lat); + *((pa_usec_t*) data) = lat; + return 0; + + case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: /* 8 */ + break; + + case PA_SINK_MESSAGE_SET_STATE: /* 9 */ + if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) /* 0 */ { + pa_log("sink_process_msg: running"); + + u->timestamp = pa_rtclock_now(); + } else { + pa_log("sink_process_msg: not running"); + close_send(u); + } + break; + + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +static void sink_update_requested_latency_cb(pa_sink *s) { + struct userdata *u; + size_t nbytes; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + u->block_usec = BLOCK_USEC; + //u->block_usec = pa_sink_get_requested_latency_within_thread(s); + pa_log("1 block_usec %d", u->block_usec); + + u->got_max_latency = 0; + if (u->block_usec == (pa_usec_t) -1) { + u->block_usec = s->thread_info.max_latency; + pa_log("2 block_usec %d", u->block_usec); + u->got_max_latency = 1; + } + + nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec); + pa_sink_set_max_rewind_within_thread(s, nbytes); + pa_sink_set_max_request_within_thread(s, nbytes); +} + +static void process_rewind(struct userdata *u, pa_usec_t now) { + size_t rewind_nbytes, in_buffer; + pa_usec_t delay; + + pa_assert(u); + + /* Figure out how much we shall rewind and reset the counter */ + rewind_nbytes = u->sink->thread_info.rewind_nbytes; + u->sink->thread_info.rewind_nbytes = 0; + + pa_assert(rewind_nbytes > 0); + pa_log_debug("Requested to rewind %lu bytes.", + (unsigned long) rewind_nbytes); + + if (u->timestamp <= now) + goto do_nothing; + + delay = u->timestamp - now; + in_buffer = pa_usec_to_bytes(delay, &u->sink->sample_spec); + + if (in_buffer <= 0) + goto do_nothing; + + if (rewind_nbytes > in_buffer) + rewind_nbytes = in_buffer; + + pa_sink_process_rewind(u->sink, rewind_nbytes); + u->timestamp -= pa_bytes_to_usec(rewind_nbytes, &u->sink->sample_spec); + u->skip_bytes += rewind_nbytes; + + pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes); + return; + +do_nothing: + + pa_sink_process_rewind(u->sink, 0); +} + +struct header { + int code; + int bytes; +}; + +static int get_display_num_from_display(char *display_text) { + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + int display_num; + char host[256]; + char disp[256]; + char scre[256]; + + if (display_text == NULL) { + return 0; + } + 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; + display_num = atoi(disp); + return display_num; +} + +static int data_send(struct userdata *u, pa_memchunk *chunk) { + char *data; + int bytes; + int sent; + int fd; + struct header h; + struct sockaddr_un s; + + if (u->fd == 0) { + if (u->failed_connect_time != 0) { + if (pa_rtclock_now() - u->failed_connect_time < 1000000) { + return 0; + } + } + fd = socket(PF_LOCAL, SOCK_STREAM, 0); + memset(&s, 0, sizeof(s)); + s.sun_family = AF_UNIX; + bytes = sizeof(s.sun_path) - 1; + snprintf(s.sun_path, bytes, CHANSRV_PORT_STR, u->display_num); + pa_log_debug("trying to conenct to %s", s.sun_path); + if (connect(fd, (struct sockaddr *)&s, + sizeof(struct sockaddr_un)) != 0) { + u->failed_connect_time = pa_rtclock_now(); + pa_log_debug("Connected failed"); + close(fd); + return 0; + } + u->failed_connect_time = 0; + pa_log("Connected ok fd %d", fd); + u->fd = fd; + } + + bytes = chunk->length; + pa_log_debug("bytes %d", bytes); + + /* from rewind */ + if (u->skip_bytes > 0) { + if (bytes > u->skip_bytes) { + bytes -= u->skip_bytes; + u->skip_bytes = 0; + } else { + u->skip_bytes -= bytes; + return bytes; + } + } + + h.code = 0; + h.bytes = bytes + 8; + if (send(u->fd, &h, 8, 0) != 8) { + pa_log("data_send: send failed"); + close(u->fd); + u->fd = 0; + return 0; + } else { + pa_log_debug("data_send: sent header ok bytes %d", bytes); + } + + data = (char*)pa_memblock_acquire(chunk->memblock); + data += chunk->index; + sent = send(u->fd, data, bytes, 0); + pa_memblock_release(chunk->memblock); + + if (sent != bytes) { + pa_log("data_send: send failed sent %d bytes %d", sent, bytes); + close(u->fd); + u->fd = 0; + return 0; + } + + return sent; +} + +static int close_send(struct userdata *u) { + struct header h; + + pa_log("close_send:"); + if (u->fd == 0) { + return 0; + } + h.code = 1; + h.bytes = 8; + if (send(u->fd, &h, 8, 0) != 8) { + pa_log("close_send: send failed"); + close(u->fd); + u->fd = 0; + return 0; + } else { + pa_log_debug("close_send: sent header ok"); + } + return 8; +} + +static void process_render(struct userdata *u, pa_usec_t now) { + pa_memchunk chunk; + int request_bytes; + + pa_assert(u); + if (u->got_max_latency) { + return; + } + pa_log_debug("process_render: u->block_usec %d", u->block_usec); + while (u->timestamp < now + u->block_usec) { + request_bytes = u->sink->thread_info.max_request; + request_bytes = MIN(request_bytes, 16 * 1024); + pa_sink_render(u->sink, request_bytes, &chunk); + data_send(u, &chunk); + pa_memblock_unref(chunk.memblock); + u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec); + } +} + +static void thread_func(void *userdata) { + + struct userdata *u = userdata; + int ret; + pa_usec_t now; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + pa_thread_mq_install(&u->thread_mq); + + u->timestamp = pa_rtclock_now(); + + for (;;) { + + if (u->sink->thread_info.state == PA_SINK_RUNNING) { + + now = pa_rtclock_now(); + + if (u->sink->thread_info.rewind_requested) { + if (u->sink->thread_info.rewind_nbytes > 0) { + process_rewind(u, now); + } else { + pa_sink_process_rewind(u->sink, 0); + } + } + + if (u->timestamp <= now) { + pa_log_debug("thread_func: calling process_render"); + process_render(u, now); + } + + pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp); + + } else { + pa_rtpoll_set_timer_disabled(u->rtpoll); + } + + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) { + goto fail; + } + + if (ret == 0) { + goto finish; + } + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), + PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, + NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_channel_map map; + pa_modargs *ma = NULL; + pa_sink_new_data data; + size_t nbytes; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + ss = m->core->default_sample_spec; + map = m->core->default_channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, + PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log("Invalid sample format specification or channel map"); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->rtpoll = pa_rtpoll_new(); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); + + pa_sink_new_data_init(&data); + data.driver = __FILE__; + data.module = m; + pa_sink_new_data_set_name(&data, + pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); + pa_sink_new_data_set_sample_spec(&data, &ss); + pa_sink_new_data_set_channel_map(&data, &map); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "xrdp sink"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); + + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, + PA_UPDATE_REPLACE) < 0) { + pa_log("Invalid properties"); + pa_sink_new_data_done(&data); + goto fail; + } + + u->sink = pa_sink_new(m->core, &data, + PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY); + pa_sink_new_data_done(&data); + + if (!u->sink) { + pa_log("Failed to create sink object."); + goto fail; + } + + u->sink->parent.process_msg = sink_process_msg; + u->sink->update_requested_latency = sink_update_requested_latency_cb; + u->sink->userdata = u; + + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + + u->block_usec = BLOCK_USEC; + pa_log("3 block_usec %d", u->block_usec); + nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec); + pa_sink_set_max_rewind(u->sink, nbytes); + pa_sink_set_max_request(u->sink, nbytes); + + u->display_num = get_display_num_from_display(getenv("DISPLAY")); + +#if defined(PA_CHECK_VERSION) +#if PA_CHECK_VERSION(0, 9, 22) + if (!(u->thread = pa_thread_new("xrdp-sink", thread_func, u))) { +#else + if (!(u->thread = pa_thread_new(thread_func, u))) { +#endif +#else + if (!(u->thread = pa_thread_new(thread_func, u))) { +#endif + pa_log("Failed to create thread."); + goto fail; + } + + pa_sink_put(u->sink); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) { + pa_modargs_free(ma); + } + + pa__done(m); + + return -1; +} + +int pa__get_n_used(pa_module *m) { + struct userdata *u; + + pa_assert(m); + pa_assert_se(u = m->userdata); + + return pa_sink_linked_by(u->sink); +} + +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) { + return; + } + + if (u->sink) { + pa_sink_unlink(u->sink); + } + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, + NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) { + pa_sink_unref(u->sink); + } + + if (u->rtpoll) { + pa_rtpoll_free(u->rtpoll); + } + + pa_xfree(u); +} diff --git a/sesman/chansrv/pulse/pulse-notes.txt b/sesman/chansrv/pulse/pulse-notes.txt new file mode 100644 index 00000000..b5d51572 --- /dev/null +++ b/sesman/chansrv/pulse/pulse-notes.txt @@ -0,0 +1,72 @@ + +Pulse audio notes. + +to see what version of PA is on your machine +pulseaudio --version + +IMA ADPCM + +To build xrdp pulse sink, +get the pulse source that most closely matches your version on +your machine. Get the source from +http://freedesktop.org/software/pulseaudio/releases/ +run ./configure after extracting. I don't think you need to build it. +edit Makefile to point to your pulse source directory. + + + +PA always respawning + + To stop its respawning habit, open /etc/pulse/client.conf, change + autospawn = yes to autospawn = no, and set daemon-binary to /bin/true. + Make sure these lines are uncommented, like this: + +autospawn = no +daemon-binary = /bin/true + +xfreerdp -a 24 -z --plugin rdpsnd --data alsa:hw:0,0 -- 127.0.0.1 + + +to get ./configure on pulse source to run +apt-get install libsndfile1-dev +apt-get install libspeex-dev +apt-get install libspeexdsp-dev + +alsamixer +apt-get install alsa-utils + + +/etc/asound.conf +--------------------------------- +pcm.pulse { + type pulse +} + +ctl.pulse { + type pulse +} + +pcm.!default { + type pulse +} + +ctl.!default { + type pulse +} +--------------------------------- + + +/etc/pulse/default.pa +--------------------------------- +.nofail +.fail +load-module module-augment-properties +#load-module module-alsa-sink device=hw:0 +#load-module module-alsa-source device=hw:0 +#load-module module-pipe-sink +#load-module module-pipe-source +#load-module module-null-sink +load-module module-xrdp-sink +load-module module-native-protocol-unix +#load-module module-udev-detect tsched=0 +--------------------------------- diff --git a/sesman/chansrv/smartcard.c b/sesman/chansrv/smartcard.c new file mode 100644 index 00000000..3fdb6723 --- /dev/null +++ b/sesman/chansrv/smartcard.c @@ -0,0 +1,528 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * smartcard redirection support + */ + +#include "os_calls.h" +#include "smartcard.h" +#include "log.h" +#include "irp.h" +#include "devredir.h" + +/* + * TODO + * + * o need to query client for build number and determine whether we should use + * SCREDIR_VERSION_XP or SCREDIR_VERSION_LONGHORN + * + * o need to call scard_release_resources() + * + * o why is win 7 sending SCARD_IOCTL_ACCESS_STARTED_EVENT first + * 0000 00 01 00 00 04 00 00 00 e0 00 09 00 00 00 00 00 ................ + * 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + * 0020 28 b7 9d 02 + */ + +/* + * Notes: + * + * XP and Server 2003 use version SCREDIR_VERSION_XP functions 5 - 58 + * Vista and Server 2008 use version SCREDIR_VERSION_LONGHORN functions 5 - 64 + * if TS Client's build number is >= 4,034 use SCREDIR_VERSION_LONGHORN + */ + +/* module based logging */ +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 + +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_DEBUG +#endif + +#define log_error(_params...) \ +{ \ + g_write("[%10.10u]: SMART_CARD %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + +#define log_info(_params...) \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: SMART_CARD %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +#define log_debug(_params...) \ +{ \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: SMART_CARD %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +/* [MS-RDPESC] 3.1.4 */ +#define SCARD_IOCTL_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */ +#define SCARD_IOCTL_RELEASE_CONTEXT 0x00090018 /* ReleaseContext */ +#define SCARD_IOCTL_IS_VALID_CONTEXT 0x0009001C /* IsValidContext */ +#define SCARD_IOCTL_LIST_READER_GROUPS 0x00090020 /* ListReaderGroups */ +#define SCARD_IOCTL_LIST_READERS_A 0x00090028 /* ListReaders ASCII */ +#define SCARD_IOCTL_LIST_READERS_W 0x0009002C /* ListReaders Wide */ +#define SCARD_IOCTL_INTRODUCE_READER_GROUP 0x00090050 /* IntroduceReaderGroup */ +#define SCARD_IOCTL_FORGET_READER_GROUP 0x00090058 /* ForgetReader */ +#define SCARD_IOCTL_INTRODUCE_READER 0x00090060 /* IntroduceReader */ +#define SCARD_IOCTL_FORGET_READER 0x00090068 /* IntroduceReader */ +#define SCARD_IOCTL_ADD_READER_TO_GROUP 0x00090070 /* AddReaderToGroup */ +#define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */ +#define SCARD_IOCTL_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */ +#define SCARD_IOCTL_CANCEL 0x000900A8 /* Cancel */ +#define SCARD_IOCTL_CONNECT 0x000900AC /* ConnectA */ +#define SCARD_IOCTL_RECONNECT 0x000900B4 /* Reconnect */ +#define SCARD_IOCTL_DISCONNECT 0x000900B8 /* Disconnect */ +#define SCARD_IOCTL_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */ +#define SCARD_IOCTL_END_TRANSACTION 0x000900C0 /* EndTransaction */ +#define SCARD_IOCTL_STATE 0x000900C4 /* State */ +#define SCARD_IOCTL_STATUS 0x000900C8 /* StatusA */ +#define SCARD_IOCTL_TRANSMIT 0x000900D0 /* Transmit */ +#define SCARD_IOCTL_CONTROL 0x000900D4 /* Control */ +#define SCARD_IOCTL_GETATTRIB 0x000900D8 /* GetAttrib */ +#define SCARD_IOCTL_SETATTRIB 0x000900DC /* SetAttrib */ +#define SCARD_IOCTL_ACCESS_STARTED_EVENT 0x000900E0 /* SCardAccessStartedEvent */ +#define SCARD_IOCTL_LOCATE_CARDS_BY_ATR 0x000900E8 /* LocateCardsByATR */ + +/* scope used in EstablishContextCall */ +#define SCARD_SCOPE_USER 0x00000000 +#define SCARD_SCOPE_TERMINAL 0x00000001 +#define SCARD_SCOPE_SYSTEM 0x00000002 + +#define MAX_SMARTCARDS 16 + +/* stores info about a smart card */ +typedef struct smartcard +{ + tui32 DeviceId; + char Context[16]; /* opaque context; save as passed to us */ + int Context_len; /* Context len in bytes */ +} SMARTCARD; + +SMARTCARD *smartcards[MAX_SMARTCARDS]; +int g_smartcards_inited = 0; + +extern tui32 g_completion_id; +extern int g_rdpdr_chan_id; /* in chansrv.c */ + +/* forward declarations specific to this file */ +static void scard_send_EstablishContext(IRP *irp); +static void scard_send_ListReaders(IRP *irp, int wide); +static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl); +static int scard_add_new_device(tui32 device_id); +static int scard_get_free_slot(); +static void scard_release_resources(); + +/****************************************************************************** +** non static functions ** +******************************************************************************/ + +void scard_device_announce(tui32 device_id) +{ + IRP *irp; + + log_debug("entered: device_id=%d", device_id); + + if (!g_smartcards_inited) + { + g_memset(&smartcards, 0, sizeof(smartcards)); + g_smartcards_inited = 1; + } + + if ((irp = devredir_irp_new()) == NULL) + { + log_error("system out of memory"); + return; + } + + irp->scard_index = scard_add_new_device(device_id); + if (irp->scard_index < 0) + { + log_debug("NOT adding smartcard with DeviceId=%d to list", device_id); + devredir_irp_delete(irp); + return; + } + + log_debug("added smartcard with DeviceId=%d to list", device_id); + + irp->CompletionId = g_completion_id++; + irp->DeviceId = device_id; + irp->callback = scard_handle_EstablishContext_Return; + + scard_send_EstablishContext(irp); + log_debug("leaving"); +} + +/****************************************************************************** +** callbacks into this module ** +******************************************************************************/ + +void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + int tmp; + SMARTCARD *sc; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to establish context - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + sc = smartcards[irp->scard_index]; + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + /* LK_TODO */ + g_hexdump(s->p, len); + + xstream_rd_u32_le(s, tmp); /* should be len 8, LE, V1 */ + xstream_rd_u32_le(s, tmp); /* marshalling flag */ + xstream_rd_u32_le(s, tmp); /* ?? */ + xstream_rd_u32_le(s, tmp); /* ?? */ + xstream_rd_u32_le(s, tmp); /* ?? */ + xstream_rd_u32_le(s, tmp); /* ?? */ + xstream_rd_u32_le(s, tmp); /* ?? */ + xstream_rd_u32_le(s, len); /* len of context in bytes */ + sc->Context_len = len; + xstream_copyout(sc->Context, s, len); + + if (LOG_LEVEL == LOG_DEBUG) + { + log_debug("dumping context (%d bytes)", sc->Context_len); + g_hexdump(sc->Context, sc->Context_len); + } + + irp->callback = scard_handle_ListReaders_Return; + scard_send_ListReaders(irp, 1); + + /* LK_TODO need to delete IRP */ + log_debug("leaving"); +} + +void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus) +{ + tui32 len; + + log_debug("entered"); + + /* sanity check */ + if ((DeviceId != irp->DeviceId) || (CompletionId != irp->CompletionId)) + { + log_error("DeviceId/CompletionId do not match those in IRP"); + return; + } + + if (IoStatus != 0) + { + log_error("failed to list readers - device not usable"); + /* LK_TODO delete irp and smartcard entry */ + return; + } + + /* get OutputBufferLen */ + xstream_rd_u32_le(s, len); + + /* LK_TODO */ + log_debug("dumping %d bytes", len); + g_hexdump(s->p, len); + + log_debug("leaving"); +} + +/****************************************************************************** +** static functions local to this file ** +******************************************************************************/ + +/** + * + *****************************************************************************/ + +static void scard_send_EstablishContext(IRP *irp) +{ + struct stream *s; + int bytes; + + if ((s = scard_make_new_ioctl(irp, SCARD_IOCTL_ESTABLISH_CONTEXT)) == NULL) + return; + + xstream_wr_u32_le(s, 0x08); /* len */ + xstream_wr_u32_le(s, 0); /* unused */ + xstream_wr_u32_le(s, SCARD_SCOPE_SYSTEM); /* Ioctl specific data */ + xstream_wr_u32_le(s, 0); /* don't know what this is, */ + /* but Win7 is sending it */ + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); +} + +/** + * + *****************************************************************************/ + +static void scard_send_ListReaders(IRP *irp, int wide) +{ + /* see [MS-RDPESC] 2.2.2.4 */ + + SMARTCARD *sc; + struct stream *s; + int bytes; + tui32 ioctl; + + if ((sc = smartcards[irp->scard_index]) == NULL) + { + log_error("smartcards[%d] is NULL", irp->scard_index); + return; + } + + ioctl = (wide > 0) ? SCARD_IOCTL_LIST_READERS_W : + SCARD_IOCTL_LIST_READERS_A; + + if ((s = scard_make_new_ioctl(irp, ioctl)) == NULL) + return; + + xstream_wr_u32_le(s, 72); /* number of bytes to follow */ + xstream_seek(s, 0x1c); /* freerdp does not use this */ + + /* insert context */ + xstream_wr_u32_le(s, sc->Context_len); + xstream_copyin(s, sc->Context, sc->Context_len); + + xstream_wr_u32_le(s, 36); /* length of mszGroups */ + xstream_wr_u16_le(s, 0x0053); + xstream_wr_u16_le(s, 0x0043); + xstream_wr_u16_le(s, 0x0061); + xstream_wr_u16_le(s, 0x0072); + xstream_wr_u16_le(s, 0x0064); + xstream_wr_u16_le(s, 0x0024); + xstream_wr_u16_le(s, 0x0041); + xstream_wr_u16_le(s, 0x006c); + xstream_wr_u16_le(s, 0x006c); + xstream_wr_u16_le(s, 0x0052); + xstream_wr_u16_le(s, 0x0065); + xstream_wr_u16_le(s, 0x0061); + xstream_wr_u16_le(s, 0x0064); + xstream_wr_u16_le(s, 0x0065); + xstream_wr_u16_le(s, 0x0072); + xstream_wr_u16_le(s, 0x0073); + + xstream_wr_u32_le(s, 0x00); + + /* get stream len */ + bytes = xstream_len(s); + + /* InputBufferLength is number of bytes AFTER 20 byte padding */ + *(s->data + 28) = bytes - 56; + + /* send to client */ + send_channel_data(g_rdpdr_chan_id, s->data, bytes); + xstream_free(s); + + /* + scard_device_control: dumping 120 bytes of data + 0000 00 08 00 00 58 00 00 00 2c 00 09 00 00 00 00 00 ....X...,....... + 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... + 0030 04 00 00 00 00 00 02 00 24 00 00 00 04 00 02 00 ........$....... + 0040 00 00 00 00 ff ff ff ff 04 00 00 00 84 db 03 01 ................ + 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. + 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. + 0070 72 00 73 00 00 00 00 00 r.s..... + scard_device_control: output_len=2048 input_len=88 ioctl_code=0x9002c + */ + + /* + scard_device_control: dumping 120 bytes of data + 0000 00 08 00 00 80 00 00 00 14 00 09 00 00 00 00 00 ................ + 0010 2e 2e 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ + 0020 01 10 08 00 cc cc cc cc 48 00 00 00 00 00 00 00 ........H....... + 0030 02 00 00 00 00 00 00 00 72 64 00 00 00 00 00 00 ........rd...... + 0040 81 27 00 00 00 00 00 00 04 00 00 00 84 b3 03 01 .'.............. + 0050 24 00 00 00 53 00 43 00 61 00 72 00 64 00 24 00 $...S.C.a.r.d.$. + 0060 41 00 6c 00 6c 00 52 00 65 00 61 00 64 00 65 00 A.l.l.R.e.a.d.e. + 0070 72 00 73 00 00 00 00 00 r.s..... + scard_device_control: output_len=2048 input_len=128 ioctl_code=0x90014 + */ +} + +/** + * Crate a new stream and insert specified IOCTL + * + * @param irp information about the I/O + * @param ioctl the IOCTL code + * + * @return stream with IOCTL inserted in it, NULL on error + *****************************************************************************/ + +static struct stream *scard_make_new_ioctl(IRP *irp, tui32 ioctl) +{ + /* + * format of device control request + * + * DeviceIoRequest + * u16 RDPDR_CTYP_CORE + * u16 PAKID_CORE_DEVICE_IOREQUEST + * u32 DeviceId + * u32 FileId + * u32 CompletionId + * u32 MajorFunction + * u32 MinorFunction + * + * u32 OutputBufferLength SHOULD be 2048 + * u32 InputBufferLength + * u32 IoControlCode + * 20 bytes padding + * xx bytes InputBuffer (variable) + */ + + struct stream *s; + + xstream_new(s, 1024 * 3); + if (s == NULL) + { + log_error("system out of memory"); + return s; + } + + devredir_insert_DeviceIoRequest(s, + irp->DeviceId, + irp->FileId, + irp->CompletionId, + IRP_MJ_DEVICE_CONTROL, + 0); + + xstream_wr_u32_le(s, 2048); /* OutputBufferLength */ + xstream_wr_u32_le(s, 0); /* InputBufferLength - insert later */ + xstream_wr_u32_le(s, ioctl); /* Ioctl Code */ + xstream_seek(s, 20); /* padding */ + + /* [MS-RPCE] 2.2.6.1 */ + xstream_wr_u32_le(s, 0x00081001); /* len 8, LE, v1 */ + xstream_wr_u32_le(s, 0xcccccccc); /* filler */ + + return s; +} + +/** + * Create a new smart card device entry and insert it into smartcards[] + * + * @param device_id DeviceId of new card + * + * @return index into smartcards[] on success, -1 on failure + *****************************************************************************/ + +static int scard_add_new_device(tui32 device_id) +{ + int index; + SMARTCARD *sc; + + if ((index = scard_get_free_slot()) < 0) + return -1; + + if ((sc = g_malloc(sizeof(SMARTCARD), 1)) == NULL) + { + log_error("system out of memory"); + return -1; + } + + sc->DeviceId = device_id; + smartcards[index] = sc; + + return index; +} + +/** + * Find first unused entry in smartcards + * + * @return index of first unused entry in smartcards or -1 if smartcards is full + *****************************************************************************/ + +static int scard_get_free_slot() +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] == NULL) + { + log_debug("found free slot at index %d", i); + return i; + } + } + + log_error("too many smart card devices; rejecting this one"); + return -1; +} + +/** + * Release resources prior to shutting down + *****************************************************************************/ + +static void scard_release_resources() +{ + int i; + + for (i = 0; i < MAX_SMARTCARDS; i++) + { + if (smartcards[i] != NULL) + { + g_free(smartcards[i]); + smartcards[i] = NULL; + } + } +} + +/** + * + *****************************************************************************/ diff --git a/sesman/chansrv/smartcard.h b/sesman/chansrv/smartcard.h new file mode 100644 index 00000000..88f31369 --- /dev/null +++ b/sesman/chansrv/smartcard.h @@ -0,0 +1,42 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * smartcard redirection support + */ + +#ifndef _SMARTCARD_C +#define _SMARTCARD_C + +#include "parse.h" +#include "irp.h" + +/* forward declarations */ +void scard_device_announce(tui32 device_id); + +/* callbacks into this module */ +void scard_handle_EstablishContext_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +void scard_handle_ListReaders_Return(struct stream *s, IRP *irp, + tui32 DeviceId, tui32 CompletionId, + tui32 IoStatus); + +#endif /* end #ifndef _SMARTCARD_C */ diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index e8b801c6..55f6f88d 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,43 +18,100 @@ #include "sound.h" #include "thread_calls.h" +#include "defines.h" extern int g_rdpsnd_chan_id; /* in chansrv.c */ extern int g_display_num; /* in chansrv.c */ -static struct trans *g_audio_l_trans = 0; // listener -static struct trans *g_audio_c_trans = 0; // connection +static struct trans *g_audio_l_trans = 0; /* listener */ +static struct trans *g_audio_c_trans = 0; /* connection */ static int g_training_sent_time = 0; static int g_cBlockNo = 0; +#define BBUF_SIZE (1024 * 8) +char g_buffer[BBUF_SIZE]; +int g_buf_index = 0; +int g_sent_time[256]; + #if defined(XRDP_SIMPLESOUND) static void *DEFAULT_CC read_raw_audio_data(void *arg); #endif +#define CHANSRV_PORT_STR "/tmp/.xrdp/xrdp_chansrv_audio_socket_%d" + +struct xr_wave_format_ex +{ + int wFormatTag; + int nChannels; + int nSamplesPerSec; + int nAvgBytesPerSec; + int nBlockAlign; + int wBitsPerSample; + int cbSize; + char *data; +}; + +static char g_pmc_22050_data[] = { 0 }; +static struct xr_wave_format_ex g_pmc_22050 = +{ + 1, /* wFormatTag - WAVE_FORMAT_PCM */ + 2, /* num of channels */ + 22050, /* samples per sec */ + 88200, /* avg bytes per sec */ + 4, /* block align */ + 16, /* bits per sample */ + 0, /* data size */ + g_pmc_22050_data /* data */ +}; + +static char g_pmc_44100_data[] = { 0 }; +static struct xr_wave_format_ex g_pmc_44100 = +{ + 1, /* wFormatTag - WAVE_FORMAT_PCM */ + 2, /* num of channels */ + 44100, /* samples per sec */ + 176400, /* avg bytes per sec */ + 4, /* block align */ + 16, /* bits per sample */ + 0, /* data size */ + g_pmc_44100_data /* data */ +}; + +#define NUM_BUILT_IN 2 +static struct xr_wave_format_ex *g_wave_formats[NUM_BUILT_IN] = +{ + &g_pmc_44100, + &g_pmc_22050 +}; + +/* index into list from client */ +static int g_current_client_format_index = 0; +/* index into list from server */ +static int g_current_server_format_index = 0; + /*****************************************************************************/ static int APP_CC sound_send_server_formats(void) { struct stream *s; int bytes; + int index; char *size_ptr; - print_got_here(); - make_stream(s); init_stream(s, 8182); out_uint16_le(s, SNDC_FORMATS); size_ptr = s->p; - out_uint16_le(s, 0); /* size, set later */ - out_uint32_le(s, 0); /* dwFlags */ - out_uint32_le(s, 0); /* dwVolume */ - out_uint32_le(s, 0); /* dwPitch */ - out_uint16_le(s, 0); /* wDGramPort */ - out_uint16_le(s, 1); /* wNumberOfFormats */ - out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */ - out_uint16_le(s, 2); /* wVersion */ - out_uint8(s, 0); /* bPad */ + out_uint16_le(s, 0); /* size, set later */ + out_uint32_le(s, 0); /* dwFlags */ + out_uint32_le(s, 0); /* dwVolume */ + out_uint32_le(s, 0); /* dwPitch */ + out_uint16_le(s, 0); /* wDGramPort */ + out_uint16_le(s, NUM_BUILT_IN); /* wNumberOfFormats */ + out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */ + out_uint16_le(s, 2); /* wVersion */ + out_uint8(s, 0); /* bPad */ /* sndFormats */ /* @@ -75,13 +132,21 @@ sound_send_server_formats(void) 00 00 */ - out_uint16_le(s, 1); // wFormatTag - WAVE_FORMAT_PCM - out_uint16_le(s, 2); // num of channels - out_uint32_le(s, 44100); // samples per sec - out_uint32_le(s, 176400); // avg bytes per sec - out_uint16_le(s, 4); // block align - out_uint16_le(s, 16); // bits per sample - out_uint16_le(s, 0); // size + for (index = 0; index < NUM_BUILT_IN; index++) + { + out_uint16_le(s, g_wave_formats[index]->wFormatTag); + out_uint16_le(s, g_wave_formats[index]->nChannels); + out_uint32_le(s, g_wave_formats[index]->nSamplesPerSec); + out_uint32_le(s, g_wave_formats[index]->nAvgBytesPerSec); + out_uint16_le(s, g_wave_formats[index]->nBlockAlign); + out_uint16_le(s, g_wave_formats[index]->wBitsPerSample); + bytes = g_wave_formats[index]->cbSize; + out_uint16_le(s, bytes); + if (bytes > 0) + { + out_uint8p(s, g_wave_formats[index]->data, bytes); + } + } s_mark_end(s); bytes = (int)((s->end - s->data) - 4); @@ -102,8 +167,6 @@ sound_send_training(void) int time; char *size_ptr; - print_got_here(); - make_stream(s); init_stream(s, 8182); out_uint16_le(s, SNDC_TRAINING); @@ -125,6 +188,52 @@ sound_send_training(void) } /*****************************************************************************/ +static int APP_CC +sound_process_format(int aindex, int wFormatTag, int nChannels, + int nSamplesPerSec, int nAvgBytesPerSec, + int nBlockAlign, int wBitsPerSample, + int cbSize, char *data) +{ + int lindex; + + LOG(0, ("sound_process_format:")); + LOG(0, (" wFormatTag %d", wFormatTag)); + LOG(0, (" nChannels %d", nChannels)); + LOG(0, (" nSamplesPerSec %d", nSamplesPerSec)); + LOG(0, (" nAvgBytesPerSec %d", nAvgBytesPerSec)); + LOG(0, (" nBlockAlign %d", nBlockAlign)); + LOG(0, (" wBitsPerSample %d", wBitsPerSample)); + LOG(0, (" cbSize %d", cbSize)); + g_hexdump(data, cbSize); + if (wFormatTag == g_pmc_44100.wFormatTag && + nChannels == g_pmc_44100.nChannels && + nSamplesPerSec == g_pmc_44100.nSamplesPerSec && + nAvgBytesPerSec == g_pmc_44100.nAvgBytesPerSec && + nBlockAlign == g_pmc_44100.nBlockAlign && + wBitsPerSample == g_pmc_44100.wBitsPerSample) + { + g_current_client_format_index = aindex; + g_current_server_format_index = 0; + } +#if 0 + for (lindex = 0; lindex < NUM_BUILT_IN; lindex++) + { + if (wFormatTag == g_wave_formats[lindex]->wFormatTag && + nChannels == g_wave_formats[lindex]->nChannels && + nSamplesPerSec == g_wave_formats[lindex]->nSamplesPerSec && + nAvgBytesPerSec == g_wave_formats[lindex]->nAvgBytesPerSec && + nBlockAlign == g_wave_formats[lindex]->nBlockAlign && + wBitsPerSample == g_wave_formats[lindex]->wBitsPerSample) + { + g_current_client_format_index = aindex; + g_current_server_format_index = lindex; + } + } +#endif + return 0; +} + +/*****************************************************************************/ /* 0000 07 02 26 00 03 00 80 00 ff ff ff ff 00 00 00 00 ..&............. 0010 00 00 01 00 00 02 00 00 01 00 02 00 44 ac 00 00 ............D... @@ -135,8 +244,15 @@ static int APP_CC sound_process_formats(struct stream *s, int size) { int num_formats; - - print_got_here(); + int index; + int wFormatTag; + int nChannels; + int nSamplesPerSec; + int nAvgBytesPerSec; + int nBlockAlign; + int wBitsPerSample; + int cbSize; + char *data; LOG(0, ("sound_process_formats:")); @@ -147,9 +263,24 @@ sound_process_formats(struct stream *s, int size) in_uint8s(s, 14); in_uint16_le(s, num_formats); + in_uint8s(s, 4); if (num_formats > 0) { + for (index = 0; index < num_formats; index++) + { + in_uint16_le(s, wFormatTag); + in_uint16_le(s, nChannels); + in_uint32_le(s, nSamplesPerSec); + in_uint32_le(s, nAvgBytesPerSec); + in_uint16_le(s, nBlockAlign); + in_uint16_le(s, wBitsPerSample); + in_uint16_le(s, cbSize); + in_uint8p(s, data, cbSize); + sound_process_format(index, wFormatTag, nChannels, nSamplesPerSec, + nAvgBytesPerSec, nBlockAlign, wBitsPerSample, + cbSize, data); + } sound_send_training(); } @@ -157,37 +288,39 @@ sound_process_formats(struct stream *s, int size) } /*****************************************************************************/ +/* send wave message to client */ static int -sound_send_wave_data(char *data, int data_bytes) +sound_send_wave_data_chunk(char *data, int data_bytes) { struct stream *s; int bytes; int time; char *size_ptr; - print_got_here(); + LOG(10, ("sound_send_wave_data_chunk: data_bytes %d", data_bytes)); - if ((data_bytes < 4) || (data_bytes > 32 * 1024)) + if ((data_bytes < 4) || (data_bytes > 128 * 1024)) { - LOG(0, ("sound_send_wave_data: bad data_bytes %d", data_bytes)); + LOG(0, ("sound_send_wave_data_chunk: bad data_bytes %d", data_bytes)); } /* part one of 2 PDU wave info */ - LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes)); + LOG(10, ("sound_send_wave_data_chunk: sending %d bytes", data_bytes)); make_stream(s); - init_stream(s, data_bytes); + init_stream(s, 16 + data_bytes); /* some extra space */ out_uint16_le(s, SNDC_WAVE); size_ptr = s->p; out_uint16_le(s, 0); /* size, set later */ time = g_time2(); out_uint16_le(s, time); - out_uint16_le(s, 0); /* wFormatNo */ + out_uint16_le(s, g_current_client_format_index); /* wFormatNo */ g_cBlockNo++; out_uint8(s, g_cBlockNo); + g_sent_time[g_cBlockNo & 0xff] = time; - LOG(10, ("sound_send_wave_data: sending time %d, g_cBlockNo %d", + LOG(10, ("sound_send_wave_data_chunk: sending time %d, g_cBlockNo %d", time & 0xffff, g_cBlockNo & 0xff)); out_uint8s(s, 3); @@ -201,60 +334,139 @@ sound_send_wave_data(char *data, int data_bytes) bytes = (int)(s->end - s->data); send_channel_data(g_rdpsnd_chan_id, s->data, bytes); - /* part two of 2 PDU wave info */ + /* part two of 2 PDU wave info + even is zero, we have to send this */ init_stream(s, data_bytes); out_uint32_le(s, 0); out_uint8a(s, data + 4, data_bytes - 4); s_mark_end(s); bytes = (int)(s->end - s->data); send_channel_data(g_rdpsnd_chan_id, s->data, bytes); + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* send wave message to client, buffer first */ +static int +sound_send_wave_data(char *data, int data_bytes) +{ + int space_left; + int chunk_bytes; + int data_index; + + LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes)); + data_index = 0; + while (data_bytes > 0) + { + space_left = BBUF_SIZE - g_buf_index; + chunk_bytes = MIN(space_left, data_bytes); + if (chunk_bytes < 1) + { + LOG(10, ("sound_send_wave_data: error")); + break; + } + g_memcpy(g_buffer + g_buf_index, data + data_index, chunk_bytes); + g_buf_index += chunk_bytes; + if (g_buf_index >= BBUF_SIZE) + { + sound_send_wave_data_chunk(g_buffer, BBUF_SIZE); + g_buf_index = 0; + } + data_bytes -= chunk_bytes; + data_index += chunk_bytes; + } + return 0; +} + +/*****************************************************************************/ +/* send close message to client */ +static int +sound_send_close(void) +{ + struct stream *s; + int bytes; + char *size_ptr; + + LOG(10, ("sound_send_close:")); + + /* send any left over data */ + sound_send_wave_data_chunk(g_buffer, g_buf_index); + g_buf_index = 0; + + make_stream(s); + init_stream(s, 8182); + out_uint16_le(s, SNDC_CLOSE); + size_ptr = s->p; + out_uint16_le(s, 0); /* size, set later */ + s_mark_end(s); + bytes = (int)((s->end - s->data) - 4); + size_ptr[0] = bytes; + size_ptr[1] = bytes >> 8; + bytes = (int)(s->end - s->data); + send_channel_data(g_rdpsnd_chan_id, s->data, bytes); free_stream(s); return 0; } /*****************************************************************************/ +/* from client */ static int APP_CC sound_process_training(struct stream *s, int size) { int time_diff; - print_got_here(); - time_diff = g_time2() - g_training_sent_time; LOG(0, ("sound_process_training: round trip time %u", time_diff)); return 0; } /*****************************************************************************/ +/* from client */ static int APP_CC sound_process_wave_confirm(struct stream *s, int size) { int wTimeStamp; int cConfirmedBlockNo; + int time; + int time_diff; - print_got_here(); - + time = g_time2(); in_uint16_le(s, wTimeStamp); in_uint8(s, cConfirmedBlockNo); + time_diff = time - g_sent_time[cConfirmedBlockNo]; - LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, cConfirmedBlockNo %d", - wTimeStamp, cConfirmedBlockNo)); + LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, " + "cConfirmedBlockNo %d time diff %d", + wTimeStamp, cConfirmedBlockNo, time_diff)); return 0; } /*****************************************************************************/ +/* process message in from the audio source, eg pulse, alsa + on it's way to the client */ static int APP_CC process_pcm_message(int id, int size, struct stream *s) { - print_got_here(); - - sound_send_wave_data(s->p, size); + switch (id) + { + case 0: + sound_send_wave_data(s->p, size); + break; + case 1: + sound_send_close(); + break; + default: + LOG(0, ("process_pcm_message: unknown id %d", id)); + break; + } return 0; } /*****************************************************************************/ -/* data coming in from audio source, eg pulse, alsa */ +/* data in from audio source, eg pulse, alsa */ static int DEFAULT_CC sound_trans_audio_data_in(struct trans *trans) { @@ -277,11 +489,12 @@ sound_trans_audio_data_in(struct trans *trans) in_uint32_le(s, id); in_uint32_le(s, size); - if ((id != 0) || (size > 32 * 1024 + 8) || (size < 1)) + if ((id & ~3) || (size > 128 * 1024 + 8) || (size < 8)) { LOG(0, ("sound_trans_audio_data_in: bad message id %d size %d", id, size)); return 1; } + LOG(10, ("sound_trans_audio_data_in: good message id %d size %d", id, size)); error = trans_force_read(trans, size - 8); @@ -295,10 +508,11 @@ sound_trans_audio_data_in(struct trans *trans) } /*****************************************************************************/ +/* this is a connection in on the unix domain socket */ static int DEFAULT_CC sound_trans_audio_conn_in(struct trans *trans, struct trans *new_trans) { - print_got_here(); + LOG(0, ("sound_trans_audio_conn_in:")); if (trans == 0) { @@ -335,12 +549,11 @@ sound_init(void) char port[256]; int error; - print_got_here(); LOG(0, ("sound_init:")); sound_send_server_formats(); - g_audio_l_trans = trans_create(2, 33 * 1024, 8192); - g_snprintf(port, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num); + g_audio_l_trans = trans_create(2, 128 * 1024, 8192); + 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); @@ -363,8 +576,6 @@ sound_init(void) int APP_CC sound_deinit(void) { - print_got_here(); - if (g_audio_l_trans != 0) { trans_delete(g_audio_l_trans); @@ -374,14 +585,14 @@ sound_deinit(void) if (g_audio_c_trans != 0) { trans_delete(g_audio_c_trans); - g_audio_l_trans = 0; + g_audio_c_trans = 0; } return 0; } /*****************************************************************************/ -/* data in from client ( clinet -> xrdp -> chansrv ) */ +/* data in from client ( client -> xrdp -> chansrv ) */ int APP_CC sound_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) @@ -389,8 +600,6 @@ sound_data_in(struct stream *s, int chan_id, int chan_flags, int length, int code; int size; - print_got_here(); - in_uint8(s, code); in_uint8s(s, 1); in_uint16_le(s, size); @@ -460,6 +669,8 @@ sound_check_wait_objs(void) #if defined(XRDP_SIMPLESOUND) +#define AUDIO_BUF_SIZE 2048 + static int DEFAULT_CC sttrans_data_in(struct trans *self) { diff --git a/sesman/chansrv/sound.h b/sesman/chansrv/sound.h index 8171680d..0666ea00 100644 --- a/sesman/chansrv/sound.h +++ b/sesman/chansrv/sound.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2009-2012 + * Copyright (C) Jay Sorg 2009-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,18 +30,6 @@ #include "chansrv.h" #include "trans.h" -#define _DEBUG_RDPSND - -#ifdef DEBUG_RDPSND -#include <stdio.h> -#define print_got_here() printf("****** got here: %s : %s : %d\n", \ - __FILE__, __func__, __LINE__); -#else -#define print_got_here() -#endif - -#define AUDIO_BUF_SIZE 2048 - #define SNDC_CLOSE 0x01 #define SNDC_WAVE 0x02 #define SNDC_SETVOLUME 0x03 diff --git a/sesman/chansrv/wave-format-server.txt b/sesman/chansrv/wave-format-server.txt new file mode 100644 index 00000000..1d0bb91e --- /dev/null +++ b/sesman/chansrv/wave-format-server.txt @@ -0,0 +1,466 @@ + + +Example wave formats from some servers + +see MMREG.H for defines + +Windows 7 SP1 + +example wave data sizes coming from server 8820 + +wFormatTag=1 nChannels=2 nSamplesPerSec=44100 nAvgBytesPerSec=176400 nBlockAlign=4 wBitsPerSample=16 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=44100 nAvgBytesPerSec=88200 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=44100 nAvgBytesPerSec=88200 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=44100 nAvgBytesPerSec=44359 nBlockAlign=2048 wBitsPerSample=4 cbSize=32 + 0000 f4 07 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=44100 nAvgBytesPerSec=44251 nBlockAlign=2048 wBitsPerSample=4 cbSize=2 + 0000 f9 07 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=44100 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=44100 nAvgBytesPerSec=44100 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=44100 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=44100 nAvgBytesPerSec=44100 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=22311 nBlockAlign=1024 wBitsPerSample=4 cbSize=32 + 0000 f4 03 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=22201 nBlockAlign=1024 wBitsPerSample=4 cbSize=2 + 0000 f9 03 .. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=44100 nAvgBytesPerSec=22179 nBlockAlign=1024 wBitsPerSample=4 cbSize=32 + 0000 f4 07 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=44100 nAvgBytesPerSec=22125 nBlockAlign=1024 wBitsPerSample=4 cbSize=2 + 0000 f9 07 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=22050 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=22050 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=22050 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=22050 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=16000 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=16000 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=11289 nBlockAlign=512 wBitsPerSample=4 cbSize=32 + 0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=11177 nBlockAlign=512 wBitsPerSample=4 cbSize=2 + 0000 f9 01 .. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=11155 nBlockAlign=512 wBitsPerSample=4 cbSize=32 + 0000 f4 03 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=11100 nBlockAlign=512 wBitsPerSample=4 cbSize=2 + 0000 f9 03 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=11025 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=11025 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +wFormatTag=49 nChannels=1 nSamplesPerSec=44100 nAvgBytesPerSec=8957 nBlockAlign=65 wBitsPerSample=0 cbSize=2 + 0000 40 01 @. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=8192 nBlockAlign=512 wBitsPerSample=4 cbSize=32 + 0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=8110 nBlockAlign=512 wBitsPerSample=4 cbSize=2 + 0000 f9 01 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=8000 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=8000 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +wFormatTag=2 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=5644 nBlockAlign=256 wBitsPerSample=4 cbSize=32 + 0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +wFormatTag=17 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=5588 nBlockAlign=256 wBitsPerSample=4 cbSize=2 + 0000 f9 01 .. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=4478 nBlockAlign=65 wBitsPerSample=0 cbSize=2 + 0000 40 01 @. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=4096 nBlockAlign=256 wBitsPerSample=4 cbSize=32 + 0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ + 0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=4055 nBlockAlign=256 wBitsPerSample=4 cbSize=2 + 0000 f9 01 .. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=2239 nBlockAlign=65 wBitsPerSample=0 cbSize=2 + 0000 40 01 @. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=1625 nBlockAlign=65 wBitsPerSample=0 cbSize=2 + 0000 40 01 @. + + + + +Windows XP SP3 + +example wave data sizes coming from server 32512, 16256 + +wFormatTag=1 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=88200 nBlockAlign=4 wBitsPerSample=16 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=44100 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=44100 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=22311 nBlockAlign=1024 wBitsPerSample=4 cbSize=32 +0000 f4 03 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=22201 nBlockAlign=1024 wBitsPerSample=4 cbSize=2 +0000 f9 03 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=22050 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=22050 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=22050 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=22050 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=16000 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=16000 nBlockAlign=2 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=11289 nBlockAlign=512 wBitsPerSample=4 cbSize=32 +0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=11177 nBlockAlign=512 wBitsPerSample=4 cbSize=2 +0000 f9 01 .. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=11155 nBlockAlign=512 wBitsPerSample=4 cbSize=32 +0000 f4 03 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=11100 nBlockAlign=512 wBitsPerSample=4 cbSize=2 +0000 f9 03 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=11025 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=11025 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=8192 nBlockAlign=512 wBitsPerSample=4 cbSize=32 +0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=8110 nBlockAlign=512 wBitsPerSample=4 cbSize=2 +0000 f9 01 .. + +#define WAVE_FORMAT_ALAW 0x0006 /* Microsoft Corporation */ +wFormatTag=6 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=8000 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MULAW 0x0007 /* Microsoft Corporation */ +wFormatTag=7 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=8000 nBlockAlign=1 wBitsPerSample=8 cbSize=0 + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=7000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 b6 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=16000 nAvgBytesPerSec=7000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 fc 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=6000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 9c 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=16000 nAvgBytesPerSec=6000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 d8 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=5644 nBlockAlign=256 wBitsPerSample=4 cbSize=32 +0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=5588 nBlockAlign=256 wBitsPerSample=4 cbSize=2 +0000 f9 01 .. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=5000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 82 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=16000 nAvgBytesPerSec=5000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 b4 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=4478 nBlockAlign=65 wBitsPerSample=0 cbSize=2 +0000 40 01 @. + +#define WAVE_FORMAT_ADPCM 0x0002 /* Microsoft Corporation */ +wFormatTag=2 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=4096 nBlockAlign=256 wBitsPerSample=4 cbSize=32 +0000 f4 01 07 00 00 01 00 00 00 02 00 ff 00 00 00 00 ................ +0010 c0 00 40 00 f0 00 00 00 cc 01 30 ff 88 01 18 ff ..@.......0..... + +#define WAVE_FORMAT_DVI_ADPCM 0x0011 /* Intel Corporation */ +wFormatTag=17 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=4055 nBlockAlign=256 wBitsPerSample=4 cbSize=2 +0000 f9 01 .. + +? +wFormatTag=353 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=4005 nBlockAlign=186 wBitsPerSample=16 cbSize=47 +0000 00 04 00 00 01 00 ba 00 00 00 46 36 44 43 39 38 ..........F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=16000 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 90 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=12000 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 c0 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 d0 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 20 01 01 00 71 05 ...... ...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 68 00 01 00 71 05 ......h...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=4000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 90 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=12000 nAvgBytesPerSec=3000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 90 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=3000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 9c 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=3000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 d8 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=3000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 4e 00 01 00 71 05 ......N...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=3000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 6c 00 01 00 71 05 ......l...q. + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=22050 nAvgBytesPerSec=2519 nBlockAlign=117 wBitsPerSample=16 cbSize=47 +0000 00 04 00 00 00 00 75 00 00 00 46 36 44 43 39 38 ......u...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +? +wFormatTag=353 nChannels=2 nSamplesPerSec=22050 nAvgBytesPerSec=2519 nBlockAlign=117 wBitsPerSample=16 cbSize=47 +0000 00 04 00 00 00 00 75 00 00 00 46 36 44 43 39 38 ......u...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=12000 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 f0 00 02 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 04 01 02 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 68 01 02 00 71 05 ......h...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 b4 00 02 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=12000 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 f0 00 02 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=2500 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 04 01 02 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=12000 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 b0 01 04 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=11025 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 d4 01 04 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 88 02 04 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 44 01 04 00 71 05 ......D...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=12000 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 b0 01 04 00 71 05 ..........q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=2250 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 d4 01 04 00 71 05 ..........q. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=2239 nBlockAlign=65 wBitsPerSample=0 cbSize=2 +0000 40 01 @. + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=2000 nBlockAlign=64 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 40 00 00 00 46 36 44 43 39 38 ......@...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=16000 nAvgBytesPerSec=2000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 48 00 01 00 71 05 ......H...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=12000 nAvgBytesPerSec=2000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 60 00 01 00 71 05 ......`...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=2000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 68 00 01 00 71 05 ......h...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=2000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 90 00 01 00 71 05 ..........q. + +#define WAVE_FORMAT_GSM610 0x0031 /* Microsoft Corporation */ +wFormatTag=49 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=1625 nBlockAlign=65 wBitsPerSample=0 cbSize=2 +0000 40 01 @. + +? +wFormatTag=353 nChannels=2 nSamplesPerSec=8000 nAvgBytesPerSec=1500 nBlockAlign=96 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 60 00 00 00 46 36 44 43 39 38 ......`...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=1249 nBlockAlign=58 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 3a 00 00 00 46 36 44 43 39 38 ......:...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +#define WAVE_FORMAT_DSPGROUP_TRUESPEECH 0x0022 /* DSP Group, Inc */ +wFormatTag=34 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=1067 nBlockAlign=32 wBitsPerSample=1 cbSize=32 +0000 01 00 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=1012 nBlockAlign=47 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 2f 00 00 00 46 36 44 43 39 38 ....../...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=1000 nBlockAlign=64 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 40 00 00 00 46 36 44 43 39 38 ......@...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=12000 nAvgBytesPerSec=1000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 30 00 01 00 71 05 ......0...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=11025 nAvgBytesPerSec=1000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 34 00 01 00 71 05 ......4...q. + +#define WAVE_FORMAT_MPEGLAYER3 0x0055 /* ISO/MPEG Layer3 Format Tag */ +wFormatTag=85 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=1000 nBlockAlign=1 wBitsPerSample=0 cbSize=12 +0000 01 00 02 00 00 00 48 00 01 00 71 05 ......H...q. + +? +wFormatTag=66 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=800 nBlockAlign=24 wBitsPerSample=0 cbSize=10 +0000 02 00 ce 9a 32 f7 a2 ae de ac ....2..... + +? +wFormatTag=353 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=750 nBlockAlign=48 wBitsPerSample=16 cbSize=47 +0000 00 02 00 00 00 00 30 00 00 00 46 36 44 43 39 38 ......0...F6DC98 +0010 33 30 2d 42 43 37 39 2d 31 31 64 32 2d 41 39 44 30-BC79-11d2-A9D +0020 30 2d 30 30 36 30 39 37 39 32 36 30 33 36 00 0-006097926036. + +? +wFormatTag=66 nChannels=1 nSamplesPerSec=8000 nAvgBytesPerSec=666 nBlockAlign=20 wBitsPerSample=0 cbSize=10 +0000 03 00 ce 9a 32 f7 a2 ae de ac ....2..... diff --git a/sesman/config.c b/sesman/config.c index 9938249f..e2131c14 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -286,13 +286,18 @@ config_read_security(int file, struct config_security *sc, sc->ts_admins = gid; } } + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALWAYSGROUPCHECK)) + { + sc->ts_always_group_check = text2bool((char *)list_get_item(param_v, i)); + } } /* printing security config */ g_printf("security configuration:\r\n"); g_printf("\tAllowRootLogin: %i\r\n", sc->allow_root); g_printf("\tMaxLoginRetry: %i\r\n", sc->login_retry); - + g_printf("\tAlwaysGroupCheck: %i\r\n", sc->ts_always_group_check); + if (sc->ts_users_enable) { g_printf("\tTSUsersGroup: %i\r\n", sc->ts_users); diff --git a/sesman/config.h b/sesman/config.h index 72c6cac4..263975b3 100644 --- a/sesman/config.h +++ b/sesman/config.h @@ -56,6 +56,7 @@ #define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" #define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" #define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" +#define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck" #define SESMAN_CFG_SESSIONS "Sessions" #define SESMAN_CFG_SESS_MAX "MaxSessions" @@ -93,6 +94,11 @@ struct config_security */ int ts_admins_enable; int ts_admins; + /** + * @var ts_always_group_check + * @brief if the Groups are not found deny access + */ + int ts_always_group_check; }; /** diff --git a/sesman/libscp/libscp_tcp.c b/sesman/libscp/libscp_tcp.c index 29870563..30e8006c 100644 --- a/sesman/libscp/libscp_tcp.c +++ b/sesman/libscp/libscp_tcp.c @@ -26,12 +26,6 @@ #include "libscp_tcp.h" -#include <netinet/in.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> - extern struct log_config *s_log; /*****************************************************************************/ @@ -124,11 +118,5 @@ scp_tcp_force_send(int sck, char *data, int len) int DEFAULT_CC scp_tcp_bind(int sck, char *addr, char *port) { - struct sockaddr_in s; - - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = inet_addr(addr); - return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); + return g_tcp_bind_address(sck, port, addr); } diff --git a/sesman/scp_v0.c b/sesman/scp_v0.c index da6ab919..6ecb47b1 100644 --- a/sesman/scp_v0.c +++ b/sesman/scp_v0.c @@ -35,8 +35,9 @@ scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) int display = 0; tbus data; struct session_item *s_item; + int errorcode = 0 ; - data = auth_userpass(s->username, s->password); + data = auth_userpass(s->username, s->password,&errorcode); if (s->type == SCP_GW_AUTHENTICATION) { @@ -47,14 +48,14 @@ scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) if (1 == access_login_allowed(s->username)) { /* the user is member of the correct groups. */ - scp_v0s_replyauthentication(c, 0); + scp_v0s_replyauthentication(c, errorcode); log_message(LOG_LEVEL_INFO, "Access permitted for user: %s", s->username); /* g_writeln("Connection allowed"); */ } else { - scp_v0s_replyauthentication(c, 3); + scp_v0s_replyauthentication(c, 32+3); /* all first 32 are reserved for PAM errors */ log_message(LOG_LEVEL_INFO, "Username okey but group problem for " "user: %s", s->username); /* g_writeln("user password ok, but group problem"); */ @@ -65,7 +66,7 @@ scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) /* g_writeln("username or password error"); */ log_message(LOG_LEVEL_INFO, "Username or password error for user: %s", s->username); - scp_v0s_replyauthentication(c, 2); + scp_v0s_replyauthentication(c, errorcode); } auth_end(data); diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c index 295fbce4..d3f0ab7f 100644 --- a/sesman/scp_v1.c +++ b/sesman/scp_v1.c @@ -50,7 +50,7 @@ scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) retries = g_cfg->sec.login_retry; current_try = retries; - data = auth_userpass(s->username, s->password); + data = auth_userpass(s->username, s->password,NULL); /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ while ((!data) && ((retries == 0) || (current_try > 0))) @@ -65,7 +65,7 @@ scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { case SCP_SERVER_STATE_OK: /* all ok, we got new username and password */ - data = auth_userpass(s->username, s->password); + data = auth_userpass(s->username, s->password,NULL); /* one try less */ if (current_try > 0) diff --git a/sesman/scp_v1_mng.c b/sesman/scp_v1_mng.c index 0e20007d..9d1da0f5 100644 --- a/sesman/scp_v1_mng.c +++ b/sesman/scp_v1_mng.c @@ -42,7 +42,7 @@ scp_v1_mng_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) int scount; int end = 0; - data = auth_userpass(s->username, s->password); + data = auth_userpass(s->username, s->password,NULL); /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ if (!data) diff --git a/sesman/sesman.ini b/sesman/sesman.ini index f2a210a4..571e063b 100644 --- a/sesman/sesman.ini +++ b/sesman/sesman.ini @@ -10,6 +10,9 @@ AllowRootLogin=1 MaxLoginRetry=4 TerminalServerUsers=tsusers TerminalServerAdmins=tsadmins +# When AlwaysGroupCheck = false access will be permitted +# if the group TerminalServerUsers is not defined. +AlwaysGroupCheck = false [Sessions] X11DisplayOffset=10 diff --git a/sesman/session.c b/sesman/session.c index 6f98fbc7..3a200f50 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -33,6 +33,8 @@ extern tbus g_sync_event; extern unsigned char g_fixedkey[8]; extern struct config_sesman *g_cfg; /* in sesman.c */ +extern int g_sck; /* in sesman.c */ +extern int g_thread_sck; /* in thread.c */ struct session_chain *g_sessions; int g_session_count; @@ -449,6 +451,8 @@ session_start_fork(int width, int height, int bpp, char *username, } else if (pid == 0) /* child sesman */ { + 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); diff --git a/sesman/startwm.sh b/sesman/startwm.sh index 02fc7956..457ca1a5 100755 --- a/sesman/startwm.sh +++ b/sesman/startwm.sh @@ -1,93 +1,25 @@ #!/bin/sh - -# change the order in line below to run to run whatever window manager you -# want, default to kde - -SESSIONS="gnome-session blackbox fluxbox startxfce4 startkde xterm" - -#start the window manager -wm_start() -{ - for WindowManager in $SESSIONS - do - which $WindowManager - if test $? -eq 0 - then - echo "Starting $WindowManager" - $WindowManager - return 0 - fi - done - return 0 -} - -#Execution sequence for interactive login shell -#Following pseudo code explains the sequence of execution of these files. -#execute /etc/profile -#IF ~/.bash_profile exists THEN -# execute ~/.bash_profile -#ELSE -# IF ~/.bash_login exist THEN -# execute ~/.bash_login -# ELSE -# IF ~/.profile exist THEN -# execute ~/.profile -# END IF -# END IF -#END IF -pre_start() -{ - if [ -f /etc/profile ] - then - . /etc/profile - fi - if [ -f ~/.bash_profile ] - then - . ~/.bash_profile - else - if [ -f ~/.bash_login ] - then - . ~/.bash_login - else - if [ -f ~/.profile ] - then - . ~/.profile - fi - fi - fi - return 0 -} - -#When you logout of the interactive shell, following is the -#sequence of execution: -#IF ~/.bash_logout exists THEN -# execute ~/.bash_logout -#END IF -post_start() -{ - if [ -f ~/.bash_logout ] - then - . ~/.bash_logout - fi - return 0 -} - -#. /etc/environment -#export PATH=$PATH -#export LANG=$LANG - -# change PATH to be what your environment needs usually what is in -# /etc/environment -#PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" -#export PATH=$PATH - -# for PATH and LANG from /etc/environment -# pam will auto process the environment file if /etc/pam.d/xrdp-sesman -# includes -# auth required pam_env.so readenv=1 - -pre_start -wm_start -post_start - -exit 1 +if [ -r /etc/default/locale ]; then + . /etc/default/locale + export LANG LANGUAGE +fi + +# debian +if [ -r /etc/X11/Xsession ]; then + . /etc/X11/Xsession + exit 0 +fi + +# el +if [ -r /etc/X11/xinit/Xsession ]; then + . /etc/X11/xinit/Xsession + exit 0 +fi + +# suse +if [ -r /etc/X11/xdm/Xsession ]; then + . /etc/X11/xdm/Xsession + exit 0 +fi + +xterm diff --git a/sesman/verify_user.c b/sesman/verify_user.c index 8765d7c2..85e614d3 100644 --- a/sesman/verify_user.c +++ b/sesman/verify_user.c @@ -48,14 +48,11 @@ auth_account_disabled(struct spwd *stp); /******************************************************************************/ /* returns boolean */ long DEFAULT_CC -auth_userpass(char *user, char *pass) +auth_userpass(char *user, char *pass, int *errorcode) { - char salt[13] = "$1$"; - char hash[35] = ""; - char *encr = 0; + const char *encr; struct passwd *spw; struct spwd *stp; - int saltcnt = 0; spw = getpwnam(user); @@ -76,50 +73,19 @@ auth_userpass(char *user, char *pass) if (1 == auth_account_disabled(stp)) { - log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user); + log_message(LOG_LEVEL_INFO, "account %s is disabled", user); return 0; } - g_strncpy(hash, stp->sp_pwdp, 34); + encr = stp->sp_pwdp; } else { /* old system with only passwd */ - g_strncpy(hash, spw->pw_passwd, 34); - } - - hash[34] = '\0'; - - if (g_strncmp(hash, "$1$", 3) == 0) - { - /* gnu style crypt(); */ - saltcnt = 3; - - while ((hash[saltcnt] != '$') && (saltcnt < 11)) - { - salt[saltcnt] = hash[saltcnt]; - saltcnt++; - } - - salt[saltcnt] = '$'; - salt[saltcnt + 1] = '\0'; - } - else - { - /* classic two char salt */ - salt[0] = hash[0]; - salt[1] = hash[1]; - salt[2] = '\0'; - } - - encr = crypt(pass, salt); - - if (g_strncmp(encr, hash, 34) != 0) - { - return 0; + encr = spw->pw_passwd; } - return 1; + return (strcmp(encr, crypt(pass, encr)) == 0); } /******************************************************************************/ diff --git a/sesman/verify_user_kerberos.c b/sesman/verify_user_kerberos.c index c4a7ecde..fc0d4aa2 100644 --- a/sesman/verify_user_kerberos.c +++ b/sesman/verify_user_kerberos.c @@ -396,7 +396,7 @@ cleanup: /******************************************************************************/ /* returns boolean */ int DEFAULT_CC -auth_userpass(char *user, char *pass) +auth_userpass(char *user, char *pass, int *errorcode) { struct k_opts opts; struct k5_data k5; diff --git a/sesman/verify_user_pam.c b/sesman/verify_user_pam.c index b81398de..b7a7bef7 100644 --- a/sesman/verify_user_pam.c +++ b/sesman/verify_user_pam.c @@ -98,9 +98,11 @@ get_service_name(char *service_name) } /******************************************************************************/ -/* returns long, zero is no go */ +/* returns long, zero is no go + Stores the detailed error code in the errorcode variable*/ + long DEFAULT_CC -auth_userpass(char *user, char *pass) +auth_userpass(char *user, char *pass, int *errorcode) { int error; struct t_auth_info *auth_info; @@ -116,6 +118,9 @@ auth_userpass(char *user, char *pass) if (error != PAM_SUCCESS) { + if(errorcode!=NULL){ + *errorcode = error ; + } g_printf("pam_start failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); return 0; @@ -125,16 +130,27 @@ auth_userpass(char *user, char *pass) if (error != PAM_SUCCESS) { + if(errorcode!=NULL){ + *errorcode = error ; + } g_printf("pam_authenticate failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); return 0; } - + /* From man page: + The pam_acct_mgmt function is used to determine if the users account is + valid. It checks for authentication token and account expiration and + verifies access restrictions. It is typically called after the user has + been authenticated. + */ error = pam_acct_mgmt(auth_info->ph, 0); if (error != PAM_SUCCESS) { + if(errorcode!=NULL){ + *errorcode = error ; + } g_printf("pam_acct_mgmt failed: %s\r\n", pam_strerror(auth_info->ph, error)); g_free(auth_info); diff --git a/sesman/verify_user_pam_userpass.c b/sesman/verify_user_pam_userpass.c index 9fa2d9e5..4d6aac40 100644 --- a/sesman/verify_user_pam_userpass.c +++ b/sesman/verify_user_pam_userpass.c @@ -34,7 +34,7 @@ /******************************************************************************/ /* returns boolean */ int DEFAULT_CC -auth_userpass(char *user, char *pass) +auth_userpass(char *user, char *pass, int *errorcode) { pam_handle_t *pamh; pam_userpass_t userpass; diff --git a/tests/gtcp_proxy/Makefile b/tests/gtcp_proxy/Makefile new file mode 100644 index 00000000..4f4c2930 --- /dev/null +++ b/tests/gtcp_proxy/Makefile @@ -0,0 +1,21 @@ + +# := evaluates the expression just once +# = evaluates the expression each time it is used + +CFLAGS := $(shell pkg-config --cflags gtk+-2.0) +CFLAGS += -O2 -Wall +#LDFLAGS = -Wl +LIBS := $(shell pkg-config --libs gtk+-2.0) +LIBS += -ldl -lgthread-2.0 + +OBJS = gtcp-proxy.o gtcp.o + +all: gtcp-proxy + +gtcp-proxy: $(OBJS) + gcc -Wall $(CFLAGS) $(LDFLAGS) gtcp-proxy.c gtcp.o -o gtcp-proxy $(LIBS) + +gtcp.o: gtcp.c + gcc -c gtcp.c +clean:: + -rm gtcp-proxy.o gtcp.o gtcp-proxy diff --git a/tests/gtcp_proxy/README.txt b/tests/gtcp_proxy/README.txt new file mode 100644 index 00000000..41907e2e --- /dev/null +++ b/tests/gtcp_proxy/README.txt @@ -0,0 +1,4 @@ + +gtcp-proxy is a 'man in the middle' program to monitor data flowing between +two network connections. + diff --git a/tests/gtcp_proxy/gtcp-proxy b/tests/gtcp_proxy/gtcp-proxy Binary files differnew file mode 100755 index 00000000..6896b437 --- /dev/null +++ b/tests/gtcp_proxy/gtcp-proxy diff --git a/tests/gtcp_proxy/gtcp-proxy.c b/tests/gtcp_proxy/gtcp-proxy.c new file mode 100644 index 00000000..39555c76 --- /dev/null +++ b/tests/gtcp_proxy/gtcp-proxy.c @@ -0,0 +1,678 @@ +/** + * 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. + */ + +#include <stdio.h> +#include <gtk/gtk.h> +#include <pthread.h> + +#include "gtcp.h" + +#define WINDOW_TITLE "Tcp Proxy Version 1.0" +#define CONTEXT_ID 1 +#define MSG_INFO GTK_MESSAGE_INFO +#define MSG_WARN GTK_MESSAGE_WARNING +#define MSG_ERROR GTK_MESSAGE_ERROR +#define MAIN_THREAD_YES 0 +#define MAIN_THREAD_NO 1 + +/* globals */ +pthread_t g_tid; +int g_keep_running = 1; +int g_loc_io_count = 0; /* bytes read from local port */ +int g_rem_io_count = 0; /* bytes read from remote port */ + +GtkWidget *g_btn_start; +GtkWidget *g_tbx_loc_port; +GtkWidget *g_tbx_rem_ip; +GtkWidget *g_tbx_rem_port; +GtkWidget *g_tbx_loc_stats; +GtkWidget *g_tbx_rem_stats; +GtkWidget *g_statusbar; +GtkWidget *g_txtvu_loc_port; +GtkWidget *g_txtvu_rem_port; + +/* forward declarations */ +static void *tcp_proxy(void *arg); + +static void show_msg(int not_main_thread, int style, + const gchar *title, const gchar *msg); + +static void show_status(int not_main_thread, char *msg); +static void clear_status(int not_main_thread); +static void enable_btn_start(int main_thread); +static void disable_btn_start(int main_thread); + +/* getters */ +static char *get_local_port(); +static char *get_remote_ip(); +static char *get_remote_port(); + +/* setters */ +static void show_loc_port_stats(int main_thread, int count); +static void show_rem_port_stats(int main_thread, int count); + +/* handlers */ +static gboolean on_delete_event(GtkWidget *widget, GdkEvent *ev, gpointer data); +static void on_destroy(GtkWidget *widget, gpointer data); +static void on_start_clicked(GtkWidget *widget, gpointer data); +static void on_clear_clicked(GtkWidget *widget, gpointer data); +static void on_quit_clicked(GtkWidget *widget, gpointer data); + +int main(int argc, char **argv) +{ + /* init threads */ + g_thread_init(NULL); + gdk_threads_init(); + + /* setup GTK */ + gtk_init(&argc, &argv); + + /* create labels and right justify them */ + GtkWidget *lbl_loc_port = gtk_label_new("Local port"); + GtkWidget *lbl_rem_ip = gtk_label_new("Remote IP"); + GtkWidget *lbl_rem_port = gtk_label_new("Remote port"); + GtkWidget *lbl_loc_stats = gtk_label_new("Local port recv stats"); + GtkWidget *lbl_rem_stats = gtk_label_new("Remote port recv stats"); + + gtk_misc_set_alignment(GTK_MISC(lbl_loc_port), 1.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(lbl_rem_ip), 1.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(lbl_rem_port), 1.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(lbl_loc_stats), 1.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(lbl_rem_stats), 1.0, 0.5); + + /* create text boxes */ + g_tbx_loc_port = gtk_entry_new(); + g_tbx_rem_ip = gtk_entry_new(); + g_tbx_rem_port = gtk_entry_new(); + g_tbx_loc_stats = gtk_entry_new(); + g_tbx_rem_stats = gtk_entry_new(); + + /* stat text boxes are read only */ + gtk_entry_set_editable(GTK_ENTRY(g_tbx_loc_stats), FALSE); + gtk_entry_set_editable(GTK_ENTRY(g_tbx_rem_stats), FALSE); + + /* enable when debugging */ +#if 0 + gtk_entry_set_text(GTK_ENTRY(g_tbx_loc_port), "1234"); + gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_ip), "192.168.2.20"); + gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_port), "43222"); +#endif + + /* setup buttons inside a HBox */ + g_btn_start = gtk_button_new_with_label("Start listening"); + GtkWidget *btn_clear = gtk_button_new_with_label("Clear receive stats"); + GtkWidget *btn_quit = gtk_button_new_with_label("Quit application"); + + GtkWidget *hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start_defaults(GTK_BOX(hbox), g_btn_start); + gtk_box_pack_start_defaults(GTK_BOX(hbox), btn_clear); + gtk_box_pack_start_defaults(GTK_BOX(hbox), btn_quit); + +#if 0 + g_txtvu_loc_port = gtk_text_view_new(); + g_txtvu_rem_port = gtk_text_view_new(); +#endif + + /* create table */ + GtkWidget *table = gtk_table_new(8, 3, FALSE); + + int row = 0; + + /* insert labels into table */ + gtk_table_attach(GTK_TABLE(table), lbl_loc_port, 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), lbl_rem_ip, 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), lbl_rem_port, 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), lbl_loc_stats, 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), lbl_rem_stats, 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + row = 0; + + /* insert text boxes into table */ + gtk_table_attach(GTK_TABLE(table), g_tbx_loc_port, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), g_tbx_rem_ip, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), g_tbx_rem_port, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), g_tbx_loc_stats, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + + gtk_table_attach(GTK_TABLE(table), g_tbx_rem_stats, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + row++; + + /* insert hbox with buttons into table */ + gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; + +#if 0 + /* text view to display hexdumps */ + gtk_table_attach(GTK_TABLE(table), g_txtvu_loc_port, 0, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + row++; +#endif + + /* status bar to display messages */ + g_statusbar = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(g_statusbar), TRUE); + gtk_table_attach(GTK_TABLE(table), g_statusbar, 0, 2, row, row + 1, + GTK_FILL, GTK_FILL, 5, 0); + + /* setup main window */ + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(window), 5); + gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); + gtk_window_set_title(GTK_WINDOW(window), WINDOW_TITLE); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_window_set_resizable(GTK_WINDOW(window), FALSE); + + gtk_container_add(GTK_CONTAINER(window), table); + gtk_widget_show_all(window); + + /* setup callbacks */ + g_signal_connect(window, "delete-event", G_CALLBACK(on_delete_event), NULL); + g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), NULL); + + g_signal_connect(g_btn_start, "clicked", G_CALLBACK(on_start_clicked), NULL); + g_signal_connect(btn_clear, "clicked", G_CALLBACK(on_clear_clicked), NULL); + g_signal_connect(btn_quit, "clicked", G_CALLBACK(on_quit_clicked), NULL); + + gdk_threads_enter(); + gtk_main(); + gdk_threads_leave(); + + return 0; +} + +/** + * Start listening on specifed local socket; when we get a connection, + * connect to specified remote server and transfer data between local + * and remote server + *****************************************************************************/ + +static void *tcp_proxy(void *arg) +{ + char buf[1024 * 32]; + + int lis_skt = -1; + int acc_skt = -1; + int con_skt = -1; + int sel = 0; + int rv = 0; + int i = 0; + int count = 0; + int sent = 0; + + /* create listener socket */ + if ((lis_skt = tcp_socket_create()) < 0) + { + show_msg(MAIN_THREAD_NO, MSG_ERROR, "Creating socket", + "\nOperation failed. System out of resources"); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + + /* place it in non blocking mode */ + tcp_set_non_blocking(lis_skt); + + if ((rv = tcp_bind(lis_skt, get_local_port())) != 0) + { + show_msg(MAIN_THREAD_NO, MSG_ERROR, "Bind error", + "\nUnable to bind socket, cannot continue"); + tcp_close(lis_skt); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + + /* listen for incoming connection */ + if (tcp_listen(lis_skt)) + { + show_msg(MAIN_THREAD_NO, MSG_ERROR, "Listen error", + "\nUnable to listen on socket, cannot continue"); + tcp_close(lis_skt); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + + show_status(MAIN_THREAD_NO, "Waiting for client connections"); + + /* accept incoming connection */ + while (g_keep_running) + { + acc_skt = tcp_accept(lis_skt); + if (acc_skt > 0) + { + /* client connected */ + show_status(MAIN_THREAD_NO, "Client connected"); + tcp_close(lis_skt); + lis_skt = -1; + break; + } + if ((acc_skt < 0) && (tcp_last_error_would_block())) + { + /* no connection, try again */ + usleep(250); + continue; + } + else + { + tcp_close(lis_skt); + lis_skt = -1; + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + } + + /* we have a client connection, try connecting to server */ + if ((con_skt = tcp_socket()) < 0) + { + show_msg(MAIN_THREAD_NO, MSG_ERROR, "Creating socket", + "\nOperation failed. System out of resources"); + tcp_close(lis_skt); + tcp_close(acc_skt); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + + /* place it in non blocking mode */ + tcp_set_non_blocking(con_skt); + + rv = tcp_connect(con_skt, get_remote_ip(), get_remote_port()); +#if 0 + if (rv < 0) + { + show_status(MAIN_THREAD_NO, "Could not connect to server"); + tcp_close(lis_skt); + tcp_close(acc_skt); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } +#endif + + if ((rv < 0) && (tcp_last_error_would_block(con_skt))) + { + for (i = 0; i < 100; i++) + { + if (tcp_can_send(con_skt, 100)) + break; + + usleep(100); + } + + if (i == 100) + { + show_status(MAIN_THREAD_NO, "Could not connect to server"); + tcp_close(lis_skt); + tcp_close(acc_skt); + enable_btn_start(MAIN_THREAD_NO); + return NULL; + } + } + + show_status(MAIN_THREAD_NO, "Connected to server"); + rv = 0; + + while (g_keep_running && rv == 0) + { + if ((sel = tcp_select(con_skt, acc_skt)) == 0) + { + usleep(10); + continue; + } + + if (sel & 1) + { + /* can read from con_skt without blocking */ + count = tcp_recv(con_skt, buf, 1024 * 16, 0); + rv = count < 1; + + if (rv == 0) + { + g_loc_io_count += count; + show_loc_port_stats(MAIN_THREAD_NO, g_loc_io_count); + + /* TODO: hexdump data here */ + + sent = 0; + + while ((sent < count) && (rv == 0) && (g_keep_running)) + { + i = tcp_send(acc_skt, buf + sent, count - sent, 0); + + if ((i == -1) && tcp_last_error_would_block(acc_skt)) + { + tcp_can_send(acc_skt, 1000); + } + else if (i < 1) + { + rv = 1; + } + else + { + sent += i; + } + } + } + } + + if (sel & 2) + { + /* can read from acc_skt without blocking */ + count = tcp_recv(acc_skt, buf, 1024 * 16, 0); + rv = count < 1; + + if (rv == 0) + { + g_rem_io_count += count; + show_rem_port_stats(MAIN_THREAD_NO, g_rem_io_count); + + /* TODO: hexdump data here */ + + sent = 0; + + while ((sent < count) && (rv == 0) && (g_keep_running)) + { + i = tcp_send(con_skt, buf + sent, count - sent, 0); + + if ((i == -1) && tcp_last_error_would_block(con_skt)) + { + tcp_can_send(con_skt, 1000); + } + else if (i < 1) + { + rv = 1; + } + else + { + sent += i; + } + } + } + } + } + + tcp_close(lis_skt); + tcp_close(con_skt); + tcp_close(acc_skt); + + show_status(MAIN_THREAD_NO, "Connection closed"); + enable_btn_start(MAIN_THREAD_NO); + return NULL; +} + +/** + * Display a message using specified style dialog + * + * @param style information, warning or error + * @param title text to be displayed in title bar + * @param msg message to be displayed + *****************************************************************************/ + +static void show_msg(int not_main_window, int style, + const gchar *title, const gchar *msg) +{ + GtkWidget *dialog; + + if (not_main_window) + gdk_threads_enter(); + + dialog = gtk_message_dialog_new(GTK_WINDOW(NULL), + GTK_DIALOG_DESTROY_WITH_PARENT, + style, + GTK_BUTTONS_OK, + "%s", msg); + + gtk_window_set_title(GTK_WINDOW(dialog), title); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (not_main_window) + gdk_threads_leave(); +} + +/** + * Write message to status bar + *****************************************************************************/ + +static void show_status(int not_main_thread, char *msg) +{ + if (not_main_thread) + gdk_threads_enter(); + + gtk_statusbar_push(GTK_STATUSBAR(g_statusbar), CONTEXT_ID, msg); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * Clear status bar + *****************************************************************************/ + +static void clear_status(int not_main_thread) +{ + if (not_main_thread) + gdk_threads_enter(); + + gtk_statusbar_remove_all(GTK_STATUSBAR(g_statusbar), CONTEXT_ID); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * Enable 'Start Listening' button + *****************************************************************************/ + +static void enable_btn_start(int not_main_thread) +{ + if (not_main_thread) + gdk_threads_enter(); + + gtk_widget_set_sensitive(GTK_WIDGET(g_btn_start), TRUE); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * Disable 'Start Listening' button + *****************************************************************************/ + +static void disable_btn_start(int not_main_thread) +{ + if (not_main_thread) + gdk_threads_enter(); + + gtk_widget_set_sensitive(GTK_WIDGET(g_btn_start), FALSE); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * Return local port setting + *****************************************************************************/ + +static char *get_local_port() +{ + const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_loc_port)); + return (char *) cptr; +} + +/** + * Return remote IP setting + *****************************************************************************/ + +static char *get_remote_ip() +{ + const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_rem_ip)); + return (char *) cptr; +} + +/** + * Return remote port setting + *****************************************************************************/ + +static char *get_remote_port() +{ + const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_rem_port)); + return (char *) cptr; +} + +/** + * Update local port stat counter + *****************************************************************************/ + +static void show_loc_port_stats(int not_main_thread, int count) +{ + char buf[128]; + + sprintf(buf, "%d", count); + + if (not_main_thread) + gdk_threads_enter(); + + gtk_entry_set_text(GTK_ENTRY(g_tbx_loc_stats), buf); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * Update remote port stat counter + *****************************************************************************/ + +static void show_rem_port_stats(int not_main_thread, int count) +{ + char buf[128]; + + sprintf(buf, "%d", count); + + if (not_main_thread) + gdk_threads_enter(); + + gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_stats), buf); + + if (not_main_thread) + gdk_threads_leave(); +} + +/** + * User clicked on window close button + *****************************************************************************/ + +static gboolean on_delete_event(GtkWidget *widget, GdkEvent *ev, gpointer data) +{ + return FALSE; +} + +/** + * Close application + *****************************************************************************/ + +static void on_destroy(GtkWidget *widget, gpointer data) +{ + /* this will destory all windows and return control to gtk_main() */ + gtk_main_quit(); +} + +/** + * Start a thread that listens for incoming connections + *****************************************************************************/ + +static void on_start_clicked(GtkWidget *widget, gpointer data) +{ + /* local port must be specified */ + if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_loc_port)) == 0) + { + show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", + "\nYou must enter a value for Local Port"); + return; + } + + /* remote IP must be specified */ + if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_rem_ip)) == 0) + { + show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", + "\nYou must enter a value for Remote IP"); + return; + } + + /* remote port must be specified */ + if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_rem_port)) == 0) + { + show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", + "\nYou must enter a value for Remote Port"); + return; + } + + if (pthread_create(&g_tid, NULL, tcp_proxy, NULL)) + { + show_msg(MAIN_THREAD_YES, MSG_ERROR, "Starting listener", + "\nThread create error. System out of resources"); + return; + } + + disable_btn_start(MAIN_THREAD_YES); +} + +/** + * Clear stat counters + *****************************************************************************/ + +static void on_clear_clicked(GtkWidget *widget, gpointer data) +{ + g_loc_io_count = 0; + g_rem_io_count = 0; + show_loc_port_stats(MAIN_THREAD_YES, g_loc_io_count); + show_rem_port_stats(MAIN_THREAD_YES, g_rem_io_count); +} + +/** + * Quit application + *****************************************************************************/ + +static void on_quit_clicked(GtkWidget *widget, gpointer data) +{ + /* this will destory all windows and return control to gtk_main() */ + gtk_main_quit(); +} diff --git a/tests/gtcp_proxy/gtcp.c b/tests/gtcp_proxy/gtcp.c new file mode 100644 index 00000000..9f0fcf88 --- /dev/null +++ b/tests/gtcp_proxy/gtcp.c @@ -0,0 +1,394 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2013 + * + * 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. + */ + +#include "gtcp.h" + +/** + * Return a newly created socket or -1 on error + *****************************************************************************/ + +int tcp_socket_create(void) +{ + int rv; + int option_value; + +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + /* in win32 a socket is an unsigned int, in linux, its an int */ + if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0) + return -1; + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, + &option_len) == 0) + { + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, + option_len); + } + } + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, + &option_len) == 0) + { + if (option_value < (1024 * 32)) + { + option_value = 1024 * 32; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, + option_len); + } + } + + return rv; +} + +/** + * Place specifed socket in non blocking mode + *****************************************************************************/ + +void tcp_set_non_blocking(int skt) +{ + unsigned long i; + +#if defined(_WIN32) + i = 1; + ioctlsocket(skt, FIONBIO, &i); +#else + i = fcntl(skt, F_GETFL); + i = i | O_NONBLOCK; + fcntl(skt, F_SETFL, i); +#endif +} + +/** + * Assign name to socket + * + * @param skt the socket to bind + * @param port the port to bind to + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_bind(int skt, char *port) +{ + struct sockaddr_in s; + + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((uint16_t) atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + + return bind(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in)); +} + +/** + * Listen for incoming connections + * + * @param skt the socket to listen on + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_listen(int skt) +{ + return listen(skt, 2); +} + +/** + * Accept incoming connection + * + * @param skt socket to accept incoming connection on + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_accept(int skt) +{ + int ret ; + char ipAddr[256] ; + struct sockaddr_in s; + +#if defined(_WIN32) + int i; +#else + unsigned int i; +#endif + + i = sizeof(struct sockaddr_in); + memset(&s, 0, i); + return accept(skt, (struct sockaddr *)&s, &i); +} + +/** + * Check if the socket would block + * + * @return TRUE if would block, else FALSE + *****************************************************************************/ + +int tcp_last_error_would_block() +{ +#if defined(_WIN32) + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS); +#endif +} + +/** + * Close specified socket + *****************************************************************************/ + +void tcp_close(int skt) +{ + if (skt <= 0) + return; + +#if defined(_WIN32) + closesocket(skt); +#else + close(skt); +#endif +} + +/** + * Create a new socket + * + * @return new socket or -1 on error + *****************************************************************************/ + +int tcp_socket(void) +{ + int rv; + int option_value; + +#if defined(_WIN32) + int option_len; +#else + unsigned int option_len; +#endif + + /* in win32 a socket is an unsigned int, in linux, its an int */ + if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0) + return -1; + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, + &option_len) == 0) + { + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, + option_len); + } + } + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, + &option_len) == 0) + { + if (option_value < (1024 * 32)) + { + option_value = 1024 * 32; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, + option_len); + } + } + + return rv; +} + +/** + * Connect to a server + * + * @param skt opaque socket obj + * @param address connect to this server + * @param port using this port + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_connect(int skt, const char *hostname, const char *port) +{ + struct sockaddr_in s; + struct hostent *h; + + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((uint16_t) atoi(port)); + s.sin_addr.s_addr = inet_addr(hostname); + + if (s.sin_addr.s_addr == INADDR_NONE) + { + h = gethostbyname(hostname); + + if (h != 0) + { + if (h->h_name != 0) + { + if (h->h_addr_list != 0) + { + if ((*(h->h_addr_list)) != 0) + { + s.sin_addr.s_addr = *((int *)(*(h->h_addr_list))); + } + } + } + } + } + + return connect(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in)); +} + +/** + * Return 1 if we can write to the socket, 0 otherwise + *****************************************************************************/ + +int tcp_can_send(int skt, int millis) +{ + fd_set wfds; + struct timeval time; + int rv; + + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + FD_ZERO(&wfds); + + if (skt > 0) + { + FD_SET(((unsigned int) skt), &wfds); + rv = select(skt + 1, 0, &wfds, 0, &time); + + if (rv > 0) + { + return tcp_socket_ok(skt); + } + } + + return 0; +} + +/** + * Return 1 if socket is OK, 0 otherwise + *****************************************************************************/ + +int tcp_socket_ok(int skt) +{ + int opt; + +#if defined(_WIN32) + int opt_len; +#else + unsigned int opt_len; +#endif + + opt_len = sizeof(opt); + + if (getsockopt(skt, SOL_SOCKET, SO_ERROR, (char *) (&opt), &opt_len) == 0) + { + if (opt == 0) + return 1; + } + + return 0; +} + +/** + * Check if specified sockets can be operated on without blocking + * + * @return 1 if they can be operated on or 0 if blocking would occur + *****************************************************************************/ + +int tcp_select(int sck1, int sck2) +{ + fd_set rfds; + struct timeval time; + + int max = 0; + int rv = 0; + + memset(&rfds, 0, sizeof(fd_set)); + memset(&time, 0, sizeof(struct timeval)); + + time.tv_sec = 0; + time.tv_usec = 0; + FD_ZERO(&rfds); + + if (sck1 > 0) + FD_SET(((unsigned int) sck1), &rfds); + + if (sck2 > 0) + FD_SET(((unsigned int) sck2), &rfds); + + max = sck1; + + if (sck2 > max) + max = sck2; + + rv = select(max + 1, &rfds, 0, 0, &time); + + if (rv > 0) + { + rv = 0; + + if (FD_ISSET(((unsigned int) sck1), &rfds)) + rv = rv | 1; + + if (FD_ISSET(((unsigned int)sck2), &rfds)) + rv = rv | 2; + } + else + { + rv = 0; + } + + return rv; +} + +int tcp_recv(int skt, void *ptr, int len, int flags) +{ +#if defined(_WIN32) + return recv(skt, (char *) ptr, len, flags); +#else + return recv(skt, ptr, len, flags); +#endif +} + +int tcp_send(int skt, const void *ptr, int len, int flags) +{ +#if defined(_WIN32) + return send(skt, (const char *)ptr, len, flags); +#else + return send(skt, ptr, len, flags); +#endif +} diff --git a/tests/gtcp_proxy/gtcp.h b/tests/gtcp_proxy/gtcp.h new file mode 100644 index 00000000..970540ef --- /dev/null +++ b/tests/gtcp_proxy/gtcp.h @@ -0,0 +1,48 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2013 + * + * 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. + */ + +#ifndef _GTCP_H +#define _GTCP_H + +#include <stdint.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> + +int tcp_socket_create(void); +void tcp_set_non_blocking(int skt); +int tcp_bind(int skt, char *port); +int tcp_listen(int skt); +int tcp_accept(int skt); +int tcp_last_error_would_block(); +void tcp_close(int skt); +int tcp_socket(void); +int tcp_connect(int skt, const char *hostname, const char *port); +int tcp_can_send(int skt, int millis); +int tcp_socket_ok(int skt); +int tcp_select(int sck1, int sck2); +int tcp_recv(int skt, void *ptr, int len, int flags); +int tcp_send(int skt, const void *ptr, int len, int flags); + +#endif diff --git a/tests/gtcp_proxy/hexdump.c b/tests/gtcp_proxy/hexdump.c new file mode 100644 index 00000000..c84b1d16 --- /dev/null +++ b/tests/gtcp_proxy/hexdump.c @@ -0,0 +1,130 @@ +/** + * 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. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +/** + * An optimized hexdump function + * + * @param address address to display in address column + * @param buf data to hexdump + * @param len number of bytes to dump + *****************************************************************************/ + +void hexdump(int address, char *buf, int len) +{ + uint32_t addr; + char outbuf[80]; + int blocks; + int residual; + int i; + int j; + int buf_index; + int index2; /* data column */ + int index3; /* ascii column */ + + unsigned char c; + + char cvt[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + if ((buf == NULL) || (len <= 0)) + return; + + addr = (address < 0) ? 0 : address; + blocks = len / 16; + residual = len - blocks * 16; + buf_index = 0; + + for (i = 0; i < blocks; i++) + { + index2 = 10; + index3 = 60; + + outbuf[9] = ' '; + outbuf[8] = ' '; + outbuf[7] = cvt[(addr >> 0) & 0x0000000f]; + outbuf[6] = cvt[(addr >> 4) & 0x0000000f]; + outbuf[5] = cvt[(addr >> 8) & 0x0000000f]; + outbuf[4] = cvt[(addr >> 12) & 0x0000000f]; + outbuf[3] = cvt[(addr >> 16) & 0x0000000f]; + outbuf[2] = cvt[(addr >> 20) & 0x0000000f]; + outbuf[1] = cvt[(addr >> 24) & 0x0000000f]; + outbuf[0] = cvt[(addr >> 28) & 0x0000000f]; + addr += 16; + + /* insert spaces */ + outbuf[8] = ' '; + outbuf[9] = ' '; + outbuf[58] = ' '; + outbuf[59] = ' '; + + for (j = 0; j < 16; j++) + { + c = buf[buf_index++]; + + outbuf[index2++] = cvt[(c >> 4) & 0x0f]; + outbuf[index2++] = cvt[(c >> 0) & 0x0f]; + outbuf[index2++] = ' '; + + if ((c >= 0x20) && (c <= 0x7e)) + outbuf[index3++] = c; + else + outbuf[index3++] = '.'; + } + + outbuf[index3] = 0; + puts(outbuf); + } + + if (!residual) + return; + + outbuf[7] = cvt[(addr >> 0) & 0x0000000f]; + outbuf[6] = cvt[(addr >> 4) & 0x0000000f]; + outbuf[5] = cvt[(addr >> 8) & 0x0000000f]; + outbuf[4] = cvt[(addr >> 12) & 0x0000000f]; + outbuf[3] = cvt[(addr >> 16) & 0x0000000f]; + outbuf[2] = cvt[(addr >> 20) & 0x0000000f]; + outbuf[1] = cvt[(addr >> 24) & 0x0000000f]; + outbuf[0] = cvt[(addr >> 28) & 0x0000000f]; + addr += 16; + + index2 = 10; + index3 = 60; + memset(&outbuf[8], ' ', 68); + + for (j = 0; j < residual; j++) + { + c = buf[buf_index++]; + + outbuf[index2++] = cvt[(c >> 4) & 0x0f]; + outbuf[index2++] = cvt[(c >> 0) & 0x0f]; + outbuf[index2++] = ' '; + + if ((c >= 0x20) && (c <= 0x7e)) + outbuf[index3++] = c; + else + outbuf[index3++] = '.'; + } + + outbuf[index3] = 0; + puts(outbuf); +} diff --git a/xorg/X11R7.6/buildx.sh b/xorg/X11R7.6/buildx.sh index a3ac4fc5..3b2bad78 100755 --- a/xorg/X11R7.6/buildx.sh +++ b/xorg/X11R7.6/buildx.sh @@ -34,41 +34,109 @@ download_file() fi echo "downloading file $file" - case "$file" in - pixman-0.15.20.tar.bz2) - url=http://ftp.x.org/pub/individual/lib/$file ;; - libdrm-2.4.26.tar.bz2) - url=http://dri.freedesktop.org/libdrm/$file ;; - MesaLib-7.10.3.tar.bz2) - url=ftp://ftp.freedesktop.org/pub/mesa/7.10.3/$file ;; - freetype-2.4.6.tar.bz2) - url=http://download.savannah.gnu.org/releases/freetype/$file ;; - xkeyboard-config-2.0.tar.bz2) - url=http://www.x.org/releases/individual/data/xkeyboard-config/$file ;; - makedepend-1.0.3.tar.bz2) - url=http://xorg.freedesktop.org/releases/individual/util/$file ;; - libxml2-sources-2.7.8.tar.gz) - url=ftp://ftp.xmlsoft.org/libxml2/$file ;; - Python-2.5.tar.bz2) - url=http://www.python.org/ftp/python/2.5/$file ;; - Python-2.7.tar.bz2) - url=http://www.python.org/ftp/python/2.7/$file ;; - expat-2.0.1.tar.gz) - url=http://server1.xrdp.org/xrdp/$file ;; - cairo-1.8.8.tar.gz) - url=http://server1.xrdp.org/xrdp/$file ;; - libpng-1.2.46.tar.gz) - url=http://server1.xrdp.org/xrdp/$file ;; - intltool-0.41.1.tar.gz) - url=http://launchpad.net/intltool/trunk/0.41.1/+download/$file ;; - libxslt-1.1.26.tar.gz) - url=ftp://xmlsoft.org/libxslt/$file ;; - fontconfig-2.8.0.tar.gz) - url=http://server1.xrdp.org/xrdp/$file ;; - *) - url=$download_url/$file ;; - esac - wget -cqP downloads "url" + + if [ "$file" = "libpthread-stubs-0.3.tar.bz2" ]; then + wget -cq http://xcb.freedesktop.org/dist/$file + status=$? + cd .. + return $status + elif [ "$file" = "libxcb-1.7.tar.bz2" ]; then + wget -cq http://xcb.freedesktop.org/dist/$file + status=$? + cd .. + return $status + elif [ "$file" = "xcb-proto-1.6.tar.bz2" ]; then + wget -cq http://xcb.freedesktop.org/dist/$file + status=$? + cd .. + return $status + elif [ "$file" = "pixman-0.15.20.tar.bz2" ]; then + wget -cq http://ftp.x.org/pub/individual/lib/$file + status=$? + cd .. + return $status + elif [ "$file" = "libdrm-2.4.26.tar.bz2" ]; then + wget -cq http://dri.freedesktop.org/libdrm/$file + status=$? + cd .. + return $status + elif [ "$file" = "MesaLib-7.10.3.tar.bz2" ]; then + wget -cq ftp://ftp.freedesktop.org/pub/mesa/7.10.3/$file + status=$? + cd .. + return $status + elif [ "$file" = "expat-2.0.1.tar.gz" ]; then + wget -cq http://server1.xrdp.org/xrdp/expat-2.0.1.tar.gz + + status=$? + cd .. + return $status + elif [ "$file" = "freetype-2.4.6.tar.bz2" ]; then + wget -cq http://download.savannah.gnu.org/releases/freetype/freetype-2.4.6.tar.bz2 + status=$? + cd .. + return $status + elif [ "$file" = "xkeyboard-config-2.0.tar.bz2" ]; then + wget -cq http://www.x.org/releases/individual/data/xkeyboard-config/xkeyboard-config-2.0.tar.bz2 + status=$? + cd .. + return $status + elif [ "$file" = "makedepend-1.0.3.tar.bz2" ]; then + wget -cq http://xorg.freedesktop.org/releases/individual/util/makedepend-1.0.3.tar.bz2 + status=$? + cd .. + return $status + elif [ "$file" = "libxml2-sources-2.7.8.tar.gz" ]; then + wget -cq ftp://ftp.xmlsoft.org/libxml2/libxml2-sources-2.7.8.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "Python-2.5.tar.bz2" ]; then + wget -cq http://www.python.org/ftp/python/2.5/Python-2.5.tar.bz2 + status=$? + cd .. + return $status + elif [ "$file" = "Python-2.7.tar.bz2" ]; then + wget -cq http://www.python.org/ftp/python/2.7/Python-2.7.tar.bz2 + status=$? + cd .. + return $status + elif [ "$file" = "expat-2.0.1.tar.gz" ]; then + wget -cq http://server1.xrdp.org/xrdp/expat-2.0.1.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "cairo-1.8.8.tar.gz" ]; then + wget -cq http://server1.xrdp.org/xrdp/cairo-1.8.8.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "libpng-1.2.46.tar.gz" ]; then + wget -cq http://server1.xrdp.org/xrdp/libpng-1.2.46.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "intltool-0.41.1.tar.gz" ]; then + wget -cq http://launchpad.net/intltool/trunk/0.41.1/+download/intltool-0.41.1.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "libxslt-1.1.26.tar.gz" ]; then + wget -cq ftp://xmlsoft.org/libxslt/libxslt-1.1.26.tar.gz + status=$? + cd .. + return $status + elif [ "$file" = "fontconfig-2.8.0.tar.gz" ]; then + wget -cq http://server1.xrdp.org/xrdp/fontconfig-2.8.0.tar.gz + status=$? + cd .. + return $status + else + wget -cq $download_url/$file + status=$? + cd .. + return $status + fi } remove_modules() diff --git a/xorg/X11R7.6/rdp/rdp.h b/xorg/X11R7.6/rdp/rdp.h index 920fe25d..ae08f38d 100644 --- a/xorg/X11R7.6/rdp/rdp.h +++ b/xorg/X11R7.6/rdp/rdp.h @@ -1,5 +1,5 @@ /* -Copyright 2005-2012 Jay Sorg +Copyright 2005-2013 Jay Sorg Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that @@ -500,6 +500,8 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h); int rdpup_set_cursor(short x, short y, char* cur_data, char* cur_mask); int +rdpup_set_cursor_ex(short x, short y, char *cur_data, char *cur_mask, int bpp); +int rdpup_create_os_surface(int rdpindexd, int width, int height); int rdpup_switch_os_surface(int rdpindex); diff --git a/xorg/X11R7.6/rdp/rdpCopyArea.c b/xorg/X11R7.6/rdp/rdpCopyArea.c index 0a5e5206..300f857d 100644 --- a/xorg/X11R7.6/rdp/rdpCopyArea.c +++ b/xorg/X11R7.6/rdp/rdpCopyArea.c @@ -81,9 +81,6 @@ rdpCopyAreaWndToWnd(WindowPtr pSrcWnd, WindowPtr pDstWnd, GCPtr pGC, RegionRec clip_reg; LLOGLN(10, ("rdpCopyAreaWndToWnd:")); - - rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstWnd->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); lsrcx = pSrcWnd->drawable.x + srcx; @@ -104,14 +101,16 @@ rdpCopyAreaWndToWnd(WindowPtr pSrcWnd, WindowPtr pDstWnd, GCPtr pGC, if (num_clips > 0) { rdpup_begin_update(); - dx = dstx - srcx; - dy = dsty - srcy; + dx = ldstx - lsrcx; + dy = ldsty - lsrcy; if ((dy < 0) || ((dy == 0) && (dx < 0))) { for (j = 0; j < num_clips; j++) { box = REGION_RECTS(&clip_reg)[j]; + LLOGLN(10, (" index %d x1 %d y1 %d x2 %d y2 %d", j, + box.x1, box.y1, box.x2, box.y2)); rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); } @@ -121,6 +120,8 @@ rdpCopyAreaWndToWnd(WindowPtr pSrcWnd, WindowPtr pDstWnd, GCPtr pGC, for (j = num_clips - 1; j >= 0; j--) { box = REGION_RECTS(&clip_reg)[j]; + LLOGLN(10, (" index %d x1 %d y1 %d x2 %d y2 %d", j, + box.x1, box.y1, box.x2, box.y2)); rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); } @@ -132,6 +133,8 @@ rdpCopyAreaWndToWnd(WindowPtr pSrcWnd, WindowPtr pDstWnd, GCPtr pGC, } RegionUninit(&clip_reg); + rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstWnd->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); return rv; } @@ -148,17 +151,12 @@ rdpCopyAreaWndToPixmap(WindowPtr pSrcWnd, int ldstx; int ldsty; int num_clips; - int dx; - int dy; int j; BoxRec box; RegionPtr rv; RegionRec clip_reg; LLOGLN(10, ("rdpCopyAreaWndToPixmap:")); - - rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstPixmap->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); lsrcx = pSrcWnd->drawable.x + srcx; @@ -182,26 +180,12 @@ rdpCopyAreaWndToPixmap(WindowPtr pSrcWnd, { rdpup_switch_os_surface(pDstPriv->rdpindex); rdpup_begin_update(); - dx = dstx - srcx; - dy = dsty - srcy; - if ((dy < 0) || ((dy == 0) && (dx < 0))) - { - for (j = 0; j < num_clips; j++) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } - } - else + for (j = 0; j < num_clips; j++) { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); } rdpup_reset_clip(); @@ -211,6 +195,8 @@ rdpCopyAreaWndToPixmap(WindowPtr pSrcWnd, } RegionUninit(&clip_reg); + rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstPixmap->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); return rv; } @@ -234,9 +220,6 @@ rdpCopyAreaPixmapToWnd(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, BoxRec box; LLOGLN(10, ("rdpCopyAreaPixmapToWnd:")); - - rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstWnd->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); ldstx = pDstWnd->drawable.x + dstx; @@ -274,6 +257,8 @@ rdpCopyAreaPixmapToWnd(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, } RegionUninit(&clip_reg); + rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstWnd->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); return rv; } @@ -292,14 +277,13 @@ rdpCopyAreaPixmapToPixmap(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, int cd; int j; int num_clips; + int dx; + int dy; RegionPtr rv; RegionRec clip_reg; BoxRec box; LLOGLN(10, ("rdpCopyAreaPixmapToPixmap:")); - - rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstPixmap->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); RegionInit(&clip_reg, NullBox, 0); cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: cd %d", cd)); @@ -325,14 +309,30 @@ rdpCopyAreaPixmapToPixmap(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, { rdpup_switch_os_surface(pDstPriv->rdpindex); rdpup_begin_update(); + dx = ldstx - lsrcx; + dy = ldsty - lsrcy; + LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: num_clips %d", num_clips)); - for (j = 0; j < num_clips; j++) + if ((dy < 0) || ((dy == 0) && (dx < 0))) { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); - LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); + for (j = 0; j < num_clips; j++) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); + LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); + } + } + else + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); + LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); + } } rdpup_reset_clip(); @@ -342,6 +342,8 @@ rdpCopyAreaPixmapToPixmap(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, } RegionUninit(&clip_reg); + rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstPixmap->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); return rv; } diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index a0cc2f0f..e711733b 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -524,7 +524,7 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) } #endif -#if 1 +#if 0 /* subtract regions */ if (priv->draw_item_tail != 0) @@ -559,6 +559,7 @@ draw_item_pack(PixmapPtr pix, rdpPixmapRec *priv) #endif #if 1 + /* remove draw items with empty regions */ di = priv->draw_item_head; di_prev = 0; @@ -738,7 +739,8 @@ xrdp_is_os(PixmapPtr pix, rdpPixmapPtr priv) { width = pix->drawable.width; height = pix->drawable.height; - if ((pix->drawable.depth >= g_rdpScreen.depth) && + if ((pix->usage_hint == 0) && + (pix->drawable.depth >= g_rdpScreen.depth) && (width > 1) && (height > 1) && (priv->kind_width > 0)) { LLOGLN(10, ("%d %d", priv->kind_width, pix->drawable.width)); @@ -1242,8 +1244,6 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, int post_process; int reset_surface; int got_id; - int lx; - int ly; WindowPtr pDstWnd; PixmapPtr pDstPixmap; rdpPixmapRec *pDstPriv; @@ -1324,7 +1324,7 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, return; } - if (pDst->clientClipType == CT_REGION) + if (pDst->pCompositeClip != 0) { box.x1 = p->x + xDst; box.y1 = p->y + yDst; @@ -1332,10 +1332,7 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, box.y2 = box.y1 + height; RegionInit(®1, &box, 0); RegionInit(®2, NullBox, 0); - RegionCopy(®2, pDst->clientClip); - lx = p->x + pDst->clipOrigin.x; - ly = p->y + pDst->clipOrigin.y; - RegionTranslate(®2, lx, ly); + RegionCopy(®2, pDst->pCompositeClip); RegionIntersect(®1, ®1, ®2); if (dirty_type != 0) diff --git a/xorg/X11R7.6/rdp/rdpinput.c b/xorg/X11R7.6/rdp/rdpinput.c index cefb5156..39cd78dd 100644 --- a/xorg/X11R7.6/rdp/rdpinput.c +++ b/xorg/X11R7.6/rdp/rdpinput.c @@ -1,5 +1,5 @@ /* -Copyright 2005-2012 Jay Sorg +Copyright 2005-2013 Jay Sorg Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that @@ -47,6 +47,7 @@ keyboard and mouse stuff extern ScreenPtr g_pScreen; /* in rdpmain.c */ extern DeviceIntPtr g_pointer; /* in rdpmain.c */ extern DeviceIntPtr g_keyboard; /* in rdpmain.c */ +extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ static int g_old_button_mask = 0; static int g_pause_spe = 0; @@ -519,6 +520,7 @@ get_pixel_safe(char *data, int x, int y, int width, int height, int bpp) int start; int shift; int c; + unsigned int *src32; if (x < 0) { @@ -552,6 +554,11 @@ get_pixel_safe(char *data, int x, int y, int width, int height, int bpp) return (c & (0x80 >> shift)) != 0; #endif } + else if (bpp == 32) + { + src32 = (unsigned int*)data; + return src32[y * width + x]; + } return 0; } @@ -563,6 +570,7 @@ set_pixel_safe(char *data, int x, int y, int width, int height, int bpp, { int start; int shift; + unsigned int *dst32; if (x < 0) { @@ -605,6 +613,11 @@ set_pixel_safe(char *data, int x, int y, int width, int height, int bpp, *(data + (3 * (y * width + x)) + 1) = pixel >> 8; *(data + (3 * (y * width + x)) + 2) = pixel >> 16; } + else if (bpp == 32) + { + dst32 = (unsigned int*)data; + dst32[y * width + x] = pixel; + } } /******************************************************************************/ @@ -612,7 +625,7 @@ void rdpSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs, int x, int y) { - char cur_data[32 * (32 * 3)]; + char cur_data[32 * (32 * 4)]; char cur_mask[32 * (32 / 8)]; char *mask; char *data; @@ -626,6 +639,7 @@ rdpSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs, int paddedRowBytes; int fgcolor; int bgcolor; + int bpp; if (pCurs == 0) { @@ -639,39 +653,62 @@ rdpSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs, w = pCurs->bits->width; h = pCurs->bits->height; - paddedRowBytes = PixmapBytePad(w, 1); - xhot = pCurs->bits->xhot; - yhot = pCurs->bits->yhot; - /* ErrorF("xhot %d yhot %d\n", xhot, yhot); */ - data = (char *)(pCurs->bits->source); - mask = (char *)(pCurs->bits->mask); - fgcolor = (((pCurs->foreRed >> 8) & 0xff) << 16) | - (((pCurs->foreGreen >> 8) & 0xff) << 8) | - ((pCurs->foreBlue >> 8) & 0xff); - bgcolor = (((pCurs->backRed >> 8) & 0xff) << 16) | - (((pCurs->backGreen >> 8) & 0xff) << 8) | - ((pCurs->backBlue >> 8) & 0xff); - memset(cur_data, 0, sizeof(cur_data)); - memset(cur_mask, 0, sizeof(cur_mask)); - - for (j = 0; j < 32; j++) + if ((pCurs->bits->argb != 0) && + (g_rdpScreen.client_info.pointer_flags & 1)) { - for (i = 0; i < 32; i++) + bpp = 32; + paddedRowBytes = PixmapBytePad(w, 32); + xhot = pCurs->bits->xhot; + yhot = pCurs->bits->yhot; + data = (char *)(pCurs->bits->argb); + memset(cur_data, 0, sizeof(cur_data)); + memset(cur_mask, 0, sizeof(cur_mask)); + + for (j = 0; j < 32; j++) { - p = get_pixel_safe(mask, i, j, paddedRowBytes * 8, h, 1); - set_pixel_safe(cur_mask, i, 31 - j, 32, 32, 1, !p); - - if (p != 0) + for (i = 0; i < 32; i++) { - p = get_pixel_safe(data, i, j, paddedRowBytes * 8, h, 1); - p = p ? fgcolor : bgcolor; - set_pixel_safe(cur_data, i, 31 - j, 32, 32, 24, p); + p = get_pixel_safe(data, i, j, paddedRowBytes / 4, h, 32); + set_pixel_safe(cur_data, i, 31 - j, 32, 32, 32, p); + } + } + } + else + { + bpp = 0; + paddedRowBytes = PixmapBytePad(w, 1); + xhot = pCurs->bits->xhot; + yhot = pCurs->bits->yhot; + data = (char *)(pCurs->bits->source); + mask = (char *)(pCurs->bits->mask); + fgcolor = (((pCurs->foreRed >> 8) & 0xff) << 16) | + (((pCurs->foreGreen >> 8) & 0xff) << 8) | + ((pCurs->foreBlue >> 8) & 0xff); + bgcolor = (((pCurs->backRed >> 8) & 0xff) << 16) | + (((pCurs->backGreen >> 8) & 0xff) << 8) | + ((pCurs->backBlue >> 8) & 0xff); + memset(cur_data, 0, sizeof(cur_data)); + memset(cur_mask, 0, sizeof(cur_mask)); + + for (j = 0; j < 32; j++) + { + for (i = 0; i < 32; i++) + { + p = get_pixel_safe(mask, i, j, paddedRowBytes * 8, h, 1); + set_pixel_safe(cur_mask, i, 31 - j, 32, 32, 1, !p); + + if (p != 0) + { + p = get_pixel_safe(data, i, j, paddedRowBytes * 8, h, 1); + p = p ? fgcolor : bgcolor; + set_pixel_safe(cur_data, i, 31 - j, 32, 32, 24, p); + } } } } rdpup_begin_update(); - rdpup_set_cursor(xhot, yhot, cur_data, cur_mask); + rdpup_set_cursor_ex(xhot, yhot, cur_data, cur_mask, bpp); rdpup_end_update(); } diff --git a/xorg/X11R7.6/rdp/rdprandr.c b/xorg/X11R7.6/rdp/rdprandr.c index 832d86d4..45e3ecf4 100644 --- a/xorg/X11R7.6/rdp/rdprandr.c +++ b/xorg/X11R7.6/rdp/rdprandr.c @@ -176,7 +176,7 @@ rdpRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, pScreen->root->drawable.width = width; pScreen->root->drawable.height = height; ResizeChildrenWinSize(pScreen->root, 0, 0, 0, 0); - RRScreenSizeNotify(pScreen); + RRGetInfo(pScreen, 1); rdpInvalidateArea(g_pScreen, 0, 0, g_rdpScreen.width, g_rdpScreen.height); ErrorF(" screen resized to %dx%d\n", pScreen->width, pScreen->height); diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index d1d654de..78263b55 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -1,5 +1,5 @@ /* -Copyright 2005-2012 Jay Sorg +Copyright 2005-2013 Jay Sorg Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that @@ -1367,6 +1367,36 @@ rdpup_set_cursor(short x, short y, char *cur_data, char *cur_mask) /******************************************************************************/ int +rdpup_set_cursor_ex(short x, short y, char *cur_data, char *cur_mask, int bpp) +{ + int size; + int Bpp; + + if (g_connected) + { + LLOGLN(10, (" rdpup_set_cursor_ex")); + Bpp = (bpp == 0) ? 3 : (bpp + 7) / 8; + size = 10 + 32 * (32 * Bpp) + 32 * (32 / 8); + rdpup_pre_check(size); + out_uint16_le(g_out_s, 51); /* set cursor ex */ + out_uint16_le(g_out_s, size); /* size */ + g_count++; + x = MAX(0, x); + x = MIN(31, x); + y = MAX(0, y); + y = MIN(31, y); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, bpp); + out_uint8a(g_out_s, cur_data, 32 * (32 * Bpp)); + out_uint8a(g_out_s, cur_mask, 32 * (32 / 8)); + } + + return 0; +} + +/******************************************************************************/ +int rdpup_create_os_surface(int rdpindex, int width, int height) { LLOGLN(10, ("rdpup_create_os_surface:")); diff --git a/xorg/debuild/debX11rdp.sh b/xorg/debuild/debX11rdp.sh new file mode 100755 index 00000000..23b1428e --- /dev/null +++ b/xorg/debuild/debX11rdp.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# receives version, release number and source directory as arguments + +VERSION=$1 +RELEASE=$2 +SRCDIR=$3 +PKGDEST=$4 + +PACKDIR=x11rdp-files +DESTDIR=$PACKDIR/opt +NAME=x11rdp +ARCH=$( dpkg --print-architecture ) + + +sed -i -e "s/DUMMYVERINFO/$VERSION-$RELEASE/" $PACKDIR/DEBIAN/control +sed -i -e "s/DUMMYARCHINFO/$ARCH/" $PACKDIR/DEBIAN/control +# need a different delimiter, since it has a path +sed -i -e "s,DUMMYDIRINFO,$SRCDIR," $PACKDIR/DEBIAN/postinst + +mkdir -p $DESTDIR +cp -Rf $SRCDIR $DESTDIR +dpkg-deb --build $PACKDIR $PKGDEST/${NAME}_$VERSION-${RELEASE}_${ARCH}.deb + +# revert to initial state +rm -rf $DESTDIR +sed -i -e "s/$VERSION-$RELEASE/DUMMYVERINFO/" $PACKDIR/DEBIAN/control +sed -i -e "s/$ARCH/DUMMYARCHINFO/" $PACKDIR/DEBIAN/control +# need a different delimiter, since it has a path +sed -i -e "s,$SRCDIR,DUMMYDIRINFO," $PACKDIR/DEBIAN/postinst diff --git a/xorg/debuild/x11rdp-files/DEBIAN/control b/xorg/debuild/x11rdp-files/DEBIAN/control new file mode 100644 index 00000000..149e9a83 --- /dev/null +++ b/xorg/debuild/x11rdp-files/DEBIAN/control @@ -0,0 +1,7 @@ +Package: x11rdp +Version: DUMMYVERINFO +Section: unknown +Priority: optional +Architecture: DUMMYARCHINFO +Maintainer: Angulo Solido <packaging@angulosolido.pt> +Description: X11rdp backend for the xrdp remote access server diff --git a/xorg/debuild/x11rdp-files/DEBIAN/postinst b/xorg/debuild/x11rdp-files/DEBIAN/postinst new file mode 100755 index 00000000..241103af --- /dev/null +++ b/xorg/debuild/x11rdp-files/DEBIAN/postinst @@ -0,0 +1,18 @@ +#!/bin/bash + +X11DIR=DUMMYDIRINFO + +# make the /usr/bin/X11rdp symbolic link if it doesn't exist... +if [ ! -e /usr/bin/X11rdp ] +then + if [ -e $X11DIR/bin/X11rdp ] + then + ln -s $X11DIR/bin/X11rdp /usr/bin/X11rdp + else + clear + echo "There was a problem... the $X11DIR/bin/X11rdp binary could not be found. Did the compilation complete?" + echo "Stopped. Please investigate what went wrong." + exit + fi +fi + diff --git a/xorg/tests/randr/Makefile b/xorg/tests/randr/Makefile new file mode 100644 index 00000000..3ab4280c --- /dev/null +++ b/xorg/tests/randr/Makefile @@ -0,0 +1,11 @@ + +CFLAGS = -O2 -Wall + +all: test-randr + +test-randr: trandr.c + gcc $(CFLAGS) trandr.c -o test-randr -lX11 -lXrandr + +.PHONY clean: + rm -f *.o test-randr + diff --git a/xorg/tests/randr/trandr.c b/xorg/tests/randr/trandr.c new file mode 100644 index 00000000..77ce2c33 --- /dev/null +++ b/xorg/tests/randr/trandr.c @@ -0,0 +1,138 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2013 + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <signal.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/Xrandr.h> + +static int +process_randr(Display *disp, Window win, int event_base, XEvent *ev) +{ + XRRScreenChangeNotifyEvent *rr_screen_change_notify; + + switch (ev->type - event_base) + { + case RRScreenChangeNotify: + rr_screen_change_notify = (XRRScreenChangeNotifyEvent *) ev; + printf("RRScreenChangeNotify: width %d height %d\n", + rr_screen_change_notify->width, + rr_screen_change_notify->height); + break; + } + return 0; +} + +int +main(int argc, char **argv) +{ + XEvent ev; + Display *disp; + Window win; + Window root_window; + Screen *screen; + int screenNumber; + int eventMask; + int white; + int black; + int rr_event_base; + int rr_error_base; + int ver_maj; + int ver_min; + int cont; + + disp = XOpenDisplay(0); + if (disp == 0) + { + printf("error opening display\n"); + return 1; + } + screenNumber = DefaultScreen(disp); + white = WhitePixel(disp, screenNumber); + black = BlackPixel(disp, screenNumber); + + screen = ScreenOfDisplay(disp, screenNumber); + root_window = RootWindowOfScreen(screen); + + eventMask = StructureNotifyMask; + XSelectInput(disp, root_window, eventMask); + + win = XCreateSimpleWindow(disp, root_window, 50, 50, 250, 250, + 0, black, white); + + XMapWindow(disp, win); + eventMask = StructureNotifyMask | VisibilityChangeMask; + XSelectInput(disp, win, eventMask); + + eventMask = KeyPressMask | KeyReleaseMask | ButtonPressMask | + ButtonReleaseMask | VisibilityChangeMask | + FocusChangeMask | StructureNotifyMask | + PointerMotionMask | ExposureMask | PropertyChangeMask; + XSelectInput(disp, win, eventMask); + + if (!XRRQueryExtension(disp, &rr_event_base, &rr_error_base)) + { + printf("error randr\n"); + return 1; + } + XRRQueryVersion(disp, &ver_maj, &ver_min); + printf("randr version %d %d\n", ver_maj, ver_min); + + XRRSelectInput(disp, win, RRScreenChangeNotifyMask); + + cont = 1; + while (cont) + { + XNextEvent(disp, &ev); + switch (ev.type) + { + case ButtonPress: + cont = 0; + break; + case ClientMessage: + printf("ClientMessage\n"); + break; + case ConfigureNotify: + if (ev.xconfigure.window == root_window) + { + printf("ConfigureNotify for root window width %d height %d\n", + ev.xconfigure.width, ev.xconfigure.height); + } + break; + default: + if ((ev.type >= rr_event_base) && + (ev.type < rr_event_base + RRNumberEvents)) + { + printf("randr\n"); + process_randr(disp, win, rr_event_base, &ev); + } + break; + } + } + + return 0; +}
\ No newline at end of file diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index b755bbeb..ac3b7fe0 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = xrdp.ini rsakeys.ini ad24b.bmp ad256.bmp xrdp24b.bmp xrdp256.bmp sans-10.fv1 cursor0.cur cursor1.cur xrdp.h xrdp_types.h +EXTRA_DIST = xrdp.ini ad24b.bmp ad256.bmp xrdp24b.bmp xrdp256.bmp sans-10.fv1 cursor0.cur cursor1.cur xrdp.h xrdp_types.h if XRDP_DEBUG EXTRA_DEFINES = -DXRDP_DEBUG @@ -11,9 +11,11 @@ AM_CFLAGS = \ -DXRDP_SBIN_PATH=\"${sbindir}\" \ -DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ + -DXRDP_LIB_PATH=\"${libdir}\" \ $(EXTRA_DEFINES) INCLUDES = \ + -I$(top_builddir) \ -I$(top_srcdir)/common \ -I$(top_srcdir)/libxrdp @@ -42,8 +44,7 @@ xrdp_LDADD = \ xrdpsysconfdir=$(sysconfdir)/xrdp xrdpsysconf_DATA = \ - xrdp.ini \ - rsakeys.ini + xrdp.ini xrdppkgdatadir=$(datadir)/xrdp @@ -56,6 +57,3 @@ xrdppkgdata_DATA = \ cursor0.cur \ cursor1.cur -# must be tab below -install-data-hook: - chmod 600 $(DESTDIR)$(sysconfdir)/xrdp/rsakeys.ini diff --git a/xrdp/funcs.c b/xrdp/funcs.c index 82662fa9..cd2ccf16 100644 --- a/xrdp/funcs.c +++ b/xrdp/funcs.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/xrdp/lang.c b/xrdp/lang.c index 29031ea2..24dafb6a 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,9 +71,9 @@ get_key_info_from_scan_code(int device_flags, int scan_code, int *keys, int ext; int index; - ext = device_flags &KBD_FLAG_EXT; /* 0x0100 */ + ext = device_flags & KBD_FLAG_EXT; /* 0x0100 */ shift = keys[42] || keys[54]; - altgr = keys[56] &KBD_FLAG_EXT; /* right alt */ + altgr = keys[56] & KBD_FLAG_EXT; /* right alt */ rv = 0; scan_code = scan_code & 0x7f; index = ext ? g_map[scan_code].code2 : g_map[scan_code].code1; diff --git a/xrdp/xrdp.c b/xrdp/xrdp.c index fb6fd5dd..0c340e55 100644 --- a/xrdp/xrdp.c +++ b/xrdp/xrdp.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -177,7 +177,7 @@ void DEFAULT_CC pipe_sig(int sig_num) { /* do nothing */ - g_writeln("got SIGPIPE(%d)", sig_num); + g_writeln("got XRDP SIGPIPE(%d)", sig_num); } /*****************************************************************************/ @@ -306,9 +306,9 @@ main(int argc, char **argv) g_init("xrdp"); ssl_init(); - for (test=0;test<argc; test++) + for (test = 0; test < argc; test++) { - DEBUG(("Argument %i - %s",test,argv[test])); + DEBUG(("Argument %i - %s", test, argv[test])); } /* check compiled endian with actual endian */ @@ -435,7 +435,7 @@ main(int argc, char **argv) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("Copyright (C) Jay Sorg 2004-2013"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln(""); g_writeln("Usage: xrdp [options]"); @@ -453,7 +453,7 @@ main(int argc, char **argv) { g_writeln(""); g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("Copyright (C) Jay Sorg 2004-2013"); g_writeln("See http://xrdp.sourceforge.net for more information."); g_writeln("Version %s", PACKAGE_VERSION); g_writeln(""); diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index a98acb16..99d5743b 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,9 +126,10 @@ int APP_CC xrdp_wm_pu(struct xrdp_wm* self, struct xrdp_bitmap* control); int APP_CC xrdp_wm_send_pointer(struct xrdp_wm* self, int cache_idx, - char* data, char* mask, int x, int y); + char* data, char* mask, int x, int y, int bpp); int APP_CC -xrdp_wm_pointer(struct xrdp_wm* self, char* data, char* mask, int x, int y); +xrdp_wm_pointer(struct xrdp_wm* self, char* data, char* mask, int x, int y, + int bpp); int callback(long id, int msg, long param1, long param2, long param3, long param4); int APP_CC @@ -376,6 +377,9 @@ int DEFAULT_CC server_set_pointer(struct xrdp_mod* mod, int x, int y, char* data, char* mask); int DEFAULT_CC +server_set_pointer_ex(struct xrdp_mod* mod, int x, int y, + char* data, char* mask, int bpp); +int DEFAULT_CC server_palette(struct xrdp_mod* mod, int* palette); int DEFAULT_CC server_msg(struct xrdp_mod* mod, char* msg, int code); diff --git a/xrdp/xrdp.ini b/xrdp/xrdp.ini index b0127d01..bdf1b177 100644 --- a/xrdp/xrdp.ini +++ b/xrdp/xrdp.ini @@ -4,7 +4,7 @@ bitmap_cache=yes bitmap_compression=yes port=3389 crypt_level=low -channel_code=1 +allow_channels=true max_bpp=24 fork=yes # regulate if the listening socket use socket option tcp_nodelay @@ -25,6 +25,8 @@ tcp_keepalive=yes #autorun=xrdp1 #hidelogwindow=yes #bulk_compression=yes +# You can set the PAM error text in a gateway setup (MAX 256 chars) +#pamerrortxt=change your password according to policy at http://url [Logging] LogFile=xrdp.log @@ -38,6 +40,8 @@ SyslogLevel=DEBUG # You can block any channel by setting its value to false. # IMPORTANT! All channels are not supported in all use # cases even if you set all values to true. +# You can override these settings on each session type +# These settings are only used if allow_channels=true rdpdr=true rdpsnd=true drdynvc=true @@ -45,6 +49,12 @@ cliprdr=true rail=true xrdpvr=true +# for debugging xrdp, in section xrdp1, change port=-1 to this: +# port=/tmp/.xrdp/xrdp_display_10 + +# for debugging xrdp, add following line to section xrdp1 +# chansrvport=/tmp/.xrdp/xrdp_chansrv_socket_7210 + [xrdp1] name=sesman-X11rdp lib=libxup.so @@ -53,6 +63,7 @@ password=ask ip=127.0.0.1 port=-1 xserverbpp=24 +code=10 [xrdp2] name=sesman-Xvnc @@ -102,10 +113,10 @@ ip=ask port=ask3389 username=ask password=ask - -channel.rdpdr=true -channel.rdpsnd=true -channel.drdynvc=true -channel.cliprdr=true -channel.rail=true -channel.xrdpvr=true +# You can override the common channel settings for each session type +#channel.rdpdr=true +#channel.rdpsnd=true +#channel.drdynvc=true +#channel.cliprdr=true +#channel.rail=true +#channel.xrdpvr=true diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index d60cc920..19620c40 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index dfc7e60b..cac7f114 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ */ #include "xrdp.h" +#include "log.h" /*****************************************************************************/ struct xrdp_cache *APP_CC @@ -224,7 +225,7 @@ xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, } else { - g_writeln("error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); + log_message(LOG_LEVEL_ERROR,"error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); } /* look for oldest */ @@ -474,9 +475,10 @@ xrdp_cache_add_pointer(struct xrdp_cache *self, if (self->pointer_items[i].x == pointer_item->x && self->pointer_items[i].y == pointer_item->y && g_memcmp(self->pointer_items[i].data, - pointer_item->data, 32 * 32 * 3) == 0 && + pointer_item->data, 32 * 32 * 4) == 0 && g_memcmp(self->pointer_items[i].mask, - pointer_item->mask, 32 * 32 / 8) == 0) + pointer_item->mask, 32 * 32 / 8) == 0 && + self->pointer_items[i].bpp == pointer_item->bpp) { self->pointer_items[i].stamp = self->pointer_stamp; xrdp_wm_set_pointer(self->wm, i); @@ -502,15 +504,17 @@ xrdp_cache_add_pointer(struct xrdp_cache *self, self->pointer_items[index].x = pointer_item->x; self->pointer_items[index].y = pointer_item->y; g_memcpy(self->pointer_items[index].data, - pointer_item->data, 32 * 32 * 3); + pointer_item->data, 32 * 32 * 4); g_memcpy(self->pointer_items[index].mask, pointer_item->mask, 32 * 32 / 8); self->pointer_items[index].stamp = self->pointer_stamp; + self->pointer_items[index].bpp = pointer_item->bpp; xrdp_wm_send_pointer(self->wm, index, self->pointer_items[index].data, self->pointer_items[index].mask, self->pointer_items[index].x, - self->pointer_items[index].y); + self->pointer_items[index].y, + self->pointer_items[index].bpp); self->wm->current_pointer = index; DEBUG(("adding pointer at %d", index)); return index; @@ -532,15 +536,17 @@ xrdp_cache_add_pointer_static(struct xrdp_cache *self, self->pointer_items[index].x = pointer_item->x; self->pointer_items[index].y = pointer_item->y; g_memcpy(self->pointer_items[index].data, - pointer_item->data, 32 * 32 * 3); + pointer_item->data, 32 * 32 * 4); g_memcpy(self->pointer_items[index].mask, pointer_item->mask, 32 * 32 / 8); self->pointer_items[index].stamp = self->pointer_stamp; + self->pointer_items[index].bpp = pointer_item->bpp; xrdp_wm_send_pointer(self->wm, index, self->pointer_items[index].data, self->pointer_items[index].mask, self->pointer_items[index].x, - self->pointer_items[index].y); + self->pointer_items[index].y, + self->pointer_items[index].bpp); self->wm->current_pointer = index; DEBUG(("adding pointer at %d", index)); return index; diff --git a/xrdp/xrdp_font.c b/xrdp/xrdp_font.c index 91734807..1b7271ee 100644 --- a/xrdp/xrdp_font.c +++ b/xrdp/xrdp_font.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ */ #include "xrdp.h" +#include "log.h" #if 0 /* not used */ static char w_char[] = @@ -80,8 +81,8 @@ xrdp_font_create(struct xrdp_wm *wm) if (!g_file_exist(file_path)) { - g_writeln("xrdp_font_create: error font file [%s] does not exist", - file_path); + log_message(LOG_LEVEL_ERROR,"xrdp_font_create: error font file [%s] does not exist", + file_path); return 0; } @@ -89,8 +90,8 @@ xrdp_font_create(struct xrdp_wm *wm) if (file_size < 1) { - g_writeln("xrdp_font_create: error reading font from file [%s]", - file_path); + log_message(LOG_LEVEL_ERROR,"xrdp_font_create: error reading font from file [%s]", + file_path); return 0; } @@ -134,9 +135,9 @@ xrdp_font_create(struct xrdp_wm *wm) if (datasize < 0 || datasize > 512) { /* shouldn't happen */ - g_writeln("error in xrdp_font_create, datasize wrong"); - g_writeln("width %d height %d datasize %d index %d", - f->width, f->height, datasize, index); + log_message(LOG_LEVEL_ERROR,"error in xrdp_font_create, datasize wrong"); + log_message(LOG_LEVEL_DEBUG,"width %d height %d datasize %d index %d", + f->width, f->height, datasize, index); break; } @@ -147,7 +148,7 @@ xrdp_font_create(struct xrdp_wm *wm) } else { - g_writeln("error in xrdp_font_create"); + log_message(LOG_LEVEL_ERROR,"error in xrdp_font_create"); } index++; diff --git a/xrdp/xrdp_listen.c b/xrdp/xrdp_listen.c index e31c5405..965aa50d 100644 --- a/xrdp/xrdp_listen.c +++ b/xrdp/xrdp_listen.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ xrdp_listen_create_pro_done(struct xrdp_listen *self) if (self->pro_done_event == 0) { - g_writeln("Failure creating pro_done_event"); + log_message(LOG_LEVEL_ERROR,"Failure creating pro_done_event"); } return 0; @@ -64,7 +64,7 @@ xrdp_listen_create(void) if (self->listen_trans == 0) { - g_writeln("xrdp_listen_create: trans_create failed"); + log_message(LOG_LEVEL_ERROR,"xrdp_listen_create: trans_create failed"); } return self; @@ -326,7 +326,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) &tcp_nodelay, &tcp_keepalive, self->startup_params) != 0) { - g_writeln("xrdp_listen_main_loop: xrdp_listen_get_port failed"); + log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed"); self->status = -1; return 1; } @@ -340,7 +340,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) { if (g_tcp_set_no_delay(self->listen_trans->sck)) { - g_writeln("Error setting tcp_nodelay"); + log_message(LOG_LEVEL_ERROR,"Error setting tcp_nodelay"); } } @@ -348,7 +348,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) { if (g_tcp_set_keepalive(self->listen_trans->sck)) { - g_writeln("Error setting tcp_keepalive"); + log_message(LOG_LEVEL_ERROR,"Error setting tcp_keepalive"); } } @@ -373,7 +373,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) if (trans_get_wait_objs(self->listen_trans, robjs, &robjs_count) != 0) { - g_writeln("Listening socket is in wrong state we " + log_message(LOG_LEVEL_ERROR,"Listening socket is in wrong state we " "terminate listener"); break; } @@ -454,7 +454,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self) } else { - g_writeln("xrdp_listen_main_loop: listen error, possible port " + log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, possible port " "already in use"); } diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index fc4cf125..e7066798 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -315,7 +315,18 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo) { self->login_window->focused_control = b; } - + /*Use the domain name as the destination IP/DNS + This is useful in a gateway setup.*/ + if (g_strncmp(name, "ip", 255) == 0) + { + /* If the first char in the domain name is '_' we use the domain name as IP*/ + if(self->session->client_info->domain[0]=='_') + { + g_strncpy(b->caption1, &self->session->client_info->domain[1], 255); + b->edit_pos = g_mbstowcs(0, b->caption1, 0); + } + + } if (g_strncmp(name, "username", 255) == 0) { g_strncpy(b->caption1, self->session->client_info->username, 255); diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 52751b72..0a79810b 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,15 @@ * module manager */ +#include <config_ac.h> +#define ACCESS #include "xrdp.h" #include "log.h" -#define ACCESS +#ifdef ACCESS +#ifndef USE_NOPAM +#include "security/_pam_types.h" +#endif +#endif /*****************************************************************************/ struct xrdp_mm *APP_CC @@ -62,7 +68,7 @@ xrdp_mm_sync_load(long param1, long param2) static void APP_CC xrdp_mm_module_cleanup(struct xrdp_mm *self) { - g_writeln("xrdp_mm_module_cleanup"); + log_message(LOG_LEVEL_DEBUG,"xrdp_mm_module_cleanup"); if (self->mod != 0) { @@ -143,13 +149,10 @@ xrdp_mm_send_login(struct xrdp_mm *self) { password = value; } - else if (g_strcasecmp(name, "lib") == 0) + else if (g_strcasecmp(name, "code") == 0) { - if ((g_strcasecmp(value, "libxup.so") == 0) || - (g_strcasecmp(value, "xup.dll") == 0)) - { - self->code = 10; - } + /* this code is either 0 for Xvnc or 10 for X11rdp */ + self->code = g_atoi(value); } else if (g_strcasecmp(name, "xserverbpp") == 0) { @@ -187,9 +190,17 @@ xrdp_mm_send_login(struct xrdp_mm *self) } /* send domain */ - index = g_strlen(self->wm->client_info->domain); - out_uint16_be(s, index); - out_uint8a(s, self->wm->client_info->domain, index); + if(self->wm->client_info->domain[0]!='_') + { + index = g_strlen(self->wm->client_info->domain); + out_uint16_be(s, index); + out_uint8a(s, self->wm->client_info->domain, index); + } + else + { + out_uint16_be(s, 0); + /* out_uint8a(s, "", 0); */ + } /* send program / shell */ index = g_strlen(self->wm->client_info->program); @@ -298,8 +309,9 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) if (self->mod_handle == 0) { + g_snprintf(text, 255, "%s/%s", XRDP_LIB_PATH, lib); /* Let the main thread load the lib,*/ - self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (long)lib, 0); + self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (tintptr)text, 0); if (self->mod_handle != 0) { @@ -315,6 +327,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) g_snprintf(text, 255, "error finding proc mod_init in %s, not a valid " "xrdp backend", lib); xrdp_wm_log_msg(self->wm, text); + log_message(LOG_LEVEL_ERROR,text); } self->mod_init = (struct xrdp_mod * ( *)(void))func; @@ -330,6 +343,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) g_snprintf(text, 255, "error finding proc mod_exit in %s, not a valid " "xrdp backend", lib); xrdp_wm_log_msg(self->wm, text); + log_message(LOG_LEVEL_ERROR,text); } self->mod_exit = (int ( *)(struct xrdp_mod *))func; @@ -346,7 +360,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) } else { - g_writeln("no mod_init or mod_exit address found"); + log_message(LOG_LEVEL_ERROR,"no mod_init or mod_exit address found"); } } else @@ -354,6 +368,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) g_snprintf(text, 255, "error loading %s specified in xrdp.ini, please " "add a valid entry like lib=libxrdp-vnc.so or similar", lib); xrdp_wm_log_msg(self->wm, text); + log_message(LOG_LEVEL_ERROR,text); return 1; } @@ -367,6 +382,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) self->mod->server_screen_blt = server_screen_blt; self->mod->server_paint_rect = server_paint_rect; self->mod->server_set_pointer = server_set_pointer; + self->mod->server_set_pointer_ex = server_set_pointer_ex; self->mod->server_palette = server_palette; self->mod->server_msg = server_msg; self->mod->server_is_term = server_is_term; @@ -693,7 +709,7 @@ xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans, rv = xrdp_mm_trans_process_channel_data(self, trans); break; default: - g_writeln("xrdp_mm_chan_process_msg: unknown id %d", id); + log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id); break; } @@ -802,26 +818,27 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, char *ip, char *port) } g_sleep(1000); - g_writeln("xrdp_mm_connect_chansrv: connect failed " + log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: connect failed " "trying again..."); } if (!(self->chan_trans_up)) { - g_writeln("xrdp_mm_connect_chansrv: error in trans_connect " - "chan"); + log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in" + "trans_connect chan"); } if (self->chan_trans_up) { if (xrdp_mm_chan_send_init(self) != 0) { - g_writeln("xrdp_mm_connect_chansrv: error in " + log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in " "xrdp_mm_chan_send_init"); } else { - g_writeln("xrdp_mm_connect_chansrv: chansrv connect successful"); + log_message(LOG_LEVEL_DEBUG,"xrdp_mm_connect_chansrv: chansrv" + "connect successful"); } } @@ -888,6 +905,8 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s) { xrdp_wm_log_msg(self->wm, "xrdp_mm_process_login_response: " "login failed"); + log_message(LOG_LEVEL_INFO,"xrdp_mm_process_login_response: " + "login failed"); } cleanup_sesman_connection(self); @@ -983,7 +1002,7 @@ xrdp_mm_process_channel_data(struct xrdp_mm *self, tbus param1, tbus param2, if (total_length < length) { - g_writeln("WARNING in xrdp_mm_process_channel_data(): total_len < length"); + log_message(LOG_LEVEL_DEBUG,"WARNING in xrdp_mm_process_channel_data(): total_len < length"); total_length = length; } @@ -1045,7 +1064,7 @@ xrdp_mm_sesman_data_in(struct trans *trans) break; default: xrdp_wm_log_msg(self->wm, "An undefined reply code was received from sesman"); - g_writeln("Fatal xrdp_mm_sesman_data_in: unknown cmd code %d", code); + log_message(LOG_LEVEL_ERROR,"Fatal xrdp_mm_sesman_data_in: unknown cmd code %d", code); cleanup_sesman_connection(self); break; } @@ -1055,17 +1074,19 @@ xrdp_mm_sesman_data_in(struct trans *trans) } #ifdef ACCESS +#ifndef USE_NOPAM /*********************************************************************/ /* return 0 on success */ -int access_control(char *username, char *password, char *srv) +static int APP_CC +access_control(char *username, char *password, char *srv) { int reply; - int rec = 1; // failure + int rec = 32+1; /* 32 is reserved for PAM failures this means connect failure */ struct stream *in_s; struct stream *out_s; unsigned long version; unsigned short int dummy; - unsigned short int ok; + unsigned short int pAM_errorcode; unsigned short int code; unsigned long size; int index; @@ -1117,17 +1138,17 @@ int access_control(char *username, char *password, char *srv) if ((size == 14) && (version == 0)) { in_uint16_be(in_s, code); - in_uint16_be(in_s, ok); + in_uint16_be(in_s, pAM_errorcode); /* this variable holds the PAM error code if the variable is >32 it is a "invented" code */ in_uint16_be(in_s, dummy); - if (code != 4) + if (code != 4) /*0x04 means SCP_GW_AUTHENTICATION*/ { log_message(LOG_LEVEL_ERROR, "Returned cmd code from " "sesman is corrupt"); } else { - rec = ok; /* here we read the reply from the access control */ + rec = pAM_errorcode; /* here we read the reply from the access control */ } } else @@ -1167,12 +1188,14 @@ int access_control(char *username, char *password, char *srv) return rec; } #endif +#endif /*****************************************************************************/ /* This routine clears all states to make sure that our next login will be * as expected. If the user does not press ok on the log window and try to * connect again we must make sure that no previous information is stored.*/ -void cleanup_states(struct xrdp_mm *self) +static void APP_CC +cleanup_states(struct xrdp_mm *self) { if (self != NULL) { @@ -1189,6 +1212,134 @@ void cleanup_states(struct xrdp_mm *self) self-> usechansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */ } } + +#ifdef ACCESS +#ifndef USE_NOPAM +static const char * APP_CC +getPAMError(const int pamError, char *text, int text_bytes) +{ + switch (pamError) + { + case PAM_SUCCESS: + return "Success"; + case PAM_OPEN_ERR: + return "dlopen() failure"; + case PAM_SYMBOL_ERR: + return "Symbol not found"; + case PAM_SERVICE_ERR: + return "Error in service module"; + case PAM_SYSTEM_ERR: + return "System error"; + case PAM_BUF_ERR: + return "Memory buffer error"; + case PAM_PERM_DENIED: + return "Permission denied"; + case PAM_AUTH_ERR: + return "Authentication failure"; + case PAM_CRED_INSUFFICIENT: + return "Insufficient credentials to access authentication data"; + case PAM_AUTHINFO_UNAVAIL: + return "Authentication service cannot retrieve authentication info."; + case PAM_USER_UNKNOWN: + return "User not known to the underlying authentication module"; + case PAM_MAXTRIES: + return "Have exhasted maximum number of retries for service."; + case PAM_NEW_AUTHTOK_REQD: + return "Authentication token is no longer valid; new one required."; + case PAM_ACCT_EXPIRED: + return "User account has expired"; + case PAM_CRED_UNAVAIL: + return "Authentication service cannot retrieve user credentials"; + case PAM_CRED_EXPIRED: + return "User credentials expired"; + case PAM_CRED_ERR: + return "Failure setting user credentials"; + case PAM_NO_MODULE_DATA: + return "No module specific data is present"; + case PAM_BAD_ITEM: + return "Bad item passed to pam_*_item()"; + case PAM_CONV_ERR: + return "Conversation error"; + case PAM_AUTHTOK_ERR: + return "Authentication token manipulation error"; + case PAM_AUTHTOK_LOCK_BUSY: + return "Authentication token lock busy"; + case PAM_AUTHTOK_DISABLE_AGING: + return "Authentication token aging disabled"; + case PAM_TRY_AGAIN: + return "Failed preliminary check by password service"; + case PAM_IGNORE: + return "Please ignore underlying account module"; + case PAM_MODULE_UNKNOWN: + return "Module is unknown"; + case PAM_AUTHTOK_EXPIRED: + return "Authentication token expired"; + case PAM_CONV_AGAIN: + return "Conversation is waiting for event"; + case PAM_INCOMPLETE: + return "Application needs to call libpam again"; + case 32 + 1: + return "Error connecting to PAM"; + case 32 + 3: + return "Username okey but group problem"; + default: + g_snprintf(text, text_bytes, "Not defined PAM error:%d", pamError); + return text; + } +} + +static const char * APP_CC +getPAMAdditionalErrorInfo(const int pamError, struct xrdp_mm *self) +{ + switch (pamError) + { + case PAM_SUCCESS: + return NULL; + case PAM_OPEN_ERR: + case PAM_SYMBOL_ERR: + case PAM_SERVICE_ERR: + case PAM_SYSTEM_ERR: + case PAM_BUF_ERR: + case PAM_PERM_DENIED: + case PAM_AUTH_ERR: + case PAM_CRED_INSUFFICIENT: + case PAM_AUTHINFO_UNAVAIL: + case PAM_USER_UNKNOWN: + case PAM_CRED_UNAVAIL: + case PAM_CRED_ERR: + case PAM_NO_MODULE_DATA: + case PAM_BAD_ITEM: + case PAM_CONV_ERR: + case PAM_AUTHTOK_ERR: + case PAM_AUTHTOK_LOCK_BUSY: + case PAM_AUTHTOK_DISABLE_AGING: + case PAM_TRY_AGAIN: + case PAM_IGNORE: + case PAM_MODULE_UNKNOWN: + case PAM_CONV_AGAIN: + case PAM_INCOMPLETE: + case _PAM_RETURN_VALUES + 1: + case _PAM_RETURN_VALUES + 3: + return NULL; + case PAM_MAXTRIES: + case PAM_NEW_AUTHTOK_REQD: + case PAM_ACCT_EXPIRED: + case PAM_CRED_EXPIRED: + case PAM_AUTHTOK_EXPIRED: + if (self->wm->pamerrortxt[0]) + { + return self->wm->pamerrortxt; + } + else + { + return "Authentication error - Verify that user/password is valid"; + } + default: + return "No expected error"; + } +} +#endif +#endif /*****************************************************************************/ int APP_CC xrdp_mm_connect(struct xrdp_mm *self) @@ -1207,10 +1358,12 @@ xrdp_mm_connect(struct xrdp_mm *self) char port[8]; char chansrvport[256]; #ifdef ACCESS +#ifndef USE_NOPAM int use_pam_auth = 0; char pam_auth_sessionIP[256]; char pam_auth_password[256]; char pam_auth_username[256]; +#endif char username[256]; char password[256]; username[0] = 0; @@ -1246,6 +1399,7 @@ xrdp_mm_connect(struct xrdp_mm *self) } #ifdef ACCESS +#ifndef USE_NOPAM else if (g_strcasecmp(name, "pamusername") == 0) { use_pam_auth = 1; @@ -1259,6 +1413,7 @@ xrdp_mm_connect(struct xrdp_mm *self) { g_strncpy(pam_auth_password, value, 255); } +#endif else if (g_strcasecmp(name, "password") == 0) { g_strncpy(password, value, 255); @@ -1277,12 +1432,13 @@ xrdp_mm_connect(struct xrdp_mm *self) } #ifdef ACCESS - +#ifndef USE_NOPAM if (use_pam_auth) { int reply; - char replytxt[80]; - char replymessage[4][80] = {"Ok", "Sesman connect failure", "User or password error", "Privilege group error"}; + char replytxt[128]; + char pam_error[128]; + const char *additionalError; xrdp_wm_log_msg(self->wm, "Please wait, we now perform access control..."); /* g_writeln("we use pam modules to check if we can approve this user"); */ @@ -1301,17 +1457,20 @@ xrdp_mm_connect(struct xrdp_mm *self) /* access_control return 0 on success */ reply = access_control(pam_auth_username, pam_auth_password, pam_auth_sessionIP); - if (reply >= 0 && reply < 4) - { - g_sprintf(replytxt, "Reply from access control: %s", replymessage[reply]); - } - else - { - g_sprintf(replytxt, "Reply from access control undefined"); - } + g_sprintf(replytxt, "Reply from access control: %s", + getPAMError(reply, pam_error, 127)); xrdp_wm_log_msg(self->wm, replytxt); log_message(LOG_LEVEL_INFO, replytxt); + additionalError = getPAMAdditionalErrorInfo(reply, self); + if (additionalError) + { + g_snprintf(replytxt, 127, "%s", additionalError); + if (replytxt[0]) + { + xrdp_wm_log_msg(self->wm, replytxt); + } + } if (reply != 0) { @@ -1319,7 +1478,7 @@ xrdp_mm_connect(struct xrdp_mm *self) return rv; } } - +#endif #endif if (self->sesman_controlled) @@ -1362,6 +1521,7 @@ xrdp_mm_connect(struct xrdp_mm *self) g_snprintf(errstr, 255, "Failure to connect to sesman: %s port: %s", ip, port); xrdp_wm_log_msg(self->wm, errstr); + log_message(LOG_LEVEL_ERROR,errstr); trans_delete(self->sesman_trans); self->sesman_trans = 0; self->sesman_trans_up = 0; @@ -1381,13 +1541,14 @@ xrdp_mm_connect(struct xrdp_mm *self) { /* connect error */ g_snprintf(errstr, 255, "Failure to connect to: %s", ip); + log_message(LOG_LEVEL_ERROR,errstr); xrdp_wm_log_msg(self->wm, errstr); rv = 1; /* failure */ } } else { - g_writeln("Failure setting up module"); + log_message(LOG_LEVEL_ERROR,"Failure setting up module"); } if (self->wm->login_mode != 10) @@ -1405,7 +1566,7 @@ xrdp_mm_connect(struct xrdp_mm *self) xrdp_mm_connect_chansrv(self, "", chansrvport); } - g_writeln("returnvalue from xrdp_mm_connect %d", rv); + log_message(LOG_LEVEL_DEBUG,"returnvalue from xrdp_mm_connect %d", rv); return rv; } @@ -1641,7 +1802,19 @@ server_set_pointer(struct xrdp_mod *mod, int x, int y, struct xrdp_wm *wm; wm = (struct xrdp_wm *)(mod->wm); - xrdp_wm_pointer(wm, data, mask, x, y); + xrdp_wm_pointer(wm, data, mask, x, y, 0); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_set_pointer_ex(struct xrdp_mod *mod, int x, int y, + char *data, char *mask, int bpp) +{ + struct xrdp_wm *wm; + + wm = (struct xrdp_wm *)(mod->wm); + xrdp_wm_pointer(wm, data, mask, x, y, bpp); return 0; } @@ -1957,7 +2130,7 @@ int read_allowed_channel_names(struct list *names, struct list *values) } else { - g_writeln("Failure reading channel section of configuration"); + log_message(LOG_LEVEL_ERROR,"Failure reading channel section of configuration"); } g_file_close(fd); @@ -1965,6 +2138,28 @@ int read_allowed_channel_names(struct list *names, struct list *values) return ret; } +/* internal function return -1 if name is not in list + * otherwise return the index 0->count-1*/ +int DEFAULT_CC +find_name_in_lists(char *inName, struct list *names) +{ + int reply = -1; /*means not in the list*/ + int index; + char *name; + + for (index = 0; index < names->count; index++) + { + name = (char *)list_get_item(names, index); + if ( (name != 0) && (g_strncmp(name, inName, MAX_CHANNEL_NAME) == 0) ) + { + reply = index; + break; /* stop loop - item found*/ + } + } + + return reply; +} + #define CHANNEL_NAME_PREFIX "channel." /* update the channel lists from connection specific overrides * return 1 on success 0 on failure */ @@ -1979,7 +2174,7 @@ int update_allowed_channel_names(struct xrdp_wm *wm, struct list *names, struct for (index = 0; index < wm->mm->login_names->count; index++) { name = (char *)list_get_item(wm->mm->login_names, index); - if ( (name != 0) && (g_strncmp( name, CHANNEL_NAME_PREFIX, g_strlen(CHANNEL_NAME_PREFIX)) == 0 ) ) + if ( (name != 0) && (g_strncmp( name, CHANNEL_NAME_PREFIX, g_strlen(CHANNEL_NAME_PREFIX)) == 0 ) ) { name += g_strlen(CHANNEL_NAME_PREFIX); // locate and remove from list @@ -1998,28 +2193,6 @@ int update_allowed_channel_names(struct xrdp_wm *wm, struct list *names, struct return ret; } -/* internal function return -1 if name is not in list - * otherwise return the index 0->count-1*/ -int DEFAULT_CC -find_name_in_lists(char *inName, struct list *names) -{ - int reply = -1; /*means not in the list*/ - int index; - char *name; - - for (index = 0; index < names->count; index++) - { - name = (char *)list_get_item(names, index); - if ( (name != 0) && (g_strncmp(name, inName, MAX_CHANNEL_NAME) == 0) ) - { - reply = index; - break; /* stop loop - item found*/ - } - } - - return reply; -} - /* internal function return 1 if name is in list of channels * and if the value is allowed */ int DEFAULT_CC @@ -2028,7 +2201,6 @@ is_channel_enabled(char *inName, struct list *names, struct list *values) int reply = 0; /*means not in the list*/ int index; char *val; - char *name; index = find_name_in_lists(inName, names); if ( index >= 0 ) @@ -2037,9 +2209,13 @@ is_channel_enabled(char *inName, struct list *names, struct list *values) reply = text2bool(val); if (reply == 0) { - g_writeln("This channel is disabled: %s", name); + log_message(LOG_LEVEL_INFO,"This channel is disabled: %s", inName); } } + else + { + log_message(LOG_LEVEL_INFO,"This channel is disabled (not in List): %s", inName); + } return reply; } @@ -2065,7 +2241,8 @@ void init_channel_allowed(struct xrdp_wm *wm) names = list_create(); values = list_create(); - + /* You can override the list of allowed channels individually for each + * session type. */ if ( read_allowed_channel_names(names, values) && update_allowed_channel_names(wm, names, values) ) { @@ -2079,19 +2256,19 @@ void init_channel_allowed(struct xrdp_wm *wm) /* examples of channel names: rdpdr ; rdpsnd ; drdynvc ; cliprdr */ if (is_channel_enabled(channelname, names, values)) { - g_writeln("The following channel is allowed: %s (%d)", channelname, index); + log_message(LOG_LEVEL_INFO,"The following channel is allowed: %s (%d)", channelname, index); wm->allowedchannels[allowindex] = index; allowindex++; if (allowindex >= MAX_NR_CHANNELS) { - g_writeln("Programming error in is_channel_allowed"); + log_message(LOG_LEVEL_ALWAYS,"Programming error in is_channel_allowed"); error = 1; /* end loop */ } } else { - g_writeln("The following channel is not allowed: %s (%d)", channelname, index); + log_message(LOG_LEVEL_INFO,"The following channel is not allowed: %s (%d)", channelname, index); } index++; @@ -2101,7 +2278,7 @@ void init_channel_allowed(struct xrdp_wm *wm) } else { - g_writeln("Error reading channel section in inifile"); + log_message(LOG_LEVEL_ERROR,"Error reading channel section in inifile"); } list_delete(names); @@ -2121,7 +2298,7 @@ int DEFAULT_CC is_channel_allowed(struct xrdp_wm *wm, int channel_id) if (wm->allowedinitialized == 0) { init_channel_allowed(wm); - g_writeln("allow channel list initialized"); + log_message(LOG_LEVEL_DEBUG,"The allow channel list now initialized for this session"); wm->allowedinitialized = 1; } @@ -2141,10 +2318,6 @@ int DEFAULT_CC is_channel_allowed(struct xrdp_wm *wm, int channel_id) } } - /*if (reply == 0) - { - g_writeln("This channel is NOT allowed: %d",channel_id) ; - }*/ return reply; } @@ -2226,7 +2399,7 @@ server_create_os_surface(struct xrdp_mod *mod, int rdpindex, if (error != 0) { - g_writeln("server_create_os_surface: xrdp_cache_add_os_bitmap failed"); + log_message(LOG_LEVEL_ERROR,"server_create_os_surface: xrdp_cache_add_os_bitmap failed"); return 1; } @@ -2277,7 +2450,7 @@ server_switch_os_surface(struct xrdp_mod *mod, int rdpindex) } else { - g_writeln("server_switch_os_surface: error finding id %d", rdpindex); + log_message(LOG_LEVEL_ERROR,"server_switch_os_surface: error finding id %d", rdpindex); } return 0; @@ -2340,7 +2513,7 @@ server_paint_rect_os(struct xrdp_mod *mod, int x, int y, int cx, int cy, } else { - g_writeln("server_paint_rect_os: error finding id %d", rdpindex); + log_message(LOG_LEVEL_ERROR,"server_paint_rect_os: error finding id %d", rdpindex); } return 0; diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 8ba33825..4457fee8 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/xrdp/xrdp_process.c b/xrdp/xrdp_process.c index e3b846ea..228bf630 100644 --- a/xrdp/xrdp_process.c +++ b/xrdp/xrdp_process.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -197,14 +197,14 @@ xrdp_process_main_loop(struct xrdp_process *self) break; } } - + /* send disconnect message if possible */ libxrdp_disconnect(self->session); } else { g_writeln("xrdp_process_main_loop: libxrdp_process_incomming failed"); } - + /* Run end in module */ xrdp_process_mod_end(self); libxrdp_exit(self->session); self->session = 0; diff --git a/xrdp/xrdp_region.c b/xrdp/xrdp_region.c index 8dc6854b..c66994f7 100644 --- a/xrdp/xrdp_region.c +++ b/xrdp/xrdp_region.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index fdaed059..e7bb7baf 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -115,8 +115,10 @@ struct xrdp_mod int (*server_monitored_desktop)(struct xrdp_mod* mod, struct rail_monitored_desktop_order* mdo, int flags); + int (*server_set_pointer_ex)(struct xrdp_mod* v, int x, int y, char* data, + char* mask, int bpp); - long server_dumby[100 - 37]; /* align, 100 minus the number of server + long server_dumby[100 - 38]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as int */ @@ -170,8 +172,9 @@ struct xrdp_pointer_item int stamp; int x; /* hotspot */ int y; - char data[32 * 32 * 3]; + char data[32 * 32 * 4]; char mask[32 * 32 / 8]; + int bpp; }; struct xrdp_brush_item @@ -316,6 +319,7 @@ struct xrdp_wm int hints; int allowedchannels[MAX_NR_CHANNELS]; int allowedinitialized ; + char pamerrortxt[256]; }; /* rdp process */ diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index e3fa1f80..bfcc7548 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ */ #include "xrdp.h" +#include "log.h" /*****************************************************************************/ struct xrdp_wm *APP_CC @@ -44,6 +45,7 @@ xrdp_wm_create(struct xrdp_process *owner, pid = g_getpid(); g_snprintf(event_name, 255, "xrdp_%8.8x_wm_login_mode_event_%8.8x", pid, owner->session_id); + log_message(LOG_LEVEL_DEBUG,event_name); self->login_mode_event = g_create_wait_obj(event_name); self->painter = xrdp_painter_create(self, self->session); self->cache = xrdp_cache_create(self, self->session, self->client_info); @@ -178,14 +180,22 @@ xrdp_wm_get_pixel(char *data, int x, int y, int width, int bpp) /*****************************************************************************/ int APP_CC -xrdp_wm_pointer(struct xrdp_wm *self, char *data, char *mask, int x, int y) +xrdp_wm_pointer(struct xrdp_wm *self, char *data, char *mask, int x, int y, + int bpp) { + int bytes; struct xrdp_pointer_item pointer_item; + if (bpp == 0) + { + bpp = 24; + } + bytes = ((bpp + 7) / 8) * 32 * 32; g_memset(&pointer_item, 0, sizeof(struct xrdp_pointer_item)); pointer_item.x = x; pointer_item.y = y; - g_memcpy(pointer_item.data, data, 32 * 32 * 3); + pointer_item.bpp = bpp; + g_memcpy(pointer_item.data, data, bytes); g_memcpy(pointer_item.mask, mask, 32 * 32 / 8); self->screen->pointer = xrdp_cache_add_pointer(self->cache, &pointer_item); return 0; @@ -209,7 +219,7 @@ xrdp_wm_load_pointer(struct xrdp_wm *self, char *file_name, char *data, if (!g_file_exist(file_name)) { - g_writeln("xrdp_wm_load_pointer: error pointer file [%s] does not exist", + log_message(LOG_LEVEL_ERROR,"xrdp_wm_load_pointer: error pointer file [%s] does not exist", file_name); return 1; } @@ -220,7 +230,7 @@ xrdp_wm_load_pointer(struct xrdp_wm *self, char *file_name, char *data, if (fd < 1) { - g_writeln("xrdp_wm_load_pointer: error loading pointer from file [%s]", + log_message(LOG_LEVEL_ERROR,"xrdp_wm_load_pointer: error loading pointer from file [%s]", file_name); return 1; } @@ -290,9 +300,10 @@ xrdp_wm_load_pointer(struct xrdp_wm *self, char *file_name, char *data, /*****************************************************************************/ int APP_CC xrdp_wm_send_pointer(struct xrdp_wm *self, int cache_idx, - char *data, char *mask, int x, int y) + char *data, char *mask, int x, int y, int bpp) { - return libxrdp_send_pointer(self->session, cache_idx, data, mask, x, y); + return libxrdp_send_pointer(self->session, cache_idx, data, mask, + x, y, bpp); } /*****************************************************************************/ @@ -446,6 +457,11 @@ xrdp_wm_load_static_colors_plus(struct xrdp_wm *self, char *autorun_name) val = (char *)list_get_item(values, index); self->hide_log_window = text2bool(val); } + else if (g_strcasecmp(val, "pamerrortxt") == 0) + { + val = (char *)list_get_item(values, index); + g_strncpy(self->pamerrortxt, val, 255); + } } } } @@ -456,7 +472,7 @@ xrdp_wm_load_static_colors_plus(struct xrdp_wm *self, char *autorun_name) } else { - g_writeln("xrdp_wm_load_static_colors: Could not read xrdp.ini file %s", cfg_file); + log_message(LOG_LEVEL_ERROR,"xrdp_wm_load_static_colors: Could not read xrdp.ini file %s", cfg_file); } if (self->screen->bpp == 8) @@ -534,24 +550,30 @@ xrdp_wm_init(struct xrdp_wm *self) names->auto_free = 1; values = list_create(); values->auto_free = 1; - g_strncpy(section_name, self->session->client_info->domain, 255); - + /* domain names that starts with '_' are reserved for IP/DNS to + * simplify for the user in a gateway setup */ + if (self->session->client_info->domain[0] != '_') + { + g_strncpy(section_name, self->session->client_info->domain, + 255); + } if (section_name[0] == 0) { if (autorun_name[0] == 0) { /* if no doamin is passed, and no autorun in xrdp.ini, use the first item in the xrdp.ini - file thats not named 'globals' */ + file thats not named + 'globals' or 'Logging' or 'channels' */ + /* TODO: change this and have a 'autologin' + line in globals section */ file_read_sections(fd, names); - for (index = 0; index < names->count; index++) { q = (char *)list_get_item(names, index); - - if ((g_strncasecmp("globals", q, 8) != 0) - && (g_strncasecmp("channels", q, 9) != 0) - && (g_strncasecmp("Logging", q, 8) != 0)) + if ((g_strncasecmp("globals", q, 8) != 0) && + (g_strncasecmp("Logging", q, 8) != 0) && + (g_strncasecmp("channels", q, 9) != 0)) { g_strncpy(section_name, q, 255); break; @@ -609,7 +631,7 @@ xrdp_wm_init(struct xrdp_wm *self) } else { - g_writeln("xrdp_wm_init: Could not read xrdp.ini file %s", cfg_file); + log_message(LOG_LEVEL_ERROR,"xrdp_wm_init: Could not read xrdp.ini file %s", cfg_file); } } else diff --git a/xrdp/xrdpwin.c b/xrdp/xrdpwin.c index ed6fa4c5..da9ba9e0 100644 --- a/xrdp/xrdpwin.c +++ b/xrdp/xrdpwin.c @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -137,7 +137,7 @@ void DEFAULT_CC pipe_sig(int sig_num) { /* do nothing */ - g_writeln("got SIGPIPE(%d)", sig_num); + g_writeln("got XRDP WIN SIGPIPE(%d)", sig_num); } /*****************************************************************************/ diff --git a/xrdpapi/xrdpapi.c b/xrdpapi/xrdpapi.c index f35c8210..e3b63035 100644 --- a/xrdpapi/xrdpapi.c +++ b/xrdpapi/xrdpapi.c @@ -163,7 +163,7 @@ mysend(int sck, const void* adata, int bytes) int error; const char* data; - data = (char*)adata; + data = (const char*)adata; sent = 0; while (sent < bytes) { @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -489,6 +489,29 @@ process_server_window_delete(struct mod *mod, struct stream *s) /******************************************************************************/ /* return error */ +static int APP_CC +process_server_set_pointer_ex(struct mod *mod, struct stream *s) +{ + int rv; + int x; + int y; + int bpp; + int Bpp; + char cur_data[32 * (32 * 4)]; + char cur_mask[32 * (32 / 8)]; + + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, bpp); + Bpp = (bpp == 0) ? 3 : (bpp + 7) / 8; + in_uint8a(s, cur_data, 32 * (32 * Bpp)); + in_uint8a(s, cur_mask, 32 * (32 / 8)); + rv = mod->server_set_cursor_ex(mod, x, y, cur_data, cur_mask, bpp); + return rv; +} + +/******************************************************************************/ +/* return error */ static int lib_mod_process_orders(struct mod *mod, int type, struct stream *s) { @@ -630,6 +653,9 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) case 26: /* server_window_delete */ rv = process_server_window_delete(mod, s); break; + case 51: /* server_set_pointer_ex */ + rv = process_server_set_pointer_ex(mod, s); + break; default: g_writeln("lib_mod_process_orders: unknown order type %d", type); rv = 0; @@ -1,7 +1,7 @@ /** * xrdp: A Remote Desktop Protocol server. * - * Copyright (C) Jay Sorg 2004-2012 + * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,7 +117,10 @@ struct mod int (*server_monitored_desktop)(struct mod* v, struct rail_monitored_desktop_order* mdo, int flags); - tbus server_dumby[100 - 37]; /* align, 100 minus the number of server + int (*server_set_cursor_ex)(struct mod* v, int x, int y, char* data, + char* mask, int bpp); + + tbus server_dumby[100 - 38]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ |
