Merge branch 'devel' into v0.9
This commit is contained in:
commit
5c622f51a4
14
.travis.yml
14
.travis.yml
@ -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
35
NEWS.md
@ -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
|
||||
|
@ -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
|
||||
|
||||
```
|
||||
|
@ -33,7 +33,6 @@ libcommon_la_SOURCES = \
|
||||
arch.h \
|
||||
base64.h \
|
||||
base64.c \
|
||||
crc16.h \
|
||||
defines.h \
|
||||
fifo.c \
|
||||
fifo.h \
|
||||
|
12
common/log.c
12
common/log.c
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
14
configure.ac
14
configure.ac
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
117
sesman/chansrv/pulse/README.md
Normal file
117
sesman/chansrv/pulse/README.md
Normal 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.
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include "xrdp.h"
|
||||
#include "log.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#define LLOG_LEVEL 1
|
||||
#define LLOGLN(_level, _args) \
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "xrdp.h"
|
||||
#include "log.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#define LLOG_LEVEL 1
|
||||
#define LLOGLN(_level, _args) \
|
||||
|
@ -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
|
||||
|
@ -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: "
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
405
xrdpapi/xrdp-ssh-agent.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user