Merge branch 'devel' into v0.9

This commit is contained in:
Koichiro IWAO 2018-01-09 15:22:53 +09:00
commit 5c622f51a4
No known key found for this signature in database
GPG Key ID: 9F72CDBC01BF10EB
37 changed files with 2580 additions and 768 deletions

View File

@ -19,7 +19,8 @@ min_amd64_deps: &min_amd64_deps
min_amd64_conf: &min_amd64_conf
env:
- CONF_FLAGS="--disable-ipv6 --disable-jpeg --disable-fuse --disable-mp3lame
--disable-rfxcodec --disable-painter --disable-pixman"
--disable-fdkaac --disable-opus --disable-rfxcodec --disable-painter
--disable-pixman"
addons:
apt:
packages:
@ -30,12 +31,15 @@ max_amd64_deps: &max_amd64_deps
- libfuse-dev
- libjpeg-dev
- libmp3lame-dev
- libfdk-aac-dev
- libopus-dev
- libpixman-1-dev
max_amd64_conf: &max_amd64_conf
env:
- CONF_FLAGS="--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
--enable-rfxcodec --enable-painter --enable-pixman"
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
--enable-pixman"
- DISTCHECK=1
addons:
apt:
@ -50,6 +54,8 @@ max_x86_deps: &max_x86_deps
- libglu1-mesa-dev:i386
- libjpeg-dev:i386
- libmp3lame-dev:i386
- libfdk-aac-dev:i386
- libopus-dev:i386
- libpam0g-dev:i386
- libssl-dev:i386
- libx11-dev:i386
@ -64,8 +70,8 @@ max_x86_deps: &max_x86_deps
max_x86_conf: &max_x86_conf
env:
- CONF_FLAGS="--enable-ipv6 --enable-jpeg --disable-fuse --enable-mp3lame
--enable-rfxcodec --enable-painter --disable-pixman
--host=i686-linux"
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
--disable-pixman --host=i686-linux"
- PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig
- CFLAGS=-m32
- LDFLAGS=-m32

35
NEWS.md
View File

@ -1,3 +1,34 @@
# Release notes for xrdp v0.9.5 (2017/12/27)
## Security fixes
* Fix local denial of service [CVE-2017-16927](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16927) #958 #979
## New features
* Add a new log level TRACE more verbose than DEBUG #835 #944
* SSH agent forwarding via RDP #867 #868 FreeRDP/FreeRDP#4122
* Support horizontal wheel properly #928
## Bug fixes
* Avoid use of hard-coded sesman port #895
* Workaround for corrupted display with Windows Server 2008 using NeutrinoRDP #869
* Fix glitch in audio redirection by AAC #910 #936
* Implement vsock support #930 #935 #948
* Avoid 100% CPU usage on SSL accept #956
## Other changes
* Add US Dvorak keyboard #929
* Suppress some misleading logs #964
* Add Finnish keyboard #972
* Add more user-friendlier description about Xorg config #974
* Renew pulseaudio document #984 #985
* Lots of cleanups and refactoring
## Known issues
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.4 (2017/09/28)
## New features
@ -22,6 +53,8 @@
* Windows 10 (1703) shows black blank screen in RemoteFX mode
* This issue is already fixed at Insider Preview build 16273
-----------------------
# Release notes for xrdp v0.9.3.1 (2017/08/16)
This release fixes a trivial packaging issue #848 occurred in v0.9.3. The issue only affects systemd systems. This release is principally for distro packagers or users who compile & install xrdp from source.
@ -31,6 +64,8 @@ Users who running xrdp on these systems don't need to upgrade from v0.9.3 to v0.
* Linux systems without systemd
* non-Linux systems such as BSD operating systems
-----------------------
# Release notes for xrdp v0.9.3 (2017/07/15)
## New features

View File

@ -2,7 +2,7 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp)
![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
*Current Version:* 0.9.4
*Current Version:* 0.9.5
# xrdp - an open source RDP server
@ -29,7 +29,7 @@ RDP transport is encrypted using TLS by default.
### Access to Remote Resources
* two-way clipboard transfer (text, bitmap, file)
* audio redirection
* audio redirection ([requires to build additional modules](https://github.com/neutrinolabs/xrdp/wiki/How-to-set-up-audio-redirection))
* drive redirection (mount local client drives on remote machine)
## Quick Start
@ -114,6 +114,11 @@ make
sudo make install
```
If you want to use audio redirection, you need to build and install additional
pulseaudio modules. The build instructions can be found at wiki.
* [How to set up audio redirection](https://github.com/neutrinolabs/xrdp/wiki/How-to-set-up-audio-redirection)
## Directory Structure
```

View File

@ -33,7 +33,6 @@ libcommon_la_SOURCES = \
arch.h \
base64.h \
base64.c \
crc16.h \
defines.h \
fifo.c \
fifo.h \

View File

View File

@ -94,6 +94,7 @@ internal_log_xrdp2syslog(const enum logLevels lvl)
case LOG_LEVEL_INFO:
return LOG_INFO;
case LOG_LEVEL_DEBUG:
case LOG_LEVEL_TRACE:
return LOG_DEBUG;
default:
g_writeln("Undefined log level - programming error");
@ -128,6 +129,9 @@ internal_log_lvl2str(const enum logLevels lvl, char *str)
case LOG_LEVEL_DEBUG:
snprintf(str, 9, "%s", "[DEBUG] ");
break;
case LOG_LEVEL_TRACE:
snprintf(str, 9, "%s", "[TRACE] ");
break;
default:
snprintf(str, 9, "%s", "PRG ERR!");
g_writeln("Programming error - undefined log level!!!");
@ -194,9 +198,6 @@ internal_log_end(struct log_config *l_cfg)
return ret;
}
/* closing log file */
log_message(LOG_LEVEL_ALWAYS, "shutting down log subsystem...");
if (-1 != l_cfg->fd)
{
/* closing logfile... */
@ -254,6 +255,11 @@ internal_log_text2level(const char *buf)
{
return LOG_LEVEL_DEBUG;
}
else if (0 == g_strcasecmp(buf, "5") ||
0 == g_strcasecmp(buf, "trace"))
{
return LOG_LEVEL_TRACE;
}
g_writeln("Your configured log level is corrupt - we use debug log level");
return LOG_LEVEL_DEBUG;

View File

@ -33,7 +33,8 @@ enum logLevels
LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG
LOG_LEVEL_DEBUG,
LOG_LEVEL_TRACE
};
/* startup return values */

View File

@ -41,6 +41,9 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#if defined(XRDP_ENABLE_VSOCK)
#include <linux/vm_sockets.h>
#endif
#include <sys/un.h>
#include <sys/time.h>
#include <sys/times.h>
@ -576,12 +579,23 @@ int
g_sck_local_socket(void)
{
#if defined(_WIN32)
return 0;
return -1;
#else
return socket(PF_LOCAL, SOCK_STREAM, 0);
#endif
}
/*****************************************************************************/
int
g_sck_vsock_socket(void)
{
#if defined(XRDP_ENABLE_VSOCK)
return socket(PF_VSOCK, SOCK_STREAM, 0);
#else
return -1;
#endif
}
/*****************************************************************************/
/* returns error */
int
@ -655,6 +669,9 @@ g_sck_close(int sck)
struct sockaddr_in sock_addr_in;
#if defined(XRDP_ENABLE_IPV6)
struct sockaddr_in6 sock_addr_in6;
#endif
#if defined(XRDP_ENABLE_VSOCK)
struct sockaddr_vm sock_addr_vm;
#endif
} sock_info;
socklen_t sock_len = sizeof(sock_info);
@ -695,6 +712,22 @@ g_sck_close(int sck)
g_snprintf(sockname, sizeof(sockname), "AF_UNIX");
break;
#if defined(XRDP_ENABLE_VSOCK)
case AF_VSOCK:
{
struct sockaddr_vm *sock_addr_vm = &sock_info.sock_addr_vm;
g_snprintf(sockname,
sizeof(sockname),
"AF_VSOCK cid %d port %d",
sock_addr_vm->svm_cid,
sock_addr_vm->svm_port);
break;
}
#endif
default:
g_snprintf(sockname, sizeof(sockname), "unknown family %d",
sock_info.sock_addr.sa_family);
@ -990,6 +1023,24 @@ g_sck_local_bind(int sck, const char *port)
#endif
}
/*****************************************************************************/
int
g_sck_vsock_bind(int sck, const char *port)
{
#if defined(XRDP_ENABLE_VSOCK)
struct sockaddr_vm s;
g_memset(&s, 0, sizeof(struct sockaddr_vm));
s.svm_family = AF_VSOCK;
s.svm_port = atoi(port);
s.svm_cid = VMADDR_CID_ANY;
return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_vm));
#else
return -1;
#endif
}
#if defined(XRDP_ENABLE_IPV6)
/*****************************************************************************/
/* Helper function for g_tcp_bind_address. */
@ -1180,9 +1231,9 @@ g_tcp_accept(int sck)
{
struct sockaddr_in *sock_addr_in = &sock_info.sock_addr_in;
snprintf(msg, sizeof(msg), "A connection received from %s port %d",
inet_ntoa(sock_addr_in->sin_addr),
ntohs(sock_addr_in->sin_port));
g_snprintf(msg, sizeof(msg), "A connection received from %s port %d",
inet_ntoa(sock_addr_in->sin_addr),
ntohs(sock_addr_in->sin_port));
log_message(LOG_LEVEL_INFO, "%s", msg);
break;
@ -1197,8 +1248,8 @@ g_tcp_accept(int sck)
inet_ntop(sock_addr_in6->sin6_family,
&sock_addr_in6->sin6_addr, addr, sizeof(addr));
snprintf(msg, sizeof(msg), "A connection received from %s port %d",
addr, ntohs(sock_addr_in6->sin6_port));
g_snprintf(msg, sizeof(msg), "A connection received from %s port %d",
addr, ntohs(sock_addr_in6->sin6_port));
log_message(LOG_LEVEL_INFO, "%s", msg);
break;
@ -1226,6 +1277,9 @@ g_sck_accept(int sck, char *addr, int addr_bytes, char *port, int port_bytes)
struct sockaddr_in6 sock_addr_in6;
#endif
struct sockaddr_un sock_addr_un;
#if defined(XRDP_ENABLE_VSOCK)
struct sockaddr_vm sock_addr_vm;
#endif
} sock_info;
socklen_t sock_len = sizeof(sock_info);
@ -1273,6 +1327,26 @@ g_sck_accept(int sck, char *addr, int addr_bytes, char *port, int port_bytes)
g_snprintf(msg, sizeof(msg), "AF_UNIX connection received");
break;
}
#if defined(XRDP_ENABLE_VSOCK)
case AF_VSOCK:
{
struct sockaddr_vm *sock_addr_vm = &sock_info.sock_addr_vm;
g_snprintf(addr, addr_bytes - 1, "%d", sock_addr_vm->svm_cid);
g_snprintf(port, addr_bytes - 1, "%d", sock_addr_vm->svm_port);
g_snprintf(msg,
sizeof(msg),
"AF_VSOCK connection received from cid: %s port: %s",
addr,
port);
break;
}
#endif
default:
{
g_strncpy(addr, "", addr_bytes - 1);
@ -1358,13 +1432,13 @@ g_write_ip_address(int rcv_sck, char *ip_address, int bytes)
if (ok)
{
snprintf(ip_address, bytes, "%s:%d - socket: %d", addr, port, rcv_sck);
g_snprintf(ip_address, bytes, "%s:%d - socket: %d", addr, port, rcv_sck);
}
}
if (!ok)
{
snprintf(ip_address, bytes, "NULL:NULL - socket: %d", rcv_sck);
g_snprintf(ip_address, bytes, "NULL:NULL - socket: %d", rcv_sck);
}
g_free(addr);

View File

@ -62,6 +62,7 @@ int g_sck_get_send_buffer_bytes(int sck, int *bytes);
int g_sck_set_recv_buffer_bytes(int sck, int bytes);
int g_sck_get_recv_buffer_bytes(int sck, int *bytes);
int g_sck_local_socket(void);
int g_sck_vsock_socket(void);
int g_sck_get_peer_cred(int sck, int *pid, int *uid, int *gid);
void g_sck_close(int sck);
int g_tcp_connect(int sck, const char* address, const char* port);
@ -69,6 +70,7 @@ int g_sck_local_connect(int sck, const char* port);
int g_sck_set_non_blocking(int sck);
int g_tcp_bind(int sck, const char *port);
int g_sck_local_bind(int sck, const char* port);
int g_sck_vsock_bind(int sck, const char* port);
int g_tcp_bind_address(int sck, const char* port, const char* address);
int g_sck_listen(int sck);
int g_tcp_accept(int sck);

View File

@ -651,6 +651,15 @@ ssl_tls_accept(struct ssl_tls *self, long ssl_protocols,
* SSL_ERROR_WANT_READ
* SSL_ERROR_WANT_WRITE
*/
switch (SSL_get_error(self->ssl, connection_status))
{
case SSL_ERROR_WANT_READ:
g_sck_can_recv(self->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
break;
case SSL_ERROR_WANT_WRITE:
g_sck_can_send(self->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
break;
}
}
else
{

View File

@ -831,6 +831,26 @@ trans_listen_address(struct trans *self, char *port, const char *address)
}
}
}
else if (self->mode == TRANS_MODE_VSOCK) /* vsock socket */
{
self->sck = g_sck_vsock_socket();
if (self->sck < 0)
{
return 1;
}
g_tcp_set_non_blocking(self->sck);
if (g_sck_vsock_bind(self->sck, port) == 0)
{
if (g_tcp_listen(self->sck) == 0)
{
self->status = TRANS_STATUS_UP; /* ok */
self->type1 = TRANS_TYPE_LISTENER; /* listener */
return 0;
}
}
}
return 1;
}

View File

@ -26,6 +26,7 @@
#define TRANS_MODE_TCP 1
#define TRANS_MODE_UNIX 2
#define TRANS_MODE_VSOCK 3
#define TRANS_TYPE_LISTENER 1
#define TRANS_TYPE_SERVER 2
@ -62,7 +63,7 @@ struct source_info
struct trans
{
tbus sck; /* socket handle */
int mode; /* 1 tcp, 2 unix socket */
int mode; /* 1 tcp, 2 unix socket, 3 vsock */
int status;
int type1; /* 1 listener 2 server 3 client */
ttrans_data_in trans_data_in;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script
AC_PREREQ(2.65)
AC_INIT([xrdp], [0.9.4], [xrdp-devel@googlegroups.com])
AC_INIT([xrdp], [0.9.5], [xrdp-devel@googlegroups.com])
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
AM_INIT_AUTOMAKE([1.7.2 foreign])
AC_CONFIG_MACRO_DIR([m4])
@ -70,6 +70,9 @@ AC_ARG_ENABLE(pam, AS_HELP_STRING([--disable-pam],
[Build PAM support (default: yes)]),
[], [enable_pam=yes])
AM_CONDITIONAL(SESMAN_NOPAM, [test x$enable_pam != xyes])
AC_ARG_ENABLE(vsock, AS_HELP_STRING([--enable-vsock],
[Build AF_VSOCK support (default: no)]),
[], [enable_vsock=no])
AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--enable-ipv6],
[Build IPv6 support (default: no, experimental)]),
[], [enable_ipv6=no])
@ -197,6 +200,15 @@ fi
AC_SUBST(PAM_RULES)
if test "x$enable_vsock" = "xyes"
then
enable_vsock=yes
AC_CHECK_HEADERS([linux/socket.h linux/vm_sockets.h],
[AC_DEFINE([XRDP_ENABLE_VSOCK], 1, [Enable AF_VSOCK])],
[],
[#include <sys/socket.h>])
fi
if test "x$enable_ipv6only" = "xyes"
then
enable_ipv6=yes

View File

@ -11,6 +11,10 @@ fi
setxkbmap -model pc104 -layout us
./xrdp-genkeymap ../instfiles/km-00000409.ini
# English - US 'dvorak' 0x00010409
setxkbmap -model pc104 -layout dvorak
./xrdp-genkeymap ../instfiles/km-00010409.ini
# English - UK 'en-GB' 0x00000809
setxkbmap -model pc105 -layout gb
./xrdp-genkeymap ../instfiles/km-00000809.ini

View File

@ -48,7 +48,8 @@ dist_startscript_DATA = \
km-0000080c.ini \
km-00000813.ini \
km-00000816.ini \
km-0000100c.ini
km-0000100c.ini \
km-00010409.ini
#
# platform specific files

1055
instfiles/km-00010409.ini Normal file

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit 631f7ee053e9b38984d838e5aff02c4abc8c6d90
Subproject commit ef68593b7d19c89cff2a2d27c6ab3cc5f33611da

View File

@ -610,90 +610,90 @@ xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
len -= 4;
switch (type)
{
case RDP_CAPSET_GENERAL: /* 1 */
case RDP_CAPSET_GENERAL:
DEBUG(("RDP_CAPSET_GENERAL"));
xrdp_caps_process_general(self, s, len);
break;
case RDP_CAPSET_BITMAP: /* 2 */
case RDP_CAPSET_BITMAP:
DEBUG(("RDP_CAPSET_BITMAP"));
break;
case RDP_CAPSET_ORDER: /* 3 */
case RDP_CAPSET_ORDER:
DEBUG(("RDP_CAPSET_ORDER"));
xrdp_caps_process_order(self, s, len);
break;
case RDP_CAPSET_BMPCACHE: /* 4 */
case RDP_CAPSET_BMPCACHE:
DEBUG(("RDP_CAPSET_BMPCACHE"));
xrdp_caps_process_bmpcache(self, s, len);
break;
case RDP_CAPSET_CONTROL: /* 5 */
case RDP_CAPSET_CONTROL:
DEBUG(("RDP_CAPSET_CONTROL"));
break;
case 6:
xrdp_caps_process_cache_v3_codec_id(self, s, len);
break;
case RDP_CAPSET_ACTIVATE: /* 7 */
case RDP_CAPSET_ACTIVATE:
DEBUG(("RDP_CAPSET_ACTIVATE"));
break;
case RDP_CAPSET_POINTER: /* 8 */
case RDP_CAPSET_POINTER:
DEBUG(("RDP_CAPSET_POINTER"));
xrdp_caps_process_pointer(self, s, len);
break;
case RDP_CAPSET_SHARE: /* 9 */
case RDP_CAPSET_SHARE:
DEBUG(("RDP_CAPSET_SHARE"));
break;
case RDP_CAPSET_COLCACHE: /* 10 */
case RDP_CAPSET_COLCACHE:
DEBUG(("RDP_CAPSET_COLCACHE"));
break;
case 12: /* 12 */
DEBUG(("--12"));
case RDP_CAPSET_SOUND:
DEBUG(("--0x0C"));
break;
case 13: /* 13 */
case RDP_CAPSET_INPUT:
xrdp_caps_process_input(self, s, len);
break;
case 14: /* 14 */
DEBUG(("--14"));
case RDP_CAPSET_FONT:
DEBUG(("--0x0D"));
break;
case RDP_CAPSET_BRUSHCACHE: /* 15 */
case RDP_CAPSET_BRUSHCACHE:
xrdp_caps_process_brushcache(self, s, len);
break;
case 16: /* 16 */
DEBUG(("--16"));
case RDP_CAPSET_GLYPHCACHE:
DEBUG(("--0x11"));
break;
case 17: /* 17 */
case RDP_CAPSET_OFFSCREENCACHE:
DEBUG(("CAPSET_TYPE_OFFSCREEN_CACHE"));
xrdp_caps_process_offscreen_bmpcache(self, s, len);
break;
case RDP_CAPSET_BMPCACHE2: /* 19 */
case RDP_CAPSET_BMPCACHE2:
DEBUG(("RDP_CAPSET_BMPCACHE2"));
xrdp_caps_process_bmpcache2(self, s, len);
break;
case 20: /* 20 */
DEBUG(("--20"));
case RDP_CAPSET_VIRCHAN:
DEBUG(("--0x14"));
break;
case 21: /* 21 */
DEBUG(("--21"));
case RDP_CAPSET_DRAWNINEGRIDCACHE:
DEBUG(("--0x15"));
break;
case 22: /* 22 */
DEBUG(("--22"));
case RDP_CAPSET_DRAWGDIPLUS:
DEBUG(("--0x16"));
break;
case 0x0017: /* 23 CAPSETTYPE_RAIL */
case RDP_CAPSET_RAIL:
xrdp_caps_process_rail(self, s, len);
break;
case 0x0018: /* 24 CAPSETTYPE_WINDOW */
case RDP_CAPSET_WINDOW:
xrdp_caps_process_window(self, s, len);
break;
case 0x001A: /* 26 CAPSETTYPE_MULTIFRAGMENTUPDATE */
case RDP_CAPSET_MULTIFRAGMENT:
xrdp_caps_process_multifragmentupdate(self, s, len);
break;
case RDP_CAPSET_BMPCODECS: /* 0x1d(29) */
case RDP_CAPSET_SURFCMDS:
xrdp_caps_process_surface_cmds(self, s, len);
break;
case RDP_CAPSET_BMPCODECS:
xrdp_caps_process_codecs(self, s, len);
break;
case 0x001E: /* CAPSSETTYPE_FRAME_ACKNOWLEDGE */
case RDP_CAPSET_FRAME_ACKNOWLEDGE:
xrdp_caps_process_frame_ack(self, s, len);
break;
case RDP_CAPSET_SURFCMDS: /* CAPSETTYPE_SURFACE_COMMANDS */
xrdp_caps_process_surface_cmds(self, s, len);
break;
default:
g_writeln("unknown in xrdp_caps_process_confirm_active %d", type);
break;
@ -924,7 +924,11 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self)
out_uint16_le(s, RDP_CAPSET_INPUT); /* 13(0xd) */
out_uint16_le(s, RDP_CAPLEN_INPUT); /* 88(0x58) */
flags = INPUT_FLAG_SCANCODES | INPUT_FLAG_MOUSEX | INPUT_FLAG_UNICODE;
flags = INPUT_FLAG_SCANCODES |
INPUT_FLAG_MOUSEX |
INPUT_FLAG_UNICODE |
TS_INPUT_FLAG_MOUSE_HWHEEL;
if (self->client_info.use_fast_path & 2)
{
flags |= INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2;

View File

@ -1608,10 +1608,10 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec* self, struct stream* s)
g_writeln("colorDepth 0x%4.4x (0xca00 4bpp 0xca01 8bpp)", colorDepth);
switch (colorDepth)
{
case 0xca00: /* RNS_UD_COLOR_4BPP */
case RNS_UD_COLOR_4BPP:
self->rdp_layer->client_info.bpp = 4;
break;
case 0xca01: /* RNS_UD_COLOR_8BPP */
case RNS_UD_COLOR_8BPP:
self->rdp_layer->client_info.bpp = 8;
break;
}
@ -1630,19 +1630,19 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec* self, struct stream* s)
switch (postBeta2ColorDepth)
{
case 0xca00: /* RNS_UD_COLOR_4BPP */
case RNS_UD_COLOR_4BPP:
self->rdp_layer->client_info.bpp = 4;
break;
case 0xca01: /* RNS_UD_COLOR_8BPP */
case RNS_UD_COLOR_8BPP :
self->rdp_layer->client_info.bpp = 8;
break;
case 0xca02: /* RNS_UD_COLOR_16BPP_555 */
case RNS_UD_COLOR_16BPP_555:
self->rdp_layer->client_info.bpp = 15;
break;
case 0xca03: /* RNS_UD_COLOR_16BPP_565 */
case RNS_UD_COLOR_16BPP_565:
self->rdp_layer->client_info.bpp = 16;
break;
case 0xca04: /* RNS_UD_COLOR_24BPP */
case RNS_UD_COLOR_24BPP:
self->rdp_layer->client_info.bpp = 24;
break;
}

View File

@ -1468,7 +1468,9 @@ lfreerdp_pre_connect(freerdp *instance)
instance->settings->glyph_cache = true;
/* GLYPH_SUPPORT_FULL and GLYPH_SUPPORT_PARTIAL seem to be the same */
instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL;
/* disabled as workaround for corrupted display like black bars left of cmd with W2K8 */
/* instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; */
instance->settings->glyphSupportLevel = GLYPH_SUPPORT_NONE;
instance->settings->order_support[NEG_DSTBLT_INDEX] = 1; /* 0x00 */
instance->settings->order_support[NEG_PATBLT_INDEX] = 1;
@ -1497,7 +1499,10 @@ lfreerdp_pre_connect(freerdp *instance)
instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = 0; /* 0x18 */
instance->settings->order_support[NEG_ELLIPSE_SC_INDEX] = 0;
instance->settings->order_support[NEG_ELLIPSE_CB_INDEX] = 0;
instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = 1;
/* disabled as workaround for corrupted display like black bars left of cmd with W2K8 */
/* instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = 1; */
instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = 0;
instance->settings->order_support[NEG_GLYPH_WEXTTEXTOUT_INDEX] = 0;
instance->settings->order_support[NEG_GLYPH_WLONGTEXTOUT_INDEX] = 0;
instance->settings->order_support[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX] = 0;

View File

@ -1451,7 +1451,8 @@ get_log_level(const char* level_str, enum logLevels default_level)
"LOG_LEVEL_ERROR",
"LOG_LEVEL_WARNING",
"LOG_LEVEL_INFO",
"LOG_LEVEL_DEBUG"
"LOG_LEVEL_DEBUG",
"LOG_LEVEL_TRACE"
};
unsigned int i;

View File

@ -0,0 +1,117 @@
The latest version of this document can be found at wiki.
* https://github.com/neutrinolabs/xrdp/wiki/How-to-set-up-audio-redirection
# Overview
xrdp supports audio redirection using PulseAudio, which is a sound system for
POSIX operating systems. Server to client redirection is compliant to Remote
Desktop Procol standard [[MS-RDPEA]](https://msdn.microsoft.com/en-us/library/cc240933.aspx)
but client to server redirection implementation is proprietary. Accordingly,
server to client redirection is available with many of RDP clients including
Microsoft client but client to server redirection requires NeutrinoRDP client,
not available with other clients.
Here is how to build pulseaudio modules for your distro, so you can have audio
support through xrdp.
# Prerequisites
Prepare xrdp source in your home directory. Of course, you can choose another
directory.
cd ~
git clone https://github.com/neutrinolabs/xrdp.git
In this instruction, pulseaudio version is **10.0**. Replace the version number
in this instruction if your environment has different versions. You can find
out your pulseaudio version executing the following command:
pulseaudio --version
# How to build
## Debian 9 / Ubuntu
This instruction also should be applicable to Ubuntu family.
### Prerequisites
Some build tools and package development tools are required. Make sure install
the tools.
apt install build-essential dpkg-dev
### Prepare & build
Install pulseaudio and requisite packages to build pulseaudio.
apt install pulseaudio
apt build-dep pulseaudio
Fetch the pulseaudio source . You'll see `pulseaudio-10.0` directory in your
current directory.
apt source pulseaudio
Enter into the directory and build the pulseaudio package.
cd pulseaudio-10.0
./configure
Finally, let's make. You'll have two .so files `module-xrdp-sink.so` and
`module-xrdp-source.so`.
cd ~/xrdp/sesman/chansrv/pulse
make PULSE_DIR="~/pulseaudio-10.0"
## Other distro
First off, find out your pulseaudio version using `pulseaudio --version`
command. Download the tarball of the pulseaudio version that you have.
* https://freedesktop.org/software/pulseaudio/releases/
After downloading the tarball, extact the tarball and `cd` into the source
directory, then run `./configure`.
wget https://freedesktop.org/software/pulseaudio/releases/pulseaudio-10.0.tar.xz
tar xf pulseaudio-10.0.tar.gz
cd pulseaudio-10.0
./configure
If additional packages are required to run `./configure`, install requisite
packages depending on your environment.
Finally, let's make. You'll have two .so files `module-xrdp-sink.so` and
`module-xrdp-source.so`.
cd ~/xrdp/sesman/chansrv/pulse
make PULSE_DIR="~/pulseaudio-10.0"
# Install
Install process is not distro specific except for install destination. Install
built two .so files into the pulseaudio modules directory. Typically,
`/usr/lib/pulse-10.0/modules` for Debian, `/usr/lib64/pulse-10.0/modules` for
CentOS 7. Other distro might have different path. Find out the right path for
your distro.
Look into the directory with `ls` command. You'll see lots of `module-*.so`
files. There's the place!
cd ~/xrdp/sesman/chansrv/pulse
for f in *.so; do install -s -m 644 $f /usr/lib/pulse-10.0/modules; done
This command is equivalent to following:
install -s -m 644 module-xrdp-sink.so /usr/lib/pulse-10.0/modules
install -s -m 644 module-xrdp-source.so /usr/lib/pulse-10.0/modules
Well done! Pulseaudio modules should be properly built and installed.
# See if it works
To see if it works, run `pavumeter` in the xrdp session. Playback any YouTube
video in Firefox. You'll see "Showing signal levels of **xrdp sink**" and
volume meter moving.

View File

@ -1,79 +0,0 @@
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
---------------------------------
To see a list of sinks
pacmd list-sinks
To manually load a sink
pactl load-module module-xrdp-sink.so sink_name=test

View File

@ -1,77 +0,0 @@
--------------------------------------
Building pulseaudio modules for xrdp
--------------------------------------
o append the following line to /etc/apt/sources.list
deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
this is what my /etc/apt/sources.list looks like
deb http://packages.linuxmint.com/ maya main upstream import
deb http://archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ precise-security main restricted universe multiverse
deb http://archive.canonical.com/ubuntu/ precise partner
deb http://packages.medibuntu.org/ precise free non-free
#deb http://archive.getdeb.net/ubuntu precise-getdeb apps
#deb http://archive.getdeb.net/ubuntu precise-getdeb games
deb http://drbl.sourceforge.net/drbl-core drbl stable
deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
NOTE: If you get an error message that goes something like this:
E: You must put some 'source' URIs in your sources.list
try running the following command first:
apt-get source pulseaudio
o run these commands in your home directory
cd
sudo apt-get install dpkg-dev
apt-get source pulseaudio
sudo apt-get build-dep pulseaudio
cd pulseaudio-1.1
dpkg-buildpackage -rfakeroot -uc -b
o edit Makefile and point PULSE_DIR to ~/pulseaudio<version> dir
o run make; the outputs will be
module-xrdp-sink.so
module-xrdp-source.so
o sudo cp module-xrdp-sink.so /usr/lib/pulse-<version>/modules
sudo cp module-xrdp-source.so /usr/lib/pulse-<version>/modules
note: on a 64bit machine use lib64 instead of lib
o if you build xrdp with --enable-load_pulse_modules, then the above modules
will get loaded automatically when xrdp starts. However if --enable-load_pulse_modules
is not used, then you need to edit /etc/pulse/default.pa and insert the following
two lines into it:
load-module module-xrdp-sink
load-module module-xrdp-source
--------------------------------------
To test sound/microphone redirection
--------------------------------------
o install gnome sound recorder or your favorite sound recorder
o mplayer -ao pulse <audio file>
o sudo apt-get install pavucontrol
o in another window run pavucontrol and you should see xrdp-sink in use
o to enable pulseaudio log
o edit /etc/pulse/daemon.conf and set
log-target = syslog
log-level = notice
o pulseaudio --kill
o log output will be in /var/log/syslog or /var/log/messages

View File

@ -400,19 +400,16 @@ sound_process_output_format(int aindex, int wFormatTag, int nChannels,
LOG(0, ("wFormatTag, fdk aac"));
g_client_does_fdk_aac = 1;
g_client_fdk_aac_index = aindex;
g_bbuf_size = 4096;
break;
case WAVE_FORMAT_MPEGLAYER3:
LOG(0, ("wFormatTag, mp3"));
g_client_does_mp3lame = 1;
g_client_mp3lame_index = aindex;
g_bbuf_size = 11520;
break;
case WAVE_FORMAT_OPUS:
LOG(0, ("wFormatTag, opus"));
g_client_does_opus = 1;
g_client_opus_index = aindex;
g_bbuf_size = 11520;
break;
}
@ -840,14 +837,17 @@ sound_wave_compress(char *data, int data_bytes, int *format_index)
{
if (g_client_does_fdk_aac)
{
g_bbuf_size = 4096;
return sound_wave_compress_fdk_aac(data, data_bytes, format_index);
}
else if (g_client_does_opus)
{
g_bbuf_size = 11520;
return sound_wave_compress_opus(data, data_bytes, format_index);
}
else if (g_client_does_mp3lame)
{
g_bbuf_size = 11520;
return sound_wave_compress_mp3lame(data, data_bytes, format_index);
}
return data_bytes;

View File

@ -161,7 +161,7 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
struct SCP_SESSION *session = 0;
tui16 sz;
tui32 code = 0;
char buf[257];
char *buf = 0;
if (!skipVchk)
{
@ -226,27 +226,31 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
/* reading username */
in_uint16_be(c->in_s, sz);
buf[sz] = '\0';
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
if (0 != scp_session_set_username(session, buf))
{
scp_session_destroy(session);
log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);
g_free(buf);
return SCP_SERVER_STATE_INTERNAL_ERR;
}
g_free(buf);
/* reading password */
in_uint16_be(c->in_s, sz);
buf[sz] = '\0';
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
if (0 != scp_session_set_password(session, buf))
{
scp_session_destroy(session);
log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__);
g_free(buf);
return SCP_SERVER_STATE_INTERNAL_ERR;
}
g_free(buf);
/* width */
in_uint16_be(c->in_s, sz);
@ -272,9 +276,11 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
if (sz > 0)
{
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
scp_session_set_domain(session, buf);
g_free(buf);
}
}
@ -285,9 +291,11 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
if (sz > 0)
{
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
scp_session_set_program(session, buf);
g_free(buf);
}
}
@ -298,9 +306,11 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
if (sz > 0)
{
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
scp_session_set_directory(session, buf);
g_free(buf);
}
}
@ -311,9 +321,11 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
if (sz > 0)
{
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
scp_session_set_client_ip(session, buf);
g_free(buf);
}
}
}
@ -332,29 +344,35 @@ scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
scp_session_set_type(session, SCP_GW_AUTHENTICATION);
/* reading username */
in_uint16_be(c->in_s, sz);
buf[sz] = '\0';
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
/* g_writeln("Received user name: %s",buf); */
if (0 != scp_session_set_username(session, buf))
{
scp_session_destroy(session);
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);*/
g_free(buf);
return SCP_SERVER_STATE_INTERNAL_ERR;
}
g_free(buf);
/* reading password */
in_uint16_be(c->in_s, sz);
buf[sz] = '\0';
buf = g_new0(char, sz + 1);
in_uint8a(c->in_s, buf, sz);
buf[sz] = '\0';
/* g_writeln("Received password: %s",buf); */
if (0 != scp_session_set_password(session, buf))
{
scp_session_destroy(session);
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */
g_free(buf);
return SCP_SERVER_STATE_INTERNAL_ERR;
}
g_free(buf);
}
else
{

View File

@ -54,6 +54,30 @@ LogLevel=DEBUG
EnableSyslog=1
SyslogLevel=DEBUG
;
; Session definitions - startup command-line parameters for each session type
;
[Xorg]
; Specify the path of non-suid Xorg executable. It might differ depending
; on your distribution and version. The typical path is shown as follows:
;
; Fedora 26 or later : param=/usr/libexec/Xorg
; Debian 9 or later : param=/usr/lib/xorg/Xorg
; Ubuntu 16.04 or later : param=/usr/lib/xorg/Xorg
; Arch Linux : param=/usr/bin/Xorg or param=Xorg
; CentOS 7 : param=/usr/bin/Xorg or param=Xorg
;
param=Xorg
; Leave the rest paramaters as-is unless you understand what will happen.
param=-config
param=xrdp/xorg.conf
param=-noreset
param=-nolisten
param=tcp
param=-logfile
param=.xorgxrdp.%s.log
[X11rdp]
param=X11rdp
param=-bs
@ -70,16 +94,6 @@ param=-localhost
param=-dpi
param=96
[Xorg]
param=Xorg
param=-config
param=xrdp/xorg.conf
param=-noreset
param=-nolisten
param=tcp
param=-logfile
param=.xorgxrdp.%s.log
[Chansrv]
; drive redirection, defaults to xrdp_client if not set
FuseMountName=thinclient_drives

View File

@ -76,7 +76,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//#include "colormapst.h"
#define X11RDPVER "0.9.4"
#define X11RDPVER "0.9.5"
#define PixelDPI 100
#define PixelToMM(_size) (((_size) * 254 + (PixelDPI) * 5) / ((PixelDPI) * 10))

View File

@ -6,6 +6,8 @@ ini_version=1
fork=true
; tcp port to listen
port=3389
; 'port' above should be connected to with vsock instead of tcp
use_vsock=false
; regulate if the listening socket use socket option tcp_nodelay
; no buffering will be performed in the TCP stack
tcp_nodelay=true
@ -148,6 +150,9 @@ tcutils=true
; Session types
;
; Some session types such as Xorg, X11rdp and Xvnc start a display server.
; Startup command-line parameters for the display server are configured
; in sesman.ini. See and configure also sesman.ini.
[Xorg]
name=Xorg
lib=libxup.so

View File

@ -27,7 +27,6 @@
#include "xrdp.h"
#include "log.h"
#include "crc16.h"
#define LLOG_LEVEL 1
#define LLOGLN(_level, _args) \

View File

@ -24,7 +24,6 @@
#include "xrdp.h"
#include "log.h"
#include "crc16.h"
#define LLOG_LEVEL 1
#define LLOGLN(_level, _args) \

View File

@ -58,8 +58,10 @@ layouts_map=default_layouts_map
[default_rdp_layouts]
rdp_layout_us=0x00000409
rdp_layout_us_dvorak=0x00010409
rdp_layout_de=0x00000407
rdp_layout_es=0x0000040A
rdp_layout_fi=0x0000040B
rdp_layout_fr=0x0000040C
rdp_layout_it=0x00000410
rdp_layout_jp=0x00000411
@ -79,8 +81,10 @@ rdp_layout_pt=0x00000816
; <rdp layout name> = <X11 keyboard layout value>
[default_layouts_map]
rdp_layout_us=us
rdp_layout_us_dvorak=dvorak
rdp_layout_de=de
rdp_layout_es=es
rdp_layout_fi=fi
rdp_layout_fr=fr
rdp_layout_it=it
rdp_layout_jp=jp
@ -111,8 +115,10 @@ layouts_map=default_layouts_map
[rdp_layouts_map_mac]
rdp_layout_us=us
rdp_layout_us_dvorak=dvorak
rdp_layout_de=de
rdp_layout_es=es
rdp_layout_fi=fi
rdp_layout_fr=fr
rdp_layout_it=it
rdp_layout_jp=jp

View File

@ -153,6 +153,7 @@ static int
xrdp_listen_get_port_address(char *port, int port_bytes,
char *address, int address_bytes,
int *tcp_nodelay, int *tcp_keepalive,
int *mode,
struct xrdp_startup_params *startup_param)
{
int fd;
@ -170,6 +171,7 @@ xrdp_listen_get_port_address(char *port, int port_bytes,
/* see if port or address is in xrdp.ini file */
g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH);
fd = g_file_open(cfg_file);
*mode = TRANS_MODE_TCP;
*tcp_nodelay = 0 ;
*tcp_keepalive = 0 ;
@ -204,7 +206,14 @@ xrdp_listen_get_port_address(char *port, int port_bytes,
}
}
}
if (g_strcasecmp(val, "use_vsock") == 0)
{
val = (char *)list_get_item(values, index);
if (g_text2bool(val) == 1)
{
*mode = TRANS_MODE_VSOCK;
}
}
if (g_strcasecmp(val, "address") == 0)
{
val = (char *)list_get_item(values, index);
@ -355,6 +364,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
if (xrdp_listen_get_port_address(port, sizeof(port),
address, sizeof(address),
&tcp_nodelay, &tcp_keepalive,
&self->listen_trans->mode,
self->startup_params) != 0)
{
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: xrdp_listen_get_port failed");
@ -369,6 +379,11 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
/* not valid with UDS */
tcp_nodelay = 0;
}
else if (self->listen_trans->mode == TRANS_MODE_VSOCK)
{
/* not valid with VSOCK */
tcp_nodelay = 0;
}
/* Create socket */
error = trans_listen_address(self->listen_trans, port, address);
@ -461,15 +476,10 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
robjs[robjs_count++] = done_obj;
timeout = -1;
/* if (self->listen_trans != 0) */
if (trans_get_wait_objs(self->listen_trans, robjs,
&robjs_count) != 0)
{
if (trans_get_wait_objs(self->listen_trans, robjs,
&robjs_count) != 0)
{
log_message(LOG_LEVEL_ERROR,"Listening socket is in wrong state, "
"terminating listener");
break;
}
break;
}
/* wait - timeout -1 means wait indefinitely*/
@ -549,6 +559,13 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
{
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, possible port "
"already in use");
#if !defined(XRDP_ENABLE_VSOCK)
if (self->listen_trans->mode == TRANS_MODE_VSOCK)
{
log_message(LOG_LEVEL_ERROR,"xrdp_listen_main_loop: listen error, "
"vsock support not compiled and config requested");
}
#endif
}
self->status = -1;
@ -563,6 +580,7 @@ xrdp_listen_test(void)
{
int rv = 0;
char port[128];
int mode;
char address[256];
int tcp_nodelay;
int tcp_keepalive;
@ -579,6 +597,7 @@ xrdp_listen_test(void)
if (xrdp_listen_get_port_address(port, sizeof(port),
address, sizeof(address),
&tcp_nodelay, &tcp_keepalive,
&mode,
xrdp_listen->startup_params) != 0)
{
log_message(LOG_LEVEL_DEBUG, "xrdp_listen_test: "

View File

@ -1306,7 +1306,7 @@ xrdp_mm_get_sesman_port(char *port, int port_bytes)
g_memset(cfg_file, 0, sizeof(char) * 256);
/* default to port 3350 */
g_strncpy(port, "3350", port_bytes - 1);
/* see if port is in xrdp.ini file */
/* see if port is in sesman.ini file */
g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH);
fd = g_file_open(cfg_file);
@ -1471,11 +1471,13 @@ access_control(char *username, char *password, char *srv)
unsigned long size;
int index;
int socket = g_tcp_socket();
char port[8];
if (socket != -1)
{
xrdp_mm_get_sesman_port(port, sizeof(port));
/* we use a blocking socket here */
reply = g_tcp_connect(socket, srv, "3350");
reply = g_tcp_connect(socket, srv, port);
if (reply == 0)
{

View File

@ -1264,6 +1264,8 @@ xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down)
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3UP, x, y, 0, 0);
}
/* vertical scroll */
if (but == 4)
{
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4DOWN,
@ -1279,21 +1281,23 @@ xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down)
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5UP,
self->mouse_x, self->mouse_y, 0, 0);
}
if (but == 6 && down)
/* horizontal scroll */
if (but == 6)
{
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6DOWN, x, y, 0, 0);
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6DOWN,
self->mouse_x, self->mouse_y, 0, 0);
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6UP,
self->mouse_x, self->mouse_y, 0, 0);
}
else if (but == 6 && !down)
if (but == 7)
{
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON6UP, x, y, 0, 0);
}
if (but == 7 && down)
{
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7DOWN, x, y, 0, 0);
}
else if (but == 7 && !down)
{
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7UP, x, y, 0, 0);
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7DOWN,
self->mouse_x, self->mouse_y, 0, 0);
self->mm->mod->mod_event(self->mm->mod, WM_BUTTON7UP,
self->mouse_x, self->mouse_y, 0, 0);
}
}
}
@ -1638,14 +1642,14 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags,
{
DEBUG(("mouse event flags %4.4x x %d y %d", device_flags, x, y));
if (device_flags & MOUSE_FLAG_MOVE) /* 0x0800 */
if (device_flags & PTRFLAGS_MOVE)
{
xrdp_wm_mouse_move(self, x, y);
}
if (device_flags & MOUSE_FLAG_BUTTON1) /* 0x1000 */
if (device_flags & PTRFLAGS_BUTTON1)
{
if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */
if (device_flags & PTRFLAGS_DOWN)
{
xrdp_wm_mouse_click(self, x, y, 1, 1);
}
@ -1655,9 +1659,9 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags,
}
}
if (device_flags & MOUSE_FLAG_BUTTON2) /* 0x2000 */
if (device_flags & PTRFLAGS_BUTTON2)
{
if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */
if (device_flags & PTRFLAGS_DOWN)
{
xrdp_wm_mouse_click(self, x, y, 2, 1);
}
@ -1667,9 +1671,9 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags,
}
}
if (device_flags & MOUSE_FLAG_BUTTON3) /* 0x4000 */
if (device_flags & PTRFLAGS_BUTTON3)
{
if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */
if (device_flags & PTRFLAGS_DOWN)
{
xrdp_wm_mouse_click(self, x, y, 3, 1);
}
@ -1679,9 +1683,10 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags,
}
}
if (device_flags & 0x200) /* PTRFLAGS_WHEEL */
/* vertical mouse wheel */
if (device_flags & PTRFLAGS_WHEEL)
{
if (device_flags & 0x100) /* PTRFLAGS_WHEEL_NEGATIVE */
if (device_flags & PTRFLAGS_WHEEL_NEGATIVE)
{
xrdp_wm_mouse_click(self, 0, 0, 5, 0);
}
@ -1691,6 +1696,24 @@ xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags,
}
}
/* horizontal mouse wheel */
/**
* As mstsc does MOUSE not MOUSEX for horizontal scrolling,
* PTRFLAGS_HWHEEL must be handled here.
*/
if (device_flags & PTRFLAGS_HWHEEL)
{
if (device_flags & PTRFLAGS_WHEEL_NEGATIVE)
{
xrdp_wm_mouse_click(self, 0, 0, 6, 0);
}
else
{
xrdp_wm_mouse_click(self, 0, 0, 7, 0);
}
}
return 0;
}
@ -1699,24 +1722,24 @@ static int
xrdp_wm_process_input_mousex(struct xrdp_wm* self, int device_flags,
int x, int y)
{
if (device_flags & 0x8000) /* PTRXFLAGS_DOWN */
if (device_flags & PTRXFLAGS_DOWN)
{
if (device_flags & 0x0001) /* PTRXFLAGS_BUTTON1 */
if (device_flags & PTRXFLAGS_BUTTON1)
{
xrdp_wm_mouse_click(self, x, y, 6, 1);
}
else if (device_flags & 0x0002) /* PTRXFLAGS_BUTTON2 */
else if (device_flags & PTRXFLAGS_BUTTON2)
{
xrdp_wm_mouse_click(self, x, y, 7, 1);
}
}
else
{
if (device_flags & 0x0001) /* PTRXFLAGS_BUTTON1 */
if (device_flags & PTRXFLAGS_BUTTON1)
{
xrdp_wm_mouse_click(self, x, y, 6, 0);
}
else if (device_flags & 0x0002) /* PTRXFLAGS_BUTTON2 */
else if (device_flags & PTRXFLAGS_BUTTON2)
{
xrdp_wm_mouse_click(self, x, y, 7, 0);
}
@ -1789,19 +1812,19 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
switch (msg)
{
case 0: /* RDP_INPUT_SYNCHRONIZE */
case RDP_INPUT_SYNCHRONIZE:
rv = xrdp_wm_key_sync(wm, param3, param1);
break;
case 4: /* RDP_INPUT_SCANCODE */
case RDP_INPUT_SCANCODE:
rv = xrdp_wm_key(wm, param3, param1);
break;
case 5: /* RDP_INPUT_UNICODE */
case RDP_INPUT_UNICODE:
rv = xrdp_wm_key_unicode(wm, param3, param1);
break;
case 0x8001: /* RDP_INPUT_MOUSE */
case RDP_INPUT_MOUSE:
rv = xrdp_wm_process_input_mouse(wm, param3, param1, param2);
break;
case 0x8002: /* RDP_INPUT_MOUSEX (INPUT_EVENT_MOUSEX) */
case RDP_INPUT_MOUSEX:
rv = xrdp_wm_process_input_mousex(wm, param3, param1, param2);
break;
case 0x4444: /* invalidate, this is not from RDP_DATA_PDU_INPUT */

405
xrdpapi/xrdp-ssh-agent.c Normal file
View File

@ -0,0 +1,405 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2012-2013
* Copyright (C) Laxmikant Rashinkar 2012-2013
* Copyright (C) Ben Cohen 2017
*
* 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.
*/
/*
* Portions are from OpenSSH, under the following license:
*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* The authentication agent program.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* xrdp-ssh-agent.c: program to forward ssh-agent protocol from xrdp session
*
* This performs the equivalent function of ssh-agent on a server you connect
* to via ssh, but the ssh-agent protocol is over an RDP dynamic virtual
* channel and not an SSH channel.
*
* This will print out variables to set in your environment (specifically,
* $SSH_AUTH_SOCK) for ssh clients to find the agent's socket, then it will
* run in the background. This is suitable to run just as you would run the
* normal ssh-agent, e.g. in your Xsession or /etc/xrdp/startwm.sh.
*
* Your RDP client needs to be running a compatible client-side plugin
* that can see a local ssh-agent.
*
* usage (from within an xrdp session):
* xrdp-ssh-agent
*
* build instructions:
* gcc xrdp-ssh-agent.c -o xrdp-ssh-agent -L./.libs -lxrdpapi -Wall
*
* protocol specification:
* Forward data verbatim over RDP dynamic virtual channel named "sshagent"
* between a ssh client on the xrdp server and the real ssh-agent where
* the RDP client is running. Each connection by a separate client to
* xrdp-ssh-agent gets a separate DVC invocation.
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#ifdef __WIN32__
#include <mstsapi.h>
#endif
#include "xrdpapi.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#define _PATH_DEVNULL "/dev/null"
char socket_name[PATH_MAX];
char socket_dir[PATH_MAX];
static int sa_uds_fd = -1;
static int is_going = 1;
/* Make a template filename for mk[sd]temp() */
/* This is from mktemp_proto() in misc.c from openssh */
void
mktemp_proto(char *s, size_t len)
{
const char *tmpdir;
int r;
if ((tmpdir = getenv("TMPDIR")) != NULL)
{
r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
if (r > 0 && (size_t)r < len)
{
return;
}
}
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
if (r < 0 || (size_t)r >= len)
{
fprintf(stderr, "%s: template string too short", __func__);
exit(1);
}
}
/* This uses parts of main() in ssh-agent.c from openssh */
static void
setup_ssh_agent(struct sockaddr_un *addr)
{
int rc;
/* Create private directory for agent socket */
mktemp_proto(socket_dir, sizeof(socket_dir));
if (mkdtemp(socket_dir) == NULL)
{
perror("mkdtemp: private socket dir");
exit(1);
}
snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
(long)getpid());
/* Create unix domain socket */
unlink(socket_name);
sa_uds_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sa_uds_fd == -1)
{
fprintf(stderr, "sshagent: socket creation failed");
exit(2);
}
memset(addr, 0, sizeof(struct sockaddr_un));
addr->sun_family = AF_UNIX;
strncpy(addr->sun_path, socket_name, sizeof(addr->sun_path));
addr->sun_path[sizeof(addr->sun_path) - 1] = 0;
/* Create with privileges rw------- so other users can't access the UDS */
mode_t umask_sav = umask(0177);
rc = bind(sa_uds_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un));
if (rc != 0)
{
fprintf(stderr, "sshagent: bind failed");
close(sa_uds_fd);
unlink(socket_name);
exit(3);
}
umask(umask_sav);
rc = listen(sa_uds_fd, /* backlog = */ 5);
if (rc != 0)
{
fprintf(stderr, "listen failed\n");
close(sa_uds_fd);
unlink(socket_name);
exit(1);
}
/* Now fork: the child becomes the ssh-agent daemon and the parent prints
* out the pid and socket name. */
pid_t pid = fork();
if (pid == -1)
{
perror("fork");
exit(1);
}
else if (pid != 0)
{
/* Parent */
close(sa_uds_fd);
printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", socket_name);
printf("SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n", pid);
printf("echo Agent pid %d;\n", pid);
exit(0);
}
/* Child */
if (setsid() == -1)
{
fprintf(stderr, "setsid failed");
exit(1);
}
(void)chdir("/");
int devnullfd;
if ((devnullfd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
{
/* XXX might close listen socket */
(void)dup2(devnullfd, STDIN_FILENO);
(void)dup2(devnullfd, STDOUT_FILENO);
(void)dup2(devnullfd, STDERR_FILENO);
if (devnullfd > 2)
{
close(devnullfd);
}
}
/* deny core dumps, since memory contains unencrypted private keys */
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
{
fprintf(stderr, "setrlimit RLIMIT_CORE: %s", strerror(errno));
exit(1);
}
}
static void
handle_connection(int client_fd)
{
int rdp_fd = -1;
int rc;
void *channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION,
"SSHAGENT",
WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED);
if (channel == NULL)
{
fprintf(stderr, "WTSVirtualChannelOpenEx() failed\n");
}
unsigned int retlen;
int *retdata;
rc = WTSVirtualChannelQuery(channel,
WTSVirtualFileHandle,
(void **)&retdata,
&retlen);
if (!rc)
{
fprintf(stderr, "WTSVirtualChannelQuery() failed\n");
}
if (retlen != sizeof(rdp_fd))
{
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n",
retlen);
}
rdp_fd = *retdata;
int client_going = 1;
while (client_going)
{
/* Wait for data from RDP or the client */
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(client_fd, &readfds);
FD_SET(rdp_fd, &readfds);
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (FD_ISSET(rdp_fd, &readfds))
{
/* Read from RDP and write to the client */
char buffer[4096];
unsigned int bytes_to_write;
rc = WTSVirtualChannelRead(channel,
/* TimeOut = */ 5000,
buffer,
sizeof(buffer),
&bytes_to_write);
if (rc == 1)
{
char *pos = buffer;
errno = 0;
while (bytes_to_write > 0)
{
int bytes_written = send(client_fd, pos, bytes_to_write, 0);
if (bytes_written > 0)
{
bytes_to_write -= bytes_written;
pos += bytes_written;
}
else if (bytes_written == 0)
{
fprintf(stderr, "send() returned 0!\n");
}
else if (errno != EINTR)
{
/* Error */
fprintf(stderr, "Error %d on recv\n", errno);
client_going = 0;
}
}
}
else
{
/* Error */
fprintf(stderr, "WTSVirtualChannelRead() failed: %d\n", errno);
client_going = 0;
}
}
if (FD_ISSET(client_fd, &readfds))
{
/* Read from the client and write to RDP */
char buffer[4096];
ssize_t bytes_to_write = recv(client_fd, buffer, sizeof(buffer), 0);
if (bytes_to_write > 0)
{
char *pos = buffer;
while (bytes_to_write > 0)
{
unsigned int bytes_written;
int rc = WTSVirtualChannelWrite(channel,
pos,
bytes_to_write,
&bytes_written);
if (rc == 0)
{
fprintf(stderr, "WTSVirtualChannelWrite() failed: %d\n",
errno);
client_going = 0;
}
else
{
bytes_to_write -= bytes_written;
pos += bytes_written;
}
}
}
else if (bytes_to_write == 0)
{
/* Client has closed connection */
client_going = 0;
}
else
{
/* Error */
fprintf(stderr, "Error %d on recv\n", errno);
client_going = 0;
}
}
}
WTSVirtualChannelClose(channel);
}
int
main(int argc, char **argv)
{
/* Setup the Unix domain socket and daemon process */
struct sockaddr_un addr;
setup_ssh_agent(&addr);
/* Wait for a client to connect to the socket */
while (is_going)
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sa_uds_fd, &readfds);
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
/* If something connected then get it...
* (You can test this using "socat - UNIX-CONNECT:<udspath>".) */
if (FD_ISSET(sa_uds_fd, &readfds))
{
socklen_t addrsize = sizeof(addr);
int client_fd = accept(sa_uds_fd,
(struct sockaddr*)&addr,
&addrsize);
handle_connection(client_fd);
close(client_fd);
}
}
close(sa_uds_fd);
unlink(socket_name);
return 0;
}