summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am7
-rw-r--r--common/file.c15
-rw-r--r--common/file_loc.h4
-rw-r--r--common/os_calls.c301
-rw-r--r--common/os_calls.h10
-rw-r--r--common/parse.h99
-rw-r--r--common/trans.h2
-rw-r--r--common/xrdp_client_info.h6
-rw-r--r--common/xrdp_constants.h1
-rw-r--r--configure.ac19
-rw-r--r--description-pak1
-rw-r--r--freerdp1/xrdp-freerdp.c186
-rw-r--r--freerdp1/xrdp-freerdp.h2
-rwxr-xr-xgenkeymap/dump-keymaps.sh4
-rw-r--r--instfiles/Makefile.am10
-rw-r--r--instfiles/default/Makefile.am3
-rw-r--r--instfiles/default/xrdp5
-rw-r--r--instfiles/init.d/Makefile.am4
-rw-r--r--instfiles/init.d/xrdp185
-rw-r--r--instfiles/km-0414.ini659
-rw-r--r--instfiles/km-0816.ini659
-rw-r--r--instfiles/pam.d/xrdp-sesman7
-rw-r--r--instfiles/pam.d/xrdp-sesman.other4
-rw-r--r--libxrdp/libxrdp.c93
-rw-r--r--libxrdp/libxrdpinc.h2
-rw-r--r--libxrdp/xrdp_mcs.c35
-rw-r--r--libxrdp/xrdp_orders.c8
-rw-r--r--libxrdp/xrdp_rdp.c40
-rw-r--r--libxrdp/xrdp_sec.c3
-rw-r--r--neutrinordp/Makefile.am28
-rw-r--r--neutrinordp/xrdp-color.c313
-rw-r--r--neutrinordp/xrdp-color.h29
-rw-r--r--neutrinordp/xrdp-neutrinordp.c1837
-rw-r--r--neutrinordp/xrdp-neutrinordp.h180
-rw-r--r--postinstall-pak21
-rw-r--r--sesman/access.c4
-rw-r--r--sesman/auth.h2
-rw-r--r--sesman/chansrv/Makefile.am4
-rw-r--r--sesman/chansrv/chansrv.c19
-rw-r--r--sesman/chansrv/chansrv_fuse.c3257
-rw-r--r--sesman/chansrv/chansrv_fuse.h80
-rw-r--r--sesman/chansrv/clipboard.c8
-rw-r--r--sesman/chansrv/clipboard_file.c28
-rw-r--r--sesman/chansrv/devredir.c1510
-rw-r--r--sesman/chansrv/devredir.h332
-rw-r--r--sesman/chansrv/irp.c241
-rw-r--r--sesman/chansrv/irp.h64
-rw-r--r--sesman/chansrv/pulse/Makefile18
-rw-r--r--sesman/chansrv/pulse/module-xrdp-sink-symdef.h29
-rw-r--r--sesman/chansrv/pulse/module-xrdp-sink.c581
-rw-r--r--sesman/chansrv/pulse/pulse-notes.txt72
-rw-r--r--sesman/chansrv/smartcard.c528
-rw-r--r--sesman/chansrv/smartcard.h42
-rw-r--r--sesman/chansrv/sound.c321
-rw-r--r--sesman/chansrv/sound.h14
-rw-r--r--sesman/chansrv/wave-format-server.txt466
-rw-r--r--sesman/config.c7
-rw-r--r--sesman/config.h6
-rw-r--r--sesman/libscp/libscp_tcp.c14
-rw-r--r--sesman/scp_v0.c9
-rw-r--r--sesman/scp_v1.c4
-rw-r--r--sesman/scp_v1_mng.c2
-rw-r--r--sesman/sesman.ini3
-rw-r--r--sesman/session.c4
-rwxr-xr-xsesman/startwm.sh116
-rw-r--r--sesman/verify_user.c46
-rw-r--r--sesman/verify_user_kerberos.c2
-rw-r--r--sesman/verify_user_pam.c22
-rw-r--r--sesman/verify_user_pam_userpass.c2
-rw-r--r--tests/gtcp_proxy/Makefile21
-rw-r--r--tests/gtcp_proxy/README.txt4
-rwxr-xr-xtests/gtcp_proxy/gtcp-proxybin0 -> 25665 bytes
-rw-r--r--tests/gtcp_proxy/gtcp-proxy.c678
-rw-r--r--tests/gtcp_proxy/gtcp.c394
-rw-r--r--tests/gtcp_proxy/gtcp.h48
-rw-r--r--tests/gtcp_proxy/hexdump.c130
-rwxr-xr-xxorg/X11R7.6/buildx.sh138
-rw-r--r--xorg/X11R7.6/rdp/rdp.h4
-rw-r--r--xorg/X11R7.6/rdp/rdpCopyArea.c80
-rw-r--r--xorg/X11R7.6/rdp/rdpdraw.c15
-rw-r--r--xorg/X11R7.6/rdp/rdpinput.c91
-rw-r--r--xorg/X11R7.6/rdp/rdprandr.c2
-rw-r--r--xorg/X11R7.6/rdp/rdpup.c32
-rwxr-xr-xxorg/debuild/debX11rdp.sh30
-rw-r--r--xorg/debuild/x11rdp-files/DEBIAN/control7
-rwxr-xr-xxorg/debuild/x11rdp-files/DEBIAN/postinst18
-rw-r--r--xorg/tests/randr/Makefile11
-rw-r--r--xorg/tests/randr/trandr.c138
-rw-r--r--xrdp/Makefile.am10
-rw-r--r--xrdp/funcs.c2
-rw-r--r--xrdp/lang.c6
-rw-r--r--xrdp/xrdp.c12
-rw-r--r--xrdp/xrdp.h10
-rw-r--r--xrdp/xrdp.ini27
-rw-r--r--xrdp/xrdp_bitmap.c2
-rw-r--r--xrdp/xrdp_cache.c22
-rw-r--r--xrdp/xrdp_font.c19
-rw-r--r--xrdp/xrdp_listen.c16
-rw-r--r--xrdp/xrdp_login_wnd.c15
-rw-r--r--xrdp/xrdp_mm.c339
-rw-r--r--xrdp/xrdp_painter.c2
-rw-r--r--xrdp/xrdp_process.c6
-rw-r--r--xrdp/xrdp_region.c2
-rw-r--r--xrdp/xrdp_types.h10
-rw-r--r--xrdp/xrdp_wm.c56
-rw-r--r--xrdp/xrdpwin.c4
-rw-r--r--xrdpapi/xrdpapi.c2
-rw-r--r--xup/xup.c28
-rw-r--r--xup/xup.h7
110 files changed, 13893 insertions, 1186 deletions
diff --git a/.gitignore b/.gitignore
index 0dc0f236..a579d210 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
new file mode 100755
index 00000000..6896b437
--- /dev/null
+++ b/tests/gtcp_proxy/gtcp-proxy
Binary files differ
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(&reg1, &box, 0);
RegionInit(&reg2, NullBox, 0);
- RegionCopy(&reg2, pDst->clientClip);
- lx = p->x + pDst->clipOrigin.x;
- ly = p->y + pDst->clipOrigin.y;
- RegionTranslate(&reg2, lx, ly);
+ RegionCopy(&reg2, pDst->pCompositeClip);
RegionIntersect(&reg1, &reg1, &reg2);
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)
{
diff --git a/xup/xup.c b/xup/xup.c
index 15498e64..27063366 100644
--- a/xup/xup.c
+++ b/xup/xup.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.
@@ -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;
diff --git a/xup/xup.h b/xup/xup.h
index ae98c5ff..a7956915 100644
--- a/xup/xup.h
+++ b/xup/xup.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.
@@ -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 */