diff --git a/.travis.yml b/.travis.yml index 255612bf..45332ed5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ addons: # This is required to use a version of cppcheck other than that # suplied with the operating system cppcheck_defs: &cppcheck_defs - - CPPCHECK_VER=1.90 + - CPPCHECK_VER=2.1 - CPPCHECK_REPO=https://github.com/danmar/cppcheck.git min_amd64_deps: &min_amd64_deps @@ -53,6 +53,17 @@ max_amd64_conf: &max_amd64_conf packages: - *max_amd64_deps +max_debug_amd64_conf: &max_debug_amd64_conf + env: + - CONF_FLAGS="--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame + --enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter + --enable-pixman --enable-xrdpdebug" + - DISTCHECK=1 + addons: + apt: + packages: + - *max_amd64_deps + max_x86_deps: &max_x86_deps - *common_deps - g++-multilib @@ -92,10 +103,11 @@ cppcheck_conf: &cppcheck_conf env: - *cppcheck_defs -# addons: -# apt: -# packages: -# - cppcheck + addons: + apt: + packages: + - libz3-dev + - z3 script: - ./bootstrap @@ -122,6 +134,10 @@ matrix: - compiler: clang << : *max_amd64_conf + # Maximal debug amd64 build + - compiler: gcc + << : *max_debug_amd64_conf + # Maximal x86 build - compiler: gcc << : *max_x86_conf @@ -138,5 +154,5 @@ matrix: script: - ./bootstrap - ./configure $CONF_FLAGS - - make CFLAGS="$CFLAGS -O2 -Wall -Wwrite-strings -Werror" + - make CFLAGS="$CFLAGS" - test -z "$DISTCHECK" || make distcheck diff --git a/NEWS.md b/NEWS.md index 3f137919..e57c13fd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,34 @@ +# Release notes for xrdp v0.9.14 (2020/08/31) + +## New features +* VNC multi-monitor support if you are using a suitable Xvnc server #1343 +* VNC sessions now resize by default on reconnection if you are using a suitable Xvnc server #1343 +* Support Slackware for PAM #1558 #1560 +* Support Programmer Dvorak Keyboard #1663 + +**[HEADS UP]** The VNC changes are significant. They described in more detail on the following wiki page. +* [Xvnc backend : Multi monitor and resize support](https://github.com/neutrinolabs/xrdp/wiki/Xvnc-backend-:-Multi-monitor-and-resize-support) + +## Bug fixes +* Fix odd shift key behavior (workaround) #397 #1522 +* Fix Xorg path in the document for Arch Linux #1448 #1529 +* Fix Xorg path in the document for CentOS 8 #1646 #1647 +* Fix internal username/password buffer is smaller than RDP protocol specification #1648 #1653 +* Fix possible memory out-of-bounds accesses #1549 +* Fix memory allocation overflow #1557 +* Prevent chansrv input channels being scanned during a server reset #1595 +* Ignore TS_MULTIFRAGMENTUPDATE_CAPABILITYSET from client if fp disabled #1593 +* Minor manpage fixes #1611 + +## Other changes +* CI error fixes +* Introduce cppcheck + +## Known issues +* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to + xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266 +* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965 + # Release notes for xrdp v0.9.13.1 (2020/06/30) This is a security fix release that includes fixes for the following local buffer overflow vulnerability. diff --git a/README.md b/README.md index 183f6d82..21f755b5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp-questions) ![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg) -*Current Version:* 0.9.13.1 +*Current Version:* 0.9.14 # xrdp - an open source RDP server diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..ae407850 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + + +## Reporting a Vulnerability + +Please DO NOT report any security issues to public GitHub issue. + +If you find a security vulnerability please kindly inform us about the problem immediately +so that we can fix the security problem to protect a lot of users around the world as soon +as possible. + +Our email eddress for security report is: + +* [xrdp-core@googlegroups.com](mailto:xrdp-core@googlegroups.com) diff --git a/common/log.c b/common/log.c index 50a44e9e..4a0bd2f3 100644 --- a/common/log.c +++ b/common/log.c @@ -569,6 +569,7 @@ log_message(const enum logLevels lvl, const char *msg, ...) if (len > LOG_BUFFER_SIZE) { log_message(LOG_LEVEL_WARNING, "next message will be truncated"); + len = LOG_BUFFER_SIZE; } /* forcing the end of message string */ diff --git a/common/log.h b/common/log.h index 2f8063e1..7545b1f0 100644 --- a/common/log.h +++ b/common/log.h @@ -114,7 +114,7 @@ internal_log_lvl2str(const enum logLevels lvl, char *str); * */ enum logLevels -internal_log_text2level(const char *s); +internal_log_text2level(const char *buf); /** * A function that init our struct that holds all state and diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index ad81d0df..03e03c39 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -74,8 +74,11 @@ #define CONNECTION_TYPE_LAN 0x06 #define CONNECTION_TYPE_AUTODETECT 0x07 -/* Virtual channel options */ -/* Channel Definition Structure: options (2.2.1.3.4.1) */ +/* Channel definition structure CHANNEL_DEF (2.2.1.3.4.1) */ +/* This isn't explicitly named in MS-RDPBCGR */ +#define CHANNEL_NAME_LEN 7 + +/* Oprions field */ /* NOTE: XR_ prefixed to avoid conflict with FreeRDP */ #define XR_CHANNEL_OPTION_INITIALIZED 0x80000000 #define XR_CHANNEL_OPTION_ENCRYPT_RDP 0x40000000 diff --git a/common/os_calls.c b/common/os_calls.c index 88b96e61..463af84c 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -2896,6 +2896,12 @@ g_strtrim(char *str, int trim_flags) text = (wchar_t *)malloc(len * sizeof(wchar_t) + 8); text1 = (wchar_t *)malloc(len * sizeof(wchar_t) + 8); + if (text == NULL || text1 == NULL) + { + free(text); + free(text1); + return 1; + } text1_index = 0; mbstowcs(text, str, len + 1); diff --git a/common/pixman-region.c b/common/pixman-region.c index eb3fd179..ccdea9ad 100644 --- a/common/pixman-region.c +++ b/common/pixman-region.c @@ -83,8 +83,16 @@ #define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2) #define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2) +/* This file is included by pixman-region16.c which defines PREFIX(x). + * This check allows cppcheck 2.x to scan this file separately */ +#ifndef PREFIX +#define PREFIX(x) pixman_region##x +#endif + #ifdef XRDP_DEBUG +pixman_bool_t PREFIX(_selfcheck) (region_type_t *reg); + #define GOOD(reg) \ do \ { \ diff --git a/common/trans.c b/common/trans.c index 883d7cbd..27efa8f8 100644 --- a/common/trans.c +++ b/common/trans.c @@ -452,17 +452,14 @@ trans_force_read_s(struct trans *self, struct stream *in_s, int size) { int rcvd; - if (self->status != TRANS_STATUS_UP) + if (self->status != TRANS_STATUS_UP || + size < 0 || !s_check_rem_out(in_s, size)) { return 1; } + while (size > 0) { - /* make sure stream has room */ - if ((in_s->end + size) > (in_s->data + in_s->size)) - { - return 1; - } rcvd = self->trans_recv(self, in_s->end, size); if (rcvd == -1) { diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 297cdc55..fa7df6bf 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -18,6 +18,8 @@ * xrdp / xserver info / caps */ +#include "xrdp_constants.h" + #if !defined(XRDP_CLIENT_INFO_H) #define XRDP_CLIENT_INFO_H @@ -57,11 +59,11 @@ struct xrdp_client_info char hostname[32]; int build; int keylayout; - char username[256]; - char password[256]; - char domain[256]; - char program[256]; - char directory[256]; + char username[INFO_CLIENT_MAX_CB_LEN]; + char password[INFO_CLIENT_MAX_CB_LEN]; + char domain[INFO_CLIENT_MAX_CB_LEN]; + char program[INFO_CLIENT_MAX_CB_LEN]; + char directory[INFO_CLIENT_MAX_CB_LEN]; int rdp_compression; int rdp_autologin; int crypt_level; /* 1, 2, 3 = low, medium, high */ diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 93ca2086..7b777e3d 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -38,6 +38,11 @@ ******************************************************************************/ #define INFO_CLIENT_NAME_BYTES 32 +/** + * Maximum length of a string including the mandatory null terminator + * [MS-RDPBCGR] TS_INFO_PACKET(2.2.1.11.1.1) + */ +#define INFO_CLIENT_MAX_CB_LEN 512 #define XRDP_MAX_BITMAP_CACHE_ID 3 #define XRDP_MAX_BITMAP_CACHE_IDX 2000 diff --git a/configure.ac b/configure.ac index cd47b405..8a2d2301 100644 --- a/configure.ac +++ b/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.13.1], [xrdp-devel@googlegroups.com]) +AC_INIT([xrdp], [0.9.14], [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]) @@ -19,11 +19,6 @@ AC_CONFIG_SUBDIRS([libpainter librfxcodec]) # Use silent rules by default if supported by Automake m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -AX_CFLAGS_WARN_ALL -AX_APPEND_COMPILE_FLAGS([-Wwrite-strings]) -AX_GCC_FUNC_ATTRIBUTE([format]) -AX_TYPE_SOCKLEN_T - case $host_os in *linux*) linux=yes @@ -155,6 +150,19 @@ AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin], [], [enable_rdpsndaudin=no]) AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes]) +# configure compiler options and CFLAGS +AX_GCC_FUNC_ATTRIBUTE([format]) +AX_TYPE_SOCKLEN_T +AX_CFLAGS_WARN_ALL +AX_APPEND_COMPILE_FLAGS([-Wwrite-strings]) + +AM_COND_IF([LINUX], + [AX_APPEND_COMPILE_FLAGS([-Werror])]) # bsd has warnings that have not been fixed yet + +AM_COND_IF([XRDP_DEBUG], + [AX_APPEND_COMPILE_FLAGS([-g -O0])], + [AX_APPEND_COMPILE_FLAGS([-O2])]) + # Don't fail without working nasm if rfxcodec is not enabled if test "x$enable_rfxcodec" != xyes; then with_simd=no @@ -243,11 +251,6 @@ then [AC_MSG_ERROR([please install libjpeg-dev or libjpeg-devel])]) fi -if test "x$enable_xrdpdebug" = "xyes" -then - CFLAGS="-g -O0" -fi - # checking for fuse if test "x$enable_fuse" = "xyes" then diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in index 8fca3a9e..6506a7ad 100644 --- a/docs/man/sesman.ini.5.in +++ b/docs/man/sesman.ini.5.in @@ -133,27 +133,30 @@ Sets the maximum number of simultaneous sessions. If not set or set to \fBKillDisconnected\fR=\fI[true|false]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR, every session will be killed within 60 seconds after the user disconnects. +This setting currently only works with xorgxrdp sessions. .TP \fBDisconnectedTimeLimit\fR=\fInumber\fR -Sets the time limit (in seconds) before a disconnected session is killed. -If set to \fI0\fR, automatic killing is disabled. +Sets the time limit for \fBKillDisconnected\fR to a value greater than 60. +Values less than 60 cannot be set. You do not actually have to specify +\fBKillDisconnected\fR if you set this value. +This setting currently only works with xorgxrdp sessions. .TP \fBIdleTimeLimit\fR=\fInumber\fR Sets the time limit (in seconds) before an idle session is disconnected. Idle means no keyboard inputs and no mouse moves/clicks here. If set to \fI0\fR, idle sessions will never be disconnected by timeout. -This works only with xorgxrdp session. Moreover, xorgxrdp must be v0.2.9 or later. +This works only with xorgxrdp sessions. Moreover, xorgxrdp must be v0.2.9 or later. .TP \fBPolicy\fR=\fI[Default|UBD|UBI|UBC|UBDI|UBDC]\fR -Session allocation policy. By default, a new session is created -for the combination when using Xrdp, and -for the combination when using Xvnc. -This behavior can be changed by setting session policy to: +Session allocation policy. Used to decide when to allocate a +new session. Set to one of the following values: .br +.br +\fBDefault\fR - session per .br \fBUBD\fR - session per .br @@ -168,7 +171,8 @@ This behavior can be changed by setting session policy to: .br Note that the \fBUser\fR and \fBBitPerPixel\fR criteria cannot be turned -off. For Xvnc connections, \fBDisplaySize\fR is always enabled as well. +off. \fBDisplaySize\fR refers to the initial geometry of a connection, +as actual display sizes can change dynamically. .br .SH "SECURITY" diff --git a/docs/man/xrdp-dis.1.in b/docs/man/xrdp-dis.1.in index 2015389f..a35e441e 100644 --- a/docs/man/xrdp-dis.1.in +++ b/docs/man/xrdp-dis.1.in @@ -17,11 +17,11 @@ to get the default host and display number. .SH FILES .TP .I @socketdir@/xrdp_disconnect_display_* -UNIX socket used to communicate with the \fBxrdp\fP(8) session manager. +UNIX socket used to communicate the disconnect request to xorgxrdp. .SH KNOWN ISSUES .TP -This utility doesn't support disconnecting xorgxrdp sessions so far. +This utility doesn't support disconnecting Xvnc sessions so far. .SH SEE ALSO .BR xrdp (8). diff --git a/docs/man/xrdp.ini.5.in b/docs/man/xrdp.ini.5.in index 834f258b..d7bce514 100644 --- a/docs/man/xrdp.ini.5.in +++ b/docs/man/xrdp.ini.5.in @@ -302,6 +302,14 @@ Specifies color depth of the backend X server. The default is the color depth of the client. Only Xvnc and X11rdp use that setting. Xorg runs at \fI24\fR bpp. +.TP +\fBdisabled_encodings_mask\fR=\fI\fR +Set this bitmask to a non-zero value to prevent \fBxrdp\fR(8) requesting +some features from the Xvnc server. You should only need to set this +to a non-zero value to work around bugs in your Xvnc server. The bit +values supported for a particular release of \fBxrdp\fR(8) are documented in +\fBxrdp.ini\fR. + .TP \fBcode\fR=\fI\fR|\fI0\fR Specifies the session type. The default, \fI0\fR, is Xvnc, \fI10\fR is diff --git a/faq-compile.txt b/faq-compile.txt index 09f57d84..7307e07a 100644 --- a/faq-compile.txt +++ b/faq-compile.txt @@ -32,3 +32,25 @@ Q. I get an error: "rail.c:31:35: fatal error: X11/extensions/Xrandr.h: No such A. You need to install the Xrandr development package. For Debian / Ubuntu this package is called libxrandr-dev. For SUSE / openSUSE this package is called libXrandr-devel. + +Q. How do I configure the same continuous integration bulids for my XRDP fork as the official XRDP repository? + +A. The XRDP project uses both Travis-CI.org and Cirrus-CI.com for continuous integration. + Both of these services are free for open source projects (both the official + repository and forks), and these services integrate with Github to build any + changes pushed to public Github repositories. + + To configure Travis CI for your XRDP fork on github: + 1. Follow Travis CI instructions for connecting your github account to Travis CI + https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github + 2. In the Travis CI dashboard setting page select your XRDP fork repository for building pushed branches. + 3. Push a commit to a branch in your XRDP fork on github and Travis CI should + start building the branch because the XRDP repository already contain a .travis.yml file. + + To configure Cirrus CI for your XRDP fork on github: + 1. Follow Cirrus CI instructions for connecting your github account to Cirrus CI + https://cirrus-ci.org/guide/quick-start/ + 2. In the Github setting page for the Cirrus CI application, enable Cirrus CI + access to your XRDP fork repository. + 3. Push a commit to a branch in your XRDP fork on github and Cirrus CI should + start building the branch because the XRDP repository already contain a .cirrus.yml file. diff --git a/genkeymap/dump-keymaps.sh b/genkeymap/dump-keymaps.sh index 7b61f240..b95305c7 100755 --- a/genkeymap/dump-keymaps.sh +++ b/genkeymap/dump-keymaps.sh @@ -15,6 +15,12 @@ setxkbmap -model pc104 -layout us setxkbmap -model pc104 -layout dvorak ./xrdp-genkeymap ../instfiles/km-00010409.ini +# English - US 'dvp' 0x19360409 +OLD_SETTINGS=$(setxkbmap -query -verbose 4 | sed "s/^\([a-z]\+\):\s*\(.*\)$/-\1 \2/;s/^-options/-option \"\" -option/;s/,/ -option /g" | xargs -d \\n) +setxkbmap -rules xfree86 -model pc105 -layout us -variant dvp -option "" -option compose:102 -option caps:shift -option numpad:sg -option numpad:shift3 -option keypad:hex -option keypad:atm -option kpdl:semi -option lv3:ralt_alt +./xrdp-genkeymap ../instfiles/km-19360409.ini +setxkbmap ${OLD_SETTINGS} + # English - UK 'en-GB' 0x00000809 setxkbmap -model pc105 -layout gb ./xrdp-genkeymap ../instfiles/km-00000809.ini diff --git a/genkeymap/genkeymap.c b/genkeymap/genkeymap.c index 03e54d8c..3b654454 100644 --- a/genkeymap/genkeymap.c +++ b/genkeymap/genkeymap.c @@ -136,7 +136,7 @@ int main(int argc, char **argv) fprintf(outf, "[%s]\n", sections[idx]); e.state = states[idx]; - for (i = 8; i <= 137; i++) /* Keycodes */ + for (i = 8; i < 137; i++) /* Keycodes */ { if (is_evdev) e.keycode = xfree86_to_evdev[i-8]; diff --git a/instfiles/Makefile.am b/instfiles/Makefile.am index 08730c03..a318ed8f 100644 --- a/instfiles/Makefile.am +++ b/instfiles/Makefile.am @@ -50,7 +50,8 @@ dist_startscript_DATA = \ km-00000813.ini \ km-00000816.ini \ km-0000100c.ini \ - km-00010409.ini + km-00010409.ini \ + km-19360409.ini # # platform specific files diff --git a/instfiles/km-19360409.ini b/instfiles/km-19360409.ini new file mode 100644 index 00000000..a8a1949c --- /dev/null +++ b/instfiles/km-19360409.ini @@ -0,0 +1,1047 @@ +[noshift] +Key8=65406:0 +Key9=65307:27 +Key10=38:38 +Key11=91:91 +Key12=123:123 +Key13=125:125 +Key14=40:40 +Key15=61:61 +Key16=42:42 +Key17=41:41 +Key18=43:43 +Key19=93:93 +Key20=33:33 +Key21=35:35 +Key22=65288:8 +Key23=65289:9 +Key24=59:59 +Key25=44:44 +Key26=46:46 +Key27=112:112 +Key28=121:121 +Key29=102:102 +Key30=103:103 +Key31=99:99 +Key32=114:114 +Key33=108:108 +Key34=47:47 +Key35=64:64 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=111:111 +Key40=101:101 +Key41=117:117 +Key42=105:105 +Key43=100:100 +Key44=104:104 +Key45=116:116 +Key46=110:110 +Key47=115:115 +Key48=45:45 +Key49=36:36 +Key50=65505:0 +Key51=92:92 +Key52=39:39 +Key53=113:113 +Key54=106:106 +Key55=107:107 +Key56=120:120 +Key57=98:98 +Key58=109:109 +Key59=119:119 +Key60=118:118 +Key61=122:122 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65514:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[shift] +Key8=65406:0 +Key9=65307:27 +Key10=37:37 +Key11=55:55 +Key12=53:53 +Key13=51:51 +Key14=49:49 +Key15=57:57 +Key16=48:48 +Key17=50:50 +Key18=52:52 +Key19=54:54 +Key20=56:56 +Key21=96:96 +Key22=65288:8 +Key23=65056:0 +Key24=58:58 +Key25=60:60 +Key26=62:62 +Key27=80:80 +Key28=89:89 +Key29=70:70 +Key30=71:71 +Key31=67:67 +Key32=82:82 +Key33=76:76 +Key34=63:63 +Key35=94:94 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=79:79 +Key40=69:69 +Key41=85:85 +Key42=73:73 +Key43=68:68 +Key44=72:72 +Key45=84:84 +Key46=78:78 +Key47=83:83 +Key48=95:95 +Key49=126:126 +Key50=65505:0 +Key51=124:124 +Key52=34:34 +Key53=81:81 +Key54=74:74 +Key55=75:75 +Key56=88:88 +Key57=66:66 +Key58=77:77 +Key59=87:87 +Key60=86:86 +Key61=90:90 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65512:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=61:61 +Key127=65515:0 +Key128=65517:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[altgr] +Key8=65406:0 +Key9=65307:27 +Key10=38:38 +Key11=164:164 +Key12=162:162 +Key13=165:165 +Key14=8364:8364 +Key15=163:163 +Key16=0:0 +Key17=189:189 +Key18=65104:96 +Key19=0:0 +Key20=161:161 +Key21=65104:96 +Key22=65288:8 +Key23=65289:9 +Key24=65111:168 +Key25=171:171 +Key26=187:187 +Key27=182:182 +Key28=252:252 +Key29=102:102 +Key30=103:103 +Key31=231:231 +Key32=174:174 +Key33=108:108 +Key34=191:191 +Key35=65106:94 +Key36=65293:13 +Key37=65507:0 +Key38=229:229 +Key39=248:248 +Key40=230:230 +Key41=233:233 +Key42=105:105 +Key43=240:240 +Key44=65105:180 +Key45=254:254 +Key46=241:241 +Key47=223:223 +Key48=173:173 +Key49=65107:126 +Key50=65505:0 +Key51=92:92 +Key52=65105:180 +Key53=113:113 +Key54=106:106 +Key55=107:107 +Key56=120:120 +Key57=98:98 +Key58=109:109 +Key59=119:119 +Key60=118:118 +Key61=122:122 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65514:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[shiftaltgr] +Key8=65406:0 +Key9=65307:27 +Key10=37:37 +Key11=0:0 +Key12=0:0 +Key13=0:0 +Key14=0:0 +Key15=65106:94 +Key16=0:0 +Key17=0:0 +Key18=0:0 +Key19=0:0 +Key20=16789016:11800 +Key21=0:0 +Key22=65288:8 +Key23=65056:0 +Key24=65111:168 +Key25=16785436:8220 +Key26=16785437:8221 +Key27=167:167 +Key28=220:220 +Key29=70:70 +Key30=71:71 +Key31=199:199 +Key32=2761:8482 +Key33=76:76 +Key34=16785469:8253 +Key35=65114:711 +Key36=65293:13 +Key37=65507:0 +Key38=197:197 +Key39=216:216 +Key40=198:198 +Key41=201:201 +Key42=73:73 +Key43=208:208 +Key44=0:0 +Key45=222:222 +Key46=209:209 +Key47=0:0 +Key48=2730:8211 +Key49=65107:126 +Key50=65505:0 +Key51=124:124 +Key52=65113:733 +Key53=81:81 +Key54=74:74 +Key55=75:75 +Key56=88:88 +Key57=66:66 +Key58=77:77 +Key59=87:87 +Key60=86:86 +Key61=90:90 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65512:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=61:61 +Key127=65515:0 +Key128=65517:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[capslock] +Key8=65406:0 +Key9=65307:27 +Key10=38:38 +Key11=55:55 +Key12=53:53 +Key13=51:51 +Key14=49:49 +Key15=57:57 +Key16=48:48 +Key17=50:50 +Key18=52:52 +Key19=54:54 +Key20=56:56 +Key21=35:35 +Key22=65288:8 +Key23=65289:9 +Key24=59:59 +Key25=44:44 +Key26=46:46 +Key27=80:80 +Key28=89:89 +Key29=70:70 +Key30=71:71 +Key31=67:67 +Key32=82:82 +Key33=76:76 +Key34=47:47 +Key35=64:64 +Key36=65293:13 +Key37=65507:0 +Key38=65:65 +Key39=79:79 +Key40=69:69 +Key41=85:85 +Key42=73:73 +Key43=68:68 +Key44=72:72 +Key45=84:84 +Key46=78:78 +Key47=83:83 +Key48=95:95 +Key49=36:36 +Key50=65505:0 +Key51=92:92 +Key52=39:39 +Key53=81:81 +Key54=74:74 +Key55=75:75 +Key56=88:88 +Key57=66:66 +Key58=77:77 +Key59=87:87 +Key60=86:86 +Key61=90:90 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65514:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[capslockaltgr] +Key8=65406:0 +Key9=65307:27 +Key10=38:38 +Key11=0:0 +Key12=0:0 +Key13=0:0 +Key14=0:0 +Key15=65106:94 +Key16=0:0 +Key17=0:0 +Key18=0:0 +Key19=0:0 +Key20=16789016:11800 +Key21=65104:96 +Key22=65288:8 +Key23=65289:9 +Key24=65111:168 +Key25=171:171 +Key26=187:187 +Key27=182:182 +Key28=220:220 +Key29=70:70 +Key30=71:71 +Key31=199:199 +Key32=174:174 +Key33=76:76 +Key34=191:191 +Key35=65106:94 +Key36=65293:13 +Key37=65507:0 +Key38=197:197 +Key39=216:216 +Key40=198:198 +Key41=201:201 +Key42=73:73 +Key43=208:208 +Key44=65105:180 +Key45=222:222 +Key46=209:209 +Key47=223:223 +Key48=2730:8211 +Key49=65107:126 +Key50=65505:0 +Key51=92:92 +Key52=65105:180 +Key53=81:81 +Key54=74:74 +Key55=75:75 +Key56=88:88 +Key57=66:66 +Key58=77:77 +Key59=87:87 +Key60=86:86 +Key61=90:90 +Key62=65506:0 +Key63=65450:42 +Key64=65513:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65514:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=0:0 +Key126=65469:61 +Key127=0:0 +Key128=0:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[shiftcapslock] +Key8=65406:0 +Key9=65307:27 +Key10=37:37 +Key11=91:91 +Key12=123:123 +Key13=125:125 +Key14=40:40 +Key15=61:61 +Key16=42:42 +Key17=41:41 +Key18=43:43 +Key19=93:93 +Key20=33:33 +Key21=96:96 +Key22=65288:8 +Key23=65056:0 +Key24=58:58 +Key25=60:60 +Key26=62:62 +Key27=112:112 +Key28=121:121 +Key29=102:102 +Key30=103:103 +Key31=99:99 +Key32=114:114 +Key33=108:108 +Key34=63:63 +Key35=94:94 +Key36=65293:13 +Key37=65507:0 +Key38=97:97 +Key39=111:111 +Key40=101:101 +Key41=117:117 +Key42=105:105 +Key43=100:100 +Key44=104:104 +Key45=116:116 +Key46=110:110 +Key47=115:115 +Key48=45:45 +Key49=126:126 +Key50=65505:0 +Key51=124:124 +Key52=34:34 +Key53=113:113 +Key54=106:106 +Key55=107:107 +Key56=120:120 +Key57=98:98 +Key58=109:109 +Key59=119:119 +Key60=118:118 +Key61=122:122 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65512:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=61:61 +Key127=65515:0 +Key128=65517:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 + +[shiftcapslockaltgr] +Key8=65406:0 +Key9=65307:27 +Key10=37:37 +Key11=164:164 +Key12=162:162 +Key13=165:165 +Key14=8364:8364 +Key15=163:163 +Key16=0:0 +Key17=189:189 +Key18=65104:96 +Key19=0:0 +Key20=161:161 +Key21=0:0 +Key22=65288:8 +Key23=65056:0 +Key24=65111:168 +Key25=16785436:8220 +Key26=16785437:8221 +Key27=167:167 +Key28=252:252 +Key29=102:102 +Key30=103:103 +Key31=231:231 +Key32=2761:8482 +Key33=108:108 +Key34=16785469:8253 +Key35=65114:711 +Key36=65293:13 +Key37=65507:0 +Key38=229:229 +Key39=248:248 +Key40=230:230 +Key41=233:233 +Key42=105:105 +Key43=240:240 +Key44=0:0 +Key45=254:254 +Key46=241:241 +Key47=0:0 +Key48=173:173 +Key49=65107:126 +Key50=65505:0 +Key51=124:124 +Key52=65113:733 +Key53=113:113 +Key54=106:106 +Key55=107:107 +Key56=120:120 +Key57=98:98 +Key58=109:109 +Key59=119:119 +Key60=118:118 +Key61=122:122 +Key62=65506:0 +Key63=65450:42 +Key64=65511:0 +Key65=32:32 +Key66=65509:0 +Key67=65470:0 +Key68=65471:0 +Key69=65472:0 +Key70=65473:0 +Key71=65474:0 +Key72=65475:0 +Key73=65476:0 +Key74=65477:0 +Key75=65478:0 +Key76=65479:0 +Key77=65407:0 +Key78=65300:0 +Key79=65429:0 +Key80=65431:0 +Key81=65434:0 +Key82=65453:45 +Key83=65430:0 +Key84=65437:0 +Key85=65432:0 +Key86=65451:43 +Key87=65436:0 +Key88=65433:0 +Key89=65435:0 +Key90=65438:0 +Key91=65439:0 +Key92=0:0 +Key93=0:0 +Key94=65312:0 +Key95=65480:0 +Key96=65481:0 +Key97=65360:0 +Key98=65362:0 +Key99=65365:0 +Key100=65361:0 +Key101=0:0 +Key102=65363:0 +Key103=65367:0 +Key104=65364:0 +Key105=65366:0 +Key106=65379:0 +Key107=65535:127 +Key108=65421:13 +Key109=65508:0 +Key110=65299:0 +Key111=65377:0 +Key112=65455:47 +Key113=65512:0 +Key114=0:0 +Key115=65515:0 +Key116=65516:0 +Key117=65383:0 +Key118=0:0 +Key119=0:0 +Key120=0:0 +Key121=0:0 +Key122=0:0 +Key123=0:0 +Key124=65027:0 +Key125=65513:0 +Key126=61:61 +Key127=65515:0 +Key128=65517:0 +Key129=0:0 +Key130=0:0 +Key131=0:0 +Key132=0:0 +Key133=0:0 +Key134=65454:46 +Key135=0:0 +Key136=0:0 diff --git a/instfiles/pam.d/mkpamrules b/instfiles/pam.d/mkpamrules index d90ad54b..a75bfc32 100755 --- a/instfiles/pam.d/mkpamrules +++ b/instfiles/pam.d/mkpamrules @@ -10,51 +10,87 @@ service="xrdp-sesman" pamdir="/etc/pam.d" pamdir_suse="/usr/etc/pam.d" +# Modules needed by xrdp-sesman.unix, if we get to that +unix_modules_needed="pam_unix.so pam_env.so pam_nologin.so" + +# Directories where pam modules might be installed +# Add to this list as platforms are added +pam_module_dir_searchpath="/lib*/security /usr/lib*/security /lib/*/security /usr/lib/*/security" + +find_pam_module_dir() +{ + # Looks for the pam security module directory + set -- $pam_module_dir_searchpath + for d in "$@"; do + if [ -s $d/pam_unix.so ]; then + echo $d + break + fi + done +} + +can_apply_unix_config() +{ + result=0 + module_dir="$1" + for m in $unix_modules_needed; do + if [ ! -s $module_dir/$m ]; then + echo " ** $m not found" >&2 + result=1 + fi + done + + return $result +} + guess_rules () { - if test -s "$pamdir/password-auth"; then + rules= + if [ -s "$pamdir/password-auth" ]; then rules="redhat" - return - fi - if test -s "$pamdir_suse/common-account"; then + elif [ -s "$pamdir_suse/common-account" ]; then rules="suse" - return - fi - if test -s "$pamdir/common-account"; then + elif [ -s "$pamdir/common-account" ]; then if grep "^@include" "$pamdir/passwd" >/dev/null 2>&1; then rules="debian" else rules="suse" fi - return - fi - if test ! -f "$pamdir/system-auth" -a -s "$pamdir/system"; then + elif [ ! -f "$pamdir/system-auth" -a -s "$pamdir/system" ]; then rules="freebsd" - return - fi - if test -s "$pamdir/authorization"; then + elif [ -s "$pamdir/authorization" ]; then rules="macos" - return - fi - if test -s "$pamdir/system-remote-login"; then + elif [ -s "$pamdir/system-remote-login" ]; then rules="arch" - return - fi - rules="unix" - return + elif [ -s "$pamdir/system-auth" ]; then + rules="system" + + else + module_dir=`find_pam_module_dir` + if [ -d "$module_dir" ]; then + #echo "- Found pam modules in $module_dir" >&2 + if can_apply_unix_config "$module_dir" ; then + rules="unix" + fi + fi + fi } -if test "$rules" = "auto"; then +if [ "$rules" = "auto" ]; then guess_rules + if [ -z "$rules" ]; then + echo "** Can't guess PAM rules for this system" + exit 1 + fi fi -if test -s "$srcdir/$service.$rules"; then +if [ -s "$srcdir/$service.$rules" ]; then ln -nsf "$srcdir/$service.$rules" "$outfile" else echo "Cannot find $srcdir/$service.$rules" diff --git a/instfiles/pam.d/xrdp-sesman.system b/instfiles/pam.d/xrdp-sesman.system new file mode 100644 index 00000000..5025a0f9 --- /dev/null +++ b/instfiles/pam.d/xrdp-sesman.system @@ -0,0 +1,5 @@ +#%PAM-1.0 +auth include system-auth +account include system-auth +password include system-auth +session include system-auth diff --git a/instfiles/pam.d/xrdp-sesman.unix b/instfiles/pam.d/xrdp-sesman.unix index 5025a0f9..3bee185c 100644 --- a/instfiles/pam.d/xrdp-sesman.unix +++ b/instfiles/pam.d/xrdp-sesman.unix @@ -1,5 +1,16 @@ #%PAM-1.0 -auth include system-auth -account include system-auth -password include system-auth -session include system-auth +# +# Really basic authentication set when nothing else is available +# +# You may need to edit this to suit your system depending on the +# required functionality. +# +auth required pam_unix.so shadow +auth required pam_env.so + +password required pam_unix.so + +account required pam_unix.so +account required pam_nologin.so + +session required pam_unix.so diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 27e2c3b7..cdb463b7 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -47,6 +47,7 @@ libxrdp_init(tbus id, struct trans *trans) session->rdp = xrdp_rdp_create(session, trans); session->orders = xrdp_orders_create(session, (struct xrdp_rdp *)session->rdp); session->client_info = &(((struct xrdp_rdp *)session->rdp)->client_info); + session->check_for_app_input = 1; return session; } @@ -125,24 +126,18 @@ libxrdp_force_read(struct trans* trans) if (trans_force_read(trans, 4) != 0) { - g_writeln("libxrdp_force_read: error"); + g_writeln("libxrdp_force_read: header read error"); return 0; } bytes = libxrdp_get_pdu_bytes(s->data); - if (bytes < 1) + if (bytes < 4 || bytes > s->size) { - g_writeln("libxrdp_force_read: error"); + g_writeln("libxrdp_force_read: bad header length %d", bytes); return 0; } - if (bytes > 32 * 1024) - { - g_writeln("libxrdp_force_read: error"); - return 0; - } - if (trans_force_read(trans, bytes - 4) != 0) { - g_writeln("libxrdp_force_read: error"); + g_writeln("libxrdp_force_read: Can't read PDU"); return 0; } return s; @@ -1049,29 +1044,36 @@ libxrdp_orders_send_font(struct xrdp_session *session, } /*****************************************************************************/ +/* Note : if this is called on a multimon setup, the client is resized + * to a single monitor */ int EXPORT_CC libxrdp_reset(struct xrdp_session *session, int width, int height, int bpp) { if (session->client_info != 0) { + struct xrdp_client_info *client_info = session->client_info; + /* older client can't resize */ - if (session->client_info->build <= 419) + if (client_info->build <= 419) { return 0; } - /* if same, don't need to do anything */ - if (session->client_info->width == width && - session->client_info->height == height && - session->client_info->bpp == bpp) + /* if same (and only one monitor on client) don't need to do anything */ + if (client_info->width == width && + client_info->height == height && + client_info->bpp == bpp && + (client_info->monitorCount == 0 || client_info->multimon == 0)) { return 0; } - session->client_info->width = width; - session->client_info->height = height; - session->client_info->bpp = bpp; + client_info->width = width; + client_info->height = height; + client_info->bpp = bpp; + client_info->monitorCount = 0; + client_info->multimon = 0; } else { @@ -1084,7 +1086,12 @@ libxrdp_reset(struct xrdp_session *session, return 1; } - /* shut down the rdp client */ + /* shut down the rdp client + * + * When resetting the lib, disable application input checks, as + * otherwise we can send a channel message to the other end while + * the channels are inactive ([MS-RDPBCGR] 3.2.5.5.1 */ + session->check_for_app_input = 0; if (xrdp_rdp_send_deactivate((struct xrdp_rdp *)session->rdp) != 0) { return 1; @@ -1096,6 +1103,9 @@ libxrdp_reset(struct xrdp_session *session, return 1; } + /* Re-enable application input checks */ + session->check_for_app_input = 1; + return 0; } diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index c236bec9..e235e6e6 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -66,6 +66,7 @@ struct xrdp_session struct trans *trans; int (*callback)(intptr_t id, int msg, intptr_t param1, intptr_t param2, intptr_t param3, intptr_t param4); + int check_for_app_input; void *rdp; void *orders; struct xrdp_client_info *client_info; diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c index ead495ca..854d23b1 100644 --- a/libxrdp/xrdp_caps.c +++ b/libxrdp/xrdp_caps.c @@ -561,7 +561,10 @@ xrdp_caps_process_multifragmentupdate(struct xrdp_rdp *self, struct stream *s, int MaxRequestSize; in_uint32_le(s, MaxRequestSize); - self->client_info.max_fastpath_frag_bytes = MaxRequestSize; + if (self->client_info.use_fast_path & 1) + { + self->client_info.max_fastpath_frag_bytes = MaxRequestSize; + } return 0; } diff --git a/libxrdp/xrdp_fastpath.c b/libxrdp/xrdp_fastpath.c index 711f2b85..fc0ac8a5 100644 --- a/libxrdp/xrdp_fastpath.c +++ b/libxrdp/xrdp_fastpath.c @@ -146,7 +146,10 @@ xrdp_fastpath_send(struct xrdp_fastpath *self, struct stream *s) { return 1; } - xrdp_fastpath_session_callback(self, 0x5556, 0, 0, 0, 0); + if (self->session->check_for_app_input) + { + xrdp_fastpath_session_callback(self, 0x5556, 0, 0, 0, 0); + } return 0; } diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c index a53af5ce..27d5a57a 100644 --- a/libxrdp/xrdp_iso.c +++ b/libxrdp/xrdp_iso.c @@ -129,6 +129,12 @@ xrdp_iso_process_rdp_neg_req(struct xrdp_iso *self, struct stream *s) int flags; int len; + if (!s_check_rem(s, 7)) + { + LLOGLN(10, ("xrdp_iso_process_rdpNegReq: unexpected end-of-record")); + return 1; + } + in_uint8(s, flags); if (flags != 0x0 && flags != 0x8 && flags != 0x1) { @@ -153,13 +159,22 @@ xrdp_iso_process_rdp_neg_req(struct xrdp_iso *self, struct stream *s) return 0; } -/*****************************************************************************/ -/* returns error */ +/***************************************************************************** + * Reads an X.224 PDU (X.224 section 13) preceded by a T.123 TPKT + * header (T.123 section 8) + * + * On entry, the TPKT header length field will have been inspected and used to + * set up the input stream. + * + * On exit, the TPKT header and the fixed part of the PDU header will have been + * removed from the stream. + * + * Returns error + *****************************************************************************/ static int xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len) { int ver; - int plen; *code = 0; *len = 0; @@ -169,7 +184,16 @@ xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len) LLOGLN(10, ("xrdp_iso_recv_msg error logic")); } + /* TPKT header is 4 bytes, then first 2 bytes of the X.224 CR-TPDU */ + if (!s_check_rem(s, 6)) + { + return 1; + } + in_uint8(s, ver); + in_uint8s(s, 3); /* Skip reserved field, plus length */ + in_uint8(s, *len); + in_uint8(s, *code); if (ver != 3) { @@ -178,24 +202,17 @@ xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len) return 1; } - in_uint8s(s, 1); - in_uint16_be(s, plen); - - if (plen < 4) + if (*len == 255) { + /* X.224 13.2.1 - reserved value */ + LLOGLN(10, ("xrdp_iso_recv_msg: reserved length encountered")); + LHEXDUMP(10, (s->data, 4)); return 1; } - if (!s_check_rem(s, 2)) - { - return 1; - } - - in_uint8(s, *len); - in_uint8(s, *code); - if (*code == ISO_PDU_DT) { + /* Data PDU : X.224 13.7 */ if (!s_check_rem(s, 1)) { return 1; @@ -204,6 +221,7 @@ xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code, int *len) } else { + /* Other supported PDUs : X.224 13.x */ if (!s_check_rem(s, 5)) { return 1; @@ -302,7 +320,20 @@ xrdp_iso_send_cc(struct xrdp_iso *self) free_stream(s); return 0; } -/*****************************************************************************/ +/***************************************************************************** + * Process an X.224 connection request PDU + * + * See MS-RDPCGR v20190923 sections 2.2.1.1 and 3.3.5.3.1. + * + * From the latter, in particular:- + * - The length embedded in the TPKT header MUST be examined for + * consistency with the received data. If there is a discrepancy, the + * connection SHOULD be dropped + * - If the optional routingToken field exists it MUST be ignored. + * - If the optional cookie field is present it MUST be ignored. + * - If both the routingToken and cookie fields are present, the server + * SHOULD continue with the connection. + *****************************************************************************/ /* returns error */ int xrdp_iso_incoming(struct xrdp_iso *self) @@ -310,16 +341,14 @@ xrdp_iso_incoming(struct xrdp_iso *self) int rv = 0; int code; int len; - int cookie_index; int cc_type; - char text[256]; - char *pend; struct stream *s; + int expected_pdu_len; LLOGLN(10, (" in xrdp_iso_incoming")); s = libxrdp_force_read(self->trans); - if (s == 0) + if (s == NULL) { return 1; } @@ -330,15 +359,29 @@ xrdp_iso_incoming(struct xrdp_iso *self) return 1; } - if ((code != ISO_PDU_CR) || (len < 6)) + if (code != ISO_PDU_CR) { return 1; } + /* + * Make sure the length indicator field extracted from the X.224 + * connection request TPDU corresponds to the length in the TPKT header. + * + * We do this by seeing how the indicator field minus the counted + * octets in the TPDU header (6) compares with the space left in + * the stream. + */ + expected_pdu_len = (s->end - s->p) + 6; + if (len != expected_pdu_len) + { + LLOGLN(0, ("xrdp_iso_incoming: X.224 CR-TPDU length exp %d got %d", + expected_pdu_len, len)); + return 1; + } + /* process connection request */ - pend = s->p + (len - 6); - cookie_index = 0; - while (s->p < pend) + while (s_check_rem(s, 1)) { in_uint8(s, cc_type); switch (cc_type) @@ -355,28 +398,30 @@ xrdp_iso_incoming(struct xrdp_iso *self) break; case RDP_CORRELATION_INFO: /* rdpCorrelationInfo 6 */ // TODO + if (!s_check_rem(s, 1 + 2 + 16 + 16)) + { + LLOGLN(0, ("xrdp_iso_incoming: short correlation info")); + return 1; + } + in_uint8s(s, 1 + 2 + 16 + 16); break; - case 'C': /* Cookie routingToken */ - while (s->p < pend) + case 'C': /* Cookie */ + /* The routingToken and cookie fields are both ASCII + * strings starting with the word 'Cookie: ' and + * ending with CR+LF. We ignore both, so we do + * not need to distinguish them */ + while (s_check_rem(s, 1)) { - text[cookie_index] = cc_type; - cookie_index++; - if (cookie_index > 255) - { - cookie_index = 255; - } - if ((s->p[0] == 0x0D) && (s->p[1] == 0x0A)) - { - in_uint8s(s, 2); - text[cookie_index] = 0; - cookie_index = 0; - if (g_strlen(text) > 0) - { - } - break; - } in_uint8(s, cc_type); + if (cc_type == 0x0D && s_check_rem(s, 1)) + { + in_uint8(s, cc_type); + if (cc_type == 0x0A) + { + break; + } + } } break; } diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 832cc408..a0502ef1 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -997,8 +997,11 @@ xrdp_mcs_call_callback(struct xrdp_mcs *self) { if (session->callback != 0) { - /* in xrdp_wm.c */ - rv = session->callback(session->id, 0x5556, 0, 0, 0, 0); + if (session->check_for_app_input) + { + /* in xrdp_wm.c */ + rv = session->callback(session->id, 0x5556, 0, 0, 0, 0); + } } else { diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index c0e513e4..4ce0d509 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -735,7 +735,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } in_uint16_le(s, len_domain); - if (len_domain > 511) + if (len_domain >= INFO_CLIENT_MAX_CB_LEN) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain > 511")); return 1; @@ -757,7 +757,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) self->rdp_layer->client_info.rdp_autologin = 0; } - if (len_user > 511) + if (len_user >= INFO_CLIENT_MAX_CB_LEN) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user > 511")); return 1; @@ -769,7 +769,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } in_uint16_le(s, len_password); - if (len_password > 511) + if (len_password >= INFO_CLIENT_MAX_CB_LEN) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password > 511")); return 1; @@ -781,7 +781,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } in_uint16_le(s, len_program); - if (len_program > 511) + if (len_program >= INFO_CLIENT_MAX_CB_LEN) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program > 511")); return 1; @@ -793,7 +793,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } in_uint16_le(s, len_directory); - if (len_directory > 511) + if (len_directory >= INFO_CLIENT_MAX_CB_LEN) { DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory > 511")); return 1; diff --git a/mc/mc.h b/mc/mc.h index 319f1a4c..7949695d 100644 --- a/mc/mc.h +++ b/mc/mc.h @@ -54,7 +54,7 @@ struct mod char* data, int width, int height, int srcx, int srcy); int (*server_set_cursor)(struct mod* v, int x, int y, char* data, char* mask); int (*server_palette)(struct mod* v, int* palette); - int (*server_msg)(struct mod* v, char* msg, int code); + int (*server_msg)(struct mod* v, const char* msg, int code); int (*server_is_term)(struct mod* v); int (*server_set_clip)(struct mod* v, int x, int y, int cx, int cy); int (*server_reset_clip)(struct mod* v); diff --git a/neutrinordp/xrdp-neutrinordp.h b/neutrinordp/xrdp-neutrinordp.h index b68eb43a..f50a299e 100644 --- a/neutrinordp/xrdp-neutrinordp.h +++ b/neutrinordp/xrdp-neutrinordp.h @@ -24,6 +24,7 @@ #include "defines.h" #include "xrdp_rail.h" #include "xrdp_client_info.h" +#include "xrdp_constants.h" /* this is the freerdp main header */ #include @@ -196,9 +197,9 @@ struct mod int vmaj; int vmin; int vrev; - char username[256]; - char password[256]; - char domain[256]; + char username[INFO_CLIENT_MAX_CB_LEN]; + char password[INFO_CLIENT_MAX_CB_LEN]; + char domain[INFO_CLIENT_MAX_CB_LEN]; int bool_keyBoardSynced ; /* Numlock can be out of sync, we hold state here to resolve */ int keyBoardLockInfo ; /* Holds initial numlock capslock state */ diff --git a/scripts/install_cppcheck.sh b/scripts/install_cppcheck.sh index 87f436fb..ef6eecd4 100755 --- a/scripts/install_cppcheck.sh +++ b/scripts/install_cppcheck.sh @@ -48,6 +48,45 @@ call_make() return $status } + +# ---------------------------------------------------------------------------- +# C R E A T E Z 3 V E R S I O N H +# +# Older versions of libz3-dev do not come packaged with z3_version.h. This +# function uses the z3 command to create a copy of this file in the +# cppcheck i#externalsi# directory. +# ---------------------------------------------------------------------------- +create_z3_version_h() +{ + set -- `z3 --version` + if [ $# != 3 -o "$1/$2" != Z3/version ]; then + echo "** Unexpected output from z3 command '$*'" >&2 + false + else + z3ver=$3 ; # e.g. 4.4.3 + set -- `echo $z3ver | tr '.' ' '` + if [ $# != 3 ]; then + echo "** Unable to determine Z3 version from '$z3ver'" >&2 + false + else + { + echo "#ifndef Z3_MAJOR_VERSION" + echo "#define Z3_MAJOR_VERSION $1" + echo "#endif" + echo + echo "#ifndef Z3_MINOR_VERSION" + echo "#define Z3_MINOR_VERSION $2" + echo "#endif" + echo + echo "#ifndef Z3_BUILD_NUMBER" + echo "#define Z3_BUILD_NUMBER $3" + echo "#endif" + } >externals/z3_version.h + echo " - Created z3_version.h for $1.$2.$3" + fi + fi +} + # ---------------------------------------------------------------------------- # M A I N # ---------------------------------------------------------------------------- @@ -78,14 +117,23 @@ fi # Put everything in this directory FILESDIR=$INSTALL_ROOT/$CPPCHECK_VER - # CFGDIR is needed for cppcheck before 1.86 - make_args="FILESDIR=$FILESDIR PREFIX=$FILESDIR CFGDIR=$FILESDIR" - # See https://stackoverflow.com/questions/ # 791959/download-a-specific-tag-with-git git clone -b $CPPCHECK_VER --depth 1 $REPO_URL $workdir cd $workdir + + case "$CPPCHECK_VER" in + 1.*) + # CFGDIR is needed for cppcheck before 1.86 + make_args="FILESDIR=$FILESDIR PREFIX=$FILESDIR CFGDIR=$FILESDIR" + ;; + *) make_args="FILESDIR=$FILESDIR PREFIX=$FILESDIR USE_Z3=yes" + if [ ! -f /usr/include/z3_version.h ]; then + create_z3_version_h + fi + esac + echo "Making cppcheck..." # CFGDIR is needed for cppcheck before 1.86 call_make $make_args diff --git a/sesman/access.c b/sesman/access.c index b978bf28..2ff7c9c5 100644 --- a/sesman/access.c +++ b/sesman/access.c @@ -48,8 +48,7 @@ access_login_allowed(const char *user) if ((0 == g_cfg->sec.ts_users_enable) && (0==g_cfg->sec.ts_always_group_check)) { - LOG_DBG("Terminal Server Users group is disabled, allowing authentication", - 1); + LOG_DBG("Terminal Server Users group is disabled, allowing authentication"); return 1; } @@ -98,7 +97,7 @@ access_login_mng_allowed(const char *user) if (0 == g_cfg->sec.ts_admins_enable) { LOG_DBG("[MNG] Terminal Server Admin group is disabled, " - "allowing authentication", 1); + "allowing authentication"); return 1; } diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 6b1b9326..d7ef1869 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -39,6 +39,10 @@ #include "xrdp_sockets.h" #include "audin.h" +#include "ms-rdpbcgr.h" + +#define MAX_PATH 260 + static struct trans *g_lis_trans = 0; static struct trans *g_con_trans = 0; static struct trans *g_api_lis_trans = 0; @@ -1042,9 +1046,13 @@ my_api_trans_data_in(struct trans *trans) int rv; int bytes; int ver; - int channel_name_bytes; struct chansrv_drdynvc_procs procs; - char *chan_name; + /* + * Name is limited to CHANNEL_NAME_LEN for an SVC, or MAX_PATH + * bytes for a DVC + */ + char chan_name[MAX(CHANNEL_NAME_LEN, MAX_PATH) + 1]; + unsigned int channel_name_bytes; //g_writeln("my_api_trans_data_in: extra_flags %d", trans->extra_flags); rv = 0; @@ -1067,12 +1075,13 @@ my_api_trans_data_in(struct trans *trans) rv = 1; in_uint32_le(s, channel_name_bytes); //g_writeln("my_api_trans_data_in: channel_name_bytes %d", channel_name_bytes); - chan_name = g_new0(char, channel_name_bytes + 1); - if (chan_name == NULL) + if (channel_name_bytes > (sizeof(chan_name) - 1)) { return 1; } in_uint8a(s, chan_name, channel_name_bytes); + chan_name[channel_name_bytes] = '\0'; + in_uint32_le(s, ad->chan_flags); //g_writeln("my_api_trans_data_in: chan_name %s chan_flags 0x%8.8x", chan_name, ad->chan_flags); if (ad->chan_flags == 0) @@ -1132,7 +1141,6 @@ my_api_trans_data_in(struct trans *trans) // "chan_id %d", rv, ad->chan_id); g_drdynvcs[ad->chan_id].xrdp_api_trans = trans; } - g_free(chan_name); init_stream(s, 0); trans->extra_flags = 2; trans->header_size = 0; diff --git a/sesman/chansrv/smartcard_pcsc.c b/sesman/chansrv/smartcard_pcsc.c index 51409567..5f4516db 100644 --- a/sesman/chansrv/smartcard_pcsc.c +++ b/sesman/chansrv/smartcard_pcsc.c @@ -586,9 +586,18 @@ int scard_process_list_readers(struct trans *con, struct stream *in_s) { int hContext; - int bytes_groups; + unsigned int bytes_groups; int cchReaders; - char *groups; + /* + * At the time of writing, the groups strings which can be sent + * over this interface are all small:- + * + * "SCard$AllReaders", "SCard$DefaultReaders", "SCard$LocalReaders" and + * "SCard$SystemReaders" + * + * We'll allow a bit extra in case the interface changes + */ + char groups[256]; struct pcsc_uds_client *uds_client; struct pcsc_context *lcontext; struct pcsc_list_readers *pcscListReaders; @@ -597,8 +606,14 @@ scard_process_list_readers(struct trans *con, struct stream *in_s) uds_client = (struct pcsc_uds_client *) (con->callback_data); in_uint32_le(in_s, hContext); in_uint32_le(in_s, bytes_groups); - groups = (char *) g_malloc(bytes_groups + 1, 1); + if (bytes_groups > (sizeof(groups) - 1)) + { + LLOGLN(0, ("scard_process_list_readers: Unreasonable string length %u", + bytes_groups)); + return 1; + } in_uint8a(in_s, groups, bytes_groups); + groups[bytes_groups] = '\0'; in_uint32_le(in_s, cchReaders); LLOGLN(10, ("scard_process_list_readers: hContext 0x%8.8x cchReaders %d", hContext, cchReaders)); @@ -615,7 +630,6 @@ scard_process_list_readers(struct trans *con, struct stream *in_s) pcscListReaders->cchReaders = cchReaders; scard_send_list_readers(pcscListReaders, lcontext->context, lcontext->context_bytes, groups, cchReaders, 1); - g_free(groups); return 0; } diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c index 60f82112..a9b5c514 100644 --- a/sesman/scp_v1.c +++ b/sesman/scp_v1.c @@ -60,7 +60,7 @@ scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) while ((!data) && ((retries == 0) || (current_try > 0))) { - LOG_DBG("data %d - retry %d - currenttry %d - expr %d", + LOG_DBG("data %ld - retry %d - currenttry %d - expr %d", data, retries, current_try, ((!data) && ((retries == 0) || (current_try > 0)))); diff --git a/sesman/scp_v1_mng.c b/sesman/scp_v1_mng.c index d44b9e04..840fa6b1 100644 --- a/sesman/scp_v1_mng.c +++ b/sesman/scp_v1_mng.c @@ -83,7 +83,7 @@ scp_v1_mng_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) case SCP_SERVER_STATE_MNG_LISTREQ: /* list disconnected sessions */ slist = session_get_byuser(NULL, &scount, SESMAN_SESSION_STATUS_ALL); - LOG_DBG("sessions on TS: %d (slist: %x)", scount, slist); + LOG_DBG("sessions on TS: %d (slist: %p)", scount, slist); if (0 == slist) { log_message(LOG_LEVEL_INFO, "No sessions on Terminal Server"); diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in index 483aac0e..f9cb1891 100644 --- a/sesman/sesman.ini.in +++ b/sesman/sesman.ini.in @@ -55,7 +55,7 @@ IdleTimeLimit=0 ;; Policy - session allocation policy ; Type: enum [ "Default" | "UBD" | "UBI" | "UBC" | "UBDI" | "UBDC" ] -; Default: Xrdp: and Xvnc: +; "Default" session per ; "UBD" session per ; "UBI" session per ; "UBC" session per @@ -75,13 +75,15 @@ SyslogLevel=DEBUG [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: +; on your distribution and version. Find out the appropreate path for your +; environment. The typical path is known 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/lib/xorg-server/Xorg +; Arch Linux : param=/usr/lib/Xorg ; CentOS 7 : param=/usr/bin/Xorg or param=Xorg +; CentOS 8 : param=/usr/libexec/Xorg ; param=Xorg ; Leave the rest paramaters as-is unless you understand what will happen. diff --git a/sesman/session.c b/sesman/session.c index 9fab0392..f85616c1 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -105,9 +105,6 @@ session_get_bydata(const char *name, int width, int height, int bpp, int type, { case SCP_SESSION_TYPE_XVNC: /* 0 */ type = SESMAN_SESSION_TYPE_XVNC; /* 2 */ - /* Xvnc cannot resize */ - policy = (enum SESMAN_CFG_SESS_POLICY) - (policy | SESMAN_CFG_SESS_POLICY_D); break; case SCP_SESSION_TYPE_XRDP: /* 1 */ type = SESMAN_SESSION_TYPE_XRDP; /* 1 */ diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index 57335dd1..e7a00004 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -31,6 +31,10 @@ #include "sesman.h" #include "tcp.h" +#if !defined(PACKAGE_VERSION) +#define PACKAGE_VERSION "???" +#endif + struct config_sesman g_cfg; /* config.h */ /******************************************************************************/ @@ -61,9 +65,9 @@ main(int argc, char **argv) if (argc == 1) { - g_printf("xrdp session starter v0.1\n"); + g_printf("xrdp session starter v" PACKAGE_VERSION "\n"); g_printf("\nusage:\n"); - g_printf("sesrun \n"); + g_printf("sesrun \n"); g_printf("session code 0 for Xvnc, 10 for X11RDP, 20 for Xorg\n"); } else if (argc == 8) diff --git a/sesman/verify_user_pam.c b/sesman/verify_user_pam.c index 05e941bb..312bcbc8 100644 --- a/sesman/verify_user_pam.c +++ b/sesman/verify_user_pam.c @@ -34,10 +34,13 @@ #include #include +/* Defines the maximum size of a username or password. With pam there is no real limit */ +#define MAX_BUF 8192 + struct t_user_pass { - char user[256]; - char pass[256]; + char user[MAX_BUF]; + char pass[MAX_BUF]; }; struct t_auth_info @@ -115,8 +118,8 @@ auth_userpass(const char *user, const char *pass, int *errorcode) get_service_name(service_name); auth_info = g_new0(struct t_auth_info, 1); - g_strncpy(auth_info->user_pass.user, user, 255); - g_strncpy(auth_info->user_pass.pass, pass, 255); + g_strncpy(auth_info->user_pass.user, user, MAX_BUF - 1); + g_strncpy(auth_info->user_pass.pass, pass, MAX_BUF - 1); auth_info->pamc.conv = &verify_pam_conv; auth_info->pamc.appdata_ptr = &(auth_info->user_pass); error = pam_start(service_name, 0, &(auth_info->pamc), &(auth_info->ph)); diff --git a/vnc/vnc.c b/vnc/vnc.c index 86eff852..555c8b7d 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -16,6 +16,14 @@ * limitations under the License. * * libvnc + * + * The message definitions used in this source file can be found mostly + * in RFC6143 - "The Remote Framebuffer Protocol". + * + * The ExtendedDesktopSize encoding is reserved in RFC6143, but not + * documented there. It is documented by the RFB protocol community + * wiki currently held at https://github.com/rfbproto/rfbroto. This is + * referred to below as the "RFB community wiki" */ #if defined(HAVE_CONFIG_H) @@ -26,21 +34,77 @@ #include "log.h" #include "trans.h" #include "ssl_calls.h" +#include "xrdp_client_info.h" #define LLOG_LEVEL 1 #define LLOGLN(_level, _args) \ - do \ - { \ - if (_level < LLOG_LEVEL) \ + do \ { \ - g_write("xrdp:vnc [%10.10u]: ", g_time3()); \ - g_writeln _args ; \ + if (_level < LLOG_LEVEL) \ + { \ + g_write("xrdp:vnc [%10.10u]: ", g_time3()); \ + g_writeln _args ; \ + } \ } \ - } \ - while (0) + while (0) #define AS_LOG_MESSAGE log_message +/* Client-to-server messages */ +enum c2s +{ + C2S_SET_PIXEL_FORMAT = 0, + C2S_SET_ENCODINGS = 2, + C2S_FRAMEBUFFER_UPDATE_REQUEST = 3, + C2S_KEY_EVENT = 4, + C2S_POINTER_EVENT = 5, + C2S_CLIENT_CUT_TEXT = 6, +}; + +/* Server to client messages */ +enum s2c +{ + S2C_FRAMEBUFFER_UPDATE = 0, + S2C_SET_COLOUR_MAP_ENTRIES = 1, + S2C_BELL = 2, + S2C_SERVER_CUT_TEXT = 3 +}; + +/* Encodings and pseudo-encodings + * + * The RFC uses a signed type for these. We use an unsigned type as the + * binary representation for the negative values is standardised in C + * (which it wouldn't be for an enum value) + */ + +typedef uint32_t encoding_type; + +#define ENC_RAW (encoding_type)0 +#define ENC_COPY_RECT (encoding_type)1 +#define ENC_CURSOR (encoding_type)-239 +#define ENC_DESKTOP_SIZE (encoding_type)-223 +#define ENC_EXTENDED_DESKTOP_SIZE (encoding_type)-308 + +/* Messages for ExtendedDesktopSize status code */ +static const char *eds_status_msg[] = +{ + /* 0 */ "No error", + /* 1 */ "Resize is administratively prohibited", + /* 2 */ "Out of resources", + /* 3 */ "Invalid screen layout", + /* others */ "Unknown code" +}; + +/* elements in above list */ +#define EDS_STATUS_MSG_COUNT \ + (sizeof(eds_status_msg) / sizeof(eds_status_msg[0])) + +/* Used by enabled_encodings_mask */ +enum +{ + MSK_EXTENDED_DESKTOP_SIZE = (1 << 0) +}; + static int lib_mod_process_message(struct vnc *v, struct stream *s); @@ -223,7 +287,7 @@ lib_process_channel_data(struct vnc *v, int chanid, int flags, int size, make_stream(out_s); // Send the RFB message type (CLIENT_CUT_TEXT) to the vnc server. init_stream(out_s, clip_bytes + 1 + 3 + 4 + 16); - out_uint8(out_s, 6); // RFB msg type: CLIENT_CUT_TEXT + out_uint8(out_s, C2S_CLIENT_CUT_TEXT); out_uint8s(out_s, 3); // padding // Send the length of the cut-text to the vnc server. out_uint32_be(out_s, clip_bytes); @@ -255,7 +319,365 @@ lib_process_channel_data(struct vnc *v, int chanid, int flags, int size, return 0; } -/******************************************************************************/ +/**************************************************************************//** + * Logs a debug message containing a screen layout + * + * @param lvl Level to log at + * @param source Where the layout came from + * @param layout Layout to log + */ +static void +log_screen_layout(const enum logLevels lvl, const char *source, + const struct vnc_screen_layout *layout) +{ + unsigned int i; + char text[256]; + size_t pos; + int res; + + pos = 0; + res = g_snprintf(text, sizeof(text) - pos, + "Layout from %s (geom=%dx%d #screens=%u) :", + source, layout->total_width, layout->total_height, + layout->count); + + i = 0; + while (res > 0 && (size_t)res < sizeof(text) - pos && i < layout->count) + { + pos += res; + res = g_snprintf(&text[pos], sizeof(text) - pos, + " %d:(%dx%d+%d+%d)", + layout->s[i].id, + layout->s[i].width, layout->s[i].height, + layout->s[i].x, layout->s[i].y); + ++i; + } + log_message(lvl, "%s", text); +} + +/**************************************************************************//** + * Compares two vnc_screen structures + * + * @param a First structure + * @param b Second structure + * + * @return Suitable for sorting structures with ID as the primary key + */ +static int cmp_vnc_screen(const struct vnc_screen *a, + const struct vnc_screen *b) +{ + int result = 0; + if (a->id != b->id) + { + result = a->id - b->id; + } + else if (a->x != b->x) + { + result = a->x - b->x; + } + else if (a->y != b->y) + { + result = a->y - b->y; + } + else if (a->width != b->width) + { + result = a->width - b->width; + } + else if (a->height != b->height) + { + result = a->height - b->height; + } + + return result; +} + +/**************************************************************************//** + * Compares two vnc_screen_layout structures for equality + * @param a First layout + * @param b First layout + * @return != 0 if structures are equal + */ +static int vnc_screen_layouts_equal(const struct vnc_screen_layout *a, + const struct vnc_screen_layout *b) +{ + unsigned int i; + int result = (a->total_width == b->total_width && + a->total_height == b->total_height && + a->count == b->count); + if (result) + { + for (i = 0 ; result && i < a->count ; ++i) + { + result = (cmp_vnc_screen(&a->s[i], &b->s[i]) == 0); + } + } + + return result; +} + +/**************************************************************************//** + * Reads an extended desktop size rectangle from the VNC server + * + * @param v VNC object + * @param [out] layout Desired layout for server + * @return != 0 for error + * + * @pre The next octet read from v->trans is the number of screens + * @pre layout is not already allocated + * + * @post if call is successful, layout->s must be freed after use. + * @post Returned structure is in increasing ID order + * @post layout->total_width is untouched + * @post layout->total_height is untouched + */ +static int +read_extended_desktop_size_rect(struct vnc *v, + struct vnc_screen_layout *layout) +{ + struct stream *s; + int error; + unsigned int count; + struct vnc_screen *screens; + + layout->count = 0; + layout->s = NULL; + + make_stream(s); + init_stream(s, 8192); + + /* Read in the current screen config */ + error = trans_force_read_s(v->trans, s, 4); + if (error == 0) + { + /* Get the number of screens */ + in_uint8(s, count); + in_uint8s(s, 3); + + error = trans_force_read_s(v->trans, s, 16 * count); + if (error == 0) + { + screens = g_new(struct vnc_screen, count); + if (screens == NULL) + { + log_message(LOG_LEVEL_ERROR, + "VNC : Can't alloc for %d screens", count); + error = 1; + } + else + { + unsigned int i; + for (i = 0 ; i < count ; ++i) + { + in_uint32_be(s, screens[i].id); + in_uint16_be(s, screens[i].x); + in_uint16_be(s, screens[i].y); + in_uint16_be(s, screens[i].width); + in_uint16_be(s, screens[i].height); + in_uint32_be(s, screens[i].flags); + } + + /* sort monitors in increasing ID order */ + qsort(screens, count, sizeof(screens[0]), + (int (*)(const void *, const void *))cmp_vnc_screen); + } + } + } + + free_stream(s); + + if (error == 0) + { + layout->count = count; + layout->s = screens; + } + + return error; +} + +/**************************************************************************//** + * Sends a SetDesktopSize message + * + * @param v VNC object + * @param layout Desired layout for server + * @return != 0 for error + * + * The SetDesktopSize message is documented in the RFB community wiki + * "SetDesktopSize" section. + */ +static int +send_set_desktop_size(struct vnc *v, const struct vnc_screen_layout *layout) +{ + unsigned int i; + struct stream *s; + int error; + + make_stream(s); + init_stream(s, 8192); + out_uint8(s, 251); + out_uint8(s, 0); + out_uint16_be(s, layout->total_width); + out_uint16_be(s, layout->total_height); + + out_uint8(s, layout->count); + out_uint8(s, 0); + for (i = 0 ; i < layout->count ; ++i) + { + out_uint32_be(s, layout->s[i].id); + out_uint16_be(s, layout->s[i].x); + out_uint16_be(s, layout->s[i].y); + out_uint16_be(s, layout->s[i].width); + out_uint16_be(s, layout->s[i].height); + out_uint32_be(s, layout->s[i].flags); + } + s_mark_end(s); + log_message(LOG_LEVEL_DEBUG, "VNC Sending SetDesktopSize"); + error = lib_send_copy(v, s); + free_stream(s); + + return error; +} + +/**************************************************************************//** + * Sets up a single-screen vnc_screen_layout structure + * + * @param layout Structure to set up + * @param width New client width + * @param height New client height + * + * @pre layout->count must be valid + * @pre layout->s must be valid + */ +static void +set_single_screen_layout(struct vnc_screen_layout *layout, + int width, int height) +{ + int id = 0; + int flags = 0; + + layout->total_width = width; + layout->total_height = height; + + if (layout->count == 0) + { + /* No previous layout */ + layout->s = g_new(struct vnc_screen, 1); + } + else + { + /* Keep the ID and flags from the previous first screen */ + id = layout->s[0].id; + flags = layout->s[0].flags; + + if (layout->count > 1) + { + g_free(layout->s); + layout->s = g_new(struct vnc_screen, 1); + } + } + layout->count = 1; + layout->s[0].id = id; + layout->s[0].x = 0; + layout->s[0].y = 0; + layout->s[0].width = width; + layout->s[0].height = height; + layout->s[0].flags = flags; +} + +/**************************************************************************//** + * Resize the client as a single screen + * + * @param v VNC object + * @param update_in_progress True if there's a painter update in progress + * @param width New client width + * @param height New client height + * @return != 0 for error + * + * The new client layout is recorded in v->client_layout. If the client was + * multi-screen before this call, it won't be afterwards. + */ +static int +resize_client(struct vnc *v, int update_in_progress, int width, int height) +{ + int error = 0; + + if (v->client_layout.count != 1 || + v->client_layout.total_width != width || + v->client_layout.total_height != height) + { + if (update_in_progress) + { + error = v->server_end_update(v); + } + + if (error == 0) + { + error = v->server_reset(v, width, height, v->server_bpp); + if (error == 0) + { + set_single_screen_layout(&v->client_layout, width, height); + if (update_in_progress) + { + error = v->server_begin_update(v); + } + } + } + } + + return error; +} + + +/**************************************************************************//** + * Resize the attached client from a layout + * + * @param v VNC object + * @param update_in_progress True if there's a painter update in progress + * @param layout Desired layout from server + * @return != 0 for error + * + * This has some limitations. We have no way to move multiple screens about + * on a connected client, and so we are not able to change the client unless + * we're changing to a single screeen layout. + */ +static int +resize_client_from_layout(struct vnc *v, + int update_in_progress, + const struct vnc_screen_layout *layout) +{ + int error = 0; + + if (!vnc_screen_layouts_equal(&v->client_layout, layout)) + { + /* + * we don't have the capability to resize to anything other + * than a single screen. + */ + if (layout->count != 1) + { + log_message(LOG_LEVEL_ERROR, + "VNC Resize to %d screen(s) from %d screen(s) " + "not implemented", + v->client_layout.count, layout->count); + + /* Dump some useful info, in case we get here when we don't + * need to */ + log_screen_layout(LOG_LEVEL_ERROR, "OldLayout", &v->client_layout); + log_screen_layout(LOG_LEVEL_ERROR, "NewLayout", layout); + error = 1; + } + else + { + error = resize_client(v, + update_in_progress, + layout->total_width, + layout->total_height); + } + } + + return error; +} + +/*****************************************************************************/ int lib_mod_event(struct vnc *v, int msg, long param1, long param2, long param3, long param4) @@ -309,7 +731,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, { /* fix for mstsc sending left control down with altgr */ init_stream(s, 8192); - out_uint8(s, 4); + out_uint8(s, C2S_KEY_EVENT); out_uint8(s, 0); /* down flag */ out_uint8s(s, 2); out_uint32_be(s, 65507); /* left control */ @@ -319,7 +741,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, } init_stream(s, 8192); - out_uint8(s, 4); + out_uint8(s, C2S_KEY_EVENT); out_uint8(s, msg == 15); /* down flag */ out_uint8s(s, 2); out_uint32_be(s, key); @@ -371,7 +793,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, } init_stream(s, 8192); - out_uint8(s, 5); + out_uint8(s, C2S_POINTER_EVENT); out_uint8(s, v->mod_mouse_state); out_uint16_be(s, param1); out_uint16_be(s, param2); @@ -382,10 +804,9 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2, { if (v->suppress_output == 0) { - /* FramebufferUpdateRequest */ init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 0); /* incremental == 0 : Full contents */ x = (param1 >> 16) & 0xffff; out_uint16_be(s, x); y = param1 & 0xffff; @@ -586,6 +1007,463 @@ make_color(int r, int g, int b, int bpp) return 0; } +/** + * Converts a bits-per-pixel value to bytes-per-pixel + */ +static int +get_bytes_per_pixel(int bpp) +{ + int result = (bpp + 7) / 8; + + if (result == 3) + { + result = 4; + } + + return result; +} + + +/**************************************************************************//** + * Skips the specified number of bytes from the transport + * + * @param transport Transport to read + * @param bytes Bytes to skip + * @return != 0 for error + */ +static int +skip_trans_bytes(struct trans *trans, int bytes) +{ + struct stream *s; + int error; + + make_stream(s); + init_stream(s, bytes); + error = trans_force_read_s(trans, s, bytes); + free_stream(s); + + return error; +} + +/**************************************************************************//** + * Reads an encoding from the input stream and discards it + * + * @param v VNC object + * @param x Encoding X value + * @param y Encoding Y value + * @param cx Encoding CX value + * @param cy Encoding CY value + * @param encoding Code for encoding + * @return != 0 for error + * + * @pre On entry the input stream is positioned after the encoding header + */ +static int +skip_encoding(struct vnc *v, int x, int y, int cx, int cy, + encoding_type encoding) +{ + char text[256]; + int error = 0; + + switch (encoding) + { + case ENC_RAW: + { + int need_size = cx * cy * get_bytes_per_pixel(v->server_bpp); + log_message(LOG_LEVEL_DEBUG, "Skipping ENC_RAW encoding"); + error = skip_trans_bytes(v->trans, need_size); + } + break; + + case ENC_COPY_RECT: + { + log_message(LOG_LEVEL_DEBUG, "Skipping ENC_COPY_RECT encoding"); + error = skip_trans_bytes(v->trans, 4); + } + break; + + case ENC_CURSOR: + { + int j = cx * cy * get_bytes_per_pixel(v->server_bpp); + int k = ((cx + 7) / 8) * cy; + + log_message(LOG_LEVEL_DEBUG, "Skipping ENC_CURSOR encoding"); + error = skip_trans_bytes(v->trans, j + k); + } + break; + + case ENC_DESKTOP_SIZE: + log_message(LOG_LEVEL_DEBUG, "Skipping ENC_DESKTOP_SIZE encoding"); + break; + + case ENC_EXTENDED_DESKTOP_SIZE: + { + struct vnc_screen_layout layout = {0}; + log_message(LOG_LEVEL_DEBUG, + "Skipping ENC_EXTENDED_DESKTOP_SIZE encoding " + "x=%d, y=%d geom=%dx%d", + x, y, cx, cy); + error = read_extended_desktop_size_rect(v, &layout); + g_free(layout.s); + } + break; + + default: + g_sprintf(text, "VNC error in skip_encoding " + "encoding = %8.8x", encoding); + v->server_msg(v, text, 1); + } + + return error; +} + +/**************************************************************************//** + * Parses an entire framebuffer update message from the wire, and returns the + * first matching ExtendedDesktopSize encoding if found. + * + * Caller can check for a match by examining match_layout.s after the call + * + * @param v VNC object + * @param match Function to call to check for a match + * @param [out] match_x Matching x parameter for an encoding (if needed) + * @param [out] match_y Matching y parameter for an encoding (if needed) + * @param [out] match_layout Returned layout for the encoding + * @return != 0 for error + * + * @post After a successful call, match_layout.s must be free'd + */ +static int +find_matching_extended_rect(struct vnc *v, + int (*match)(int x, int y, int cx, int cy), + int *match_x, + int *match_y, + struct vnc_screen_layout *match_layout) +{ + int error; + struct stream *s; + unsigned int num_rects; + unsigned int i; + int x; + int y; + int cx; + int cy; + encoding_type encoding; + + match_layout->s = NULL; + + make_stream(s); + init_stream(s, 8192); + error = trans_force_read_s(v->trans, s, 3); + + if (error == 0) + { + in_uint8s(s, 1); + in_uint16_be(s, num_rects); + + for (i = 0; i < num_rects; ++i) + { + if (error != 0) + { + break; + } + + init_stream(s, 8192); + error = trans_force_read_s(v->trans, s, 12); + + if (error == 0) + { + in_uint16_be(s, x); + in_uint16_be(s, y); + in_uint16_be(s, cx); + in_uint16_be(s, cy); + in_uint32_be(s, encoding); + + if (encoding == ENC_EXTENDED_DESKTOP_SIZE && + match_layout->s == NULL && + match(x, y, cx, cy)) + { + log_message(LOG_LEVEL_DEBUG, + "VNC matched ExtendedDesktopSize rectangle " + "x=%d, y=%d geom=%dx%d", + x, y, cx, cy); + + error = read_extended_desktop_size_rect(v, match_layout); + if (match_x) + { + *match_x = x; + } + if (match_y) + { + *match_y = y; + } + match_layout->total_width = cx; + match_layout->total_height = cy; + } + else + { + error = skip_encoding(v, x, y, cx, cy, encoding); + } + } + } + } + + return error; +} + +/**************************************************************************//** + * Sends a FramebufferUpdateRequest for the resize status state machine + * + * The state machine is used at the start of the connection to negotiate + * a common geometry between the client and the server. + * + * The RFB community wiki contains the following paragraph not present + * in RFC6143:- + * + * Note that an empty area can still solicit a FramebufferUpdate + * even though that update will only contain pseudo-encodings + * + * This doesn't seem to be as widely supported as we would like at + * present. We will always request at least a single pixel update to + * avoid confusing the server. + * + * @param v VNC object + * @return != 0 for error + */ +static int +send_update_request_for_resize_status(struct vnc *v) +{ + int error = 0; + struct stream *s; + make_stream(s); + init_stream(s, 8192); + + switch (v->initial_resize_status) + { + case VRS_WAITING_FOR_FIRST_UPDATE: + /* + * Ask for an immediate, minimal update. + */ + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 0); /* incremental == 0 : Full update */ + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, 1); + out_uint16_be(s, 1); + s_mark_end(s); + error = lib_send_copy(v, s); + break; + + case VRS_WAITING_FOR_RESIZE_CONFIRM: + /* + * Ask for a deferred minimal update. + */ + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 1); /* incremental == 1 : Changes only */ + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, 1); + out_uint16_be(s, 1); + s_mark_end(s); + error = lib_send_copy(v, s); + break; + + default: + /* + * Ask for a full update from the server + */ + if (v->suppress_output == 0) + { + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 0); /* incremental == 0 : Full update */ + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->server_width); + out_uint16_be(s, v->server_height); + s_mark_end(s); + error = lib_send_copy(v, s); + } + break; + } + + free_stream(s); + + return error; +} + +/**************************************************************************//** + * Tests if extended desktop size rect is an initial geometry specification + * + * This should be x == 0, but the specification says to treat undefined + * values as 0 also */ +static int +rect_is_initial_geometry(int x, int y, int cx, int cy) +{ + return (x != 1 && x != 2); +} + +/**************************************************************************//** + * Tests if extended desktop size rect is a reply to a request from us + */ +static int +rect_is_reply_to_us(int x, int y, int cx, int cy) +{ + return (x == 1); +} + +/**************************************************************************//** + * Returns an error string for an ExtendedDesktopSize status code + */ +static const char * +get_eds_status_msg(unsigned int response_code) +{ + if (response_code >= EDS_STATUS_MSG_COUNT) + { + response_code = EDS_STATUS_MSG_COUNT - 1; + } + + return eds_status_msg[response_code]; +} + +/**************************************************************************//** + * Handles the first framebuffer update from the server + * + * This is used to determine if the server supports resizes from + * us. See The RFB community wiki for details. + * + * If the server does support resizing, we send our client geometry over. + * + * @param v VNC object + * @return != 0 for error + */ +static int +lib_framebuffer_first_update(struct vnc *v) +{ + int error; + struct vnc_screen_layout layout = {0}; + + error = find_matching_extended_rect(v, + rect_is_initial_geometry, + NULL, + NULL, + &layout); + if (error == 0) + { + if (layout.s != NULL) + { + log_message(LOG_LEVEL_DEBUG, "VNC server supports resizing"); + + /* Force the client geometry over to the server */ + log_screen_layout(LOG_LEVEL_INFO, "OldLayout", &layout); + + /* + * If we've only got one screen, and the other side has + * only got one screen, we will preserve their screen ID + * and any flags. This may prevent us sending an unwanted + * SetDesktopSize message if the screen dimensions are + * a match. We can't do this with more than one screen, + * as we have no way to map different IDs + */ + if (layout.count == 1 && v->client_layout.count == 1) + { + log_message(LOG_LEVEL_DEBUG, "VNC " + "setting screen id to %d from server", + layout.s[0].id); + + v->client_layout.s[0].id = layout.s[0].id; + v->client_layout.s[0].flags = layout.s[0].flags; + } + + if (vnc_screen_layouts_equal(&layout, &v->client_layout)) + { + log_message(LOG_LEVEL_DEBUG, "Server layout is the same " + "as the client layout"); + v->initial_resize_status = VRS_DONE; + } + else + { + log_message(LOG_LEVEL_DEBUG, "Server layout differs from " + "the client layout. Changing server layout"); + error = send_set_desktop_size(v, &v->client_layout); + v->initial_resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM; + } + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC server does not support resizing"); + + /* Force client to same size as server */ + log_message(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d", + v->server_width, v->server_height); + error = resize_client(v, 0, v->server_width, v->server_height); + v->initial_resize_status = VRS_DONE; + } + + g_free(layout.s); + } + + if (error == 0) + { + error = send_update_request_for_resize_status(v); + } + + return error; +} + +/**************************************************************************//** + * Looks for a resize confirm in a framebuffer update request + * + * If the server supports resizes from us, this is used to find the + * reply to our initial resize request. See The RFB community wiki for details. + * + * @param v VNC object + * @return != 0 for error + */ +static int +lib_framebuffer_waiting_for_resize_confirm(struct vnc *v) +{ + int error; + struct vnc_screen_layout layout = {0}; + int response_code; + + error = find_matching_extended_rect(v, + rect_is_reply_to_us, + NULL, + &response_code, + &layout); + if (error == 0) + { + if (layout.s != NULL) + { + if (response_code == 0) + { + log_message(LOG_LEVEL_DEBUG, "VNC server successfully resized"); + log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout); + } + else + { + log_message(LOG_LEVEL_ERROR, + "VNC server resize failed - error code %d [%s]", + response_code, + get_eds_status_msg(response_code)); + /* Force client to same size as server */ + log_message(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d", + v->server_width, v->server_height); + error = resize_client(v, 0, v->server_width, v->server_height); + } + v->initial_resize_status = VRS_DONE; + } + + g_free(layout.s); + } + + if (error == 0) + { + error = send_update_request_for_resize_status(v); + } + + return error; +} + /******************************************************************************/ int lib_framebuffer_update(struct vnc *v) @@ -606,7 +1484,6 @@ lib_framebuffer_update(struct vnc *v) int srcx; int srcy; unsigned int encoding; - int Bpp; int pixel; int r; int g; @@ -615,14 +1492,9 @@ lib_framebuffer_update(struct vnc *v) int need_size; struct stream *s; struct stream *pixel_s; + struct vnc_screen_layout layout = { 0 }; num_recs = 0; - Bpp = (v->mod_bpp + 7) / 8; - - if (Bpp == 3) - { - Bpp = 4; - } make_stream(pixel_s); @@ -655,9 +1527,9 @@ lib_framebuffer_update(struct vnc *v) in_uint16_be(s, cy); in_uint32_be(s, encoding); - if (encoding == 0) /* raw */ + if (encoding == ENC_RAW) { - need_size = cx * cy * Bpp; + need_size = cx * cy * get_bytes_per_pixel(v->server_bpp); init_stream(pixel_s, need_size); error = trans_force_read_s(v->trans, pixel_s, need_size); @@ -666,7 +1538,7 @@ lib_framebuffer_update(struct vnc *v) error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0); } } - else if (encoding == 1) /* copy rect */ + else if (encoding == ENC_COPY_RECT) { init_stream(s, 8192); error = trans_force_read_s(v->trans, s, 4); @@ -678,11 +1550,11 @@ lib_framebuffer_update(struct vnc *v) error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy); } } - else if (encoding == 0xffffff11) /* cursor */ + else if (encoding == ENC_CURSOR) { g_memset(cursor_data, 0, 32 * (32 * 3)); g_memset(cursor_mask, 0, 32 * (32 / 8)); - j = cx * cy * Bpp; + j = cx * cy * get_bytes_per_pixel(v->server_bpp); k = ((cx + 7) / 8) * cy; init_stream(s, j + k); error = trans_force_read_s(v->trans, s, j + k); @@ -701,8 +1573,8 @@ lib_framebuffer_update(struct vnc *v) if (pixel) { - pixel = get_pixel_safe(d1, k, 31 - j, cx, cy, v->mod_bpp); - split_color(pixel, &r, &g, &b, v->mod_bpp, v->palette); + pixel = get_pixel_safe(d1, k, 31 - j, cx, cy, v->server_bpp); + split_color(pixel, &r, &g, &b, v->server_bpp, v->palette); pixel = make_color(r, g, b, 24); set_pixel_safe(cursor_data, k, j, 32, 32, 24, pixel); } @@ -723,11 +1595,26 @@ lib_framebuffer_update(struct vnc *v) error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask); } } - else if (encoding == 0xffffff21) /* desktop size */ + else if (encoding == ENC_DESKTOP_SIZE) { - v->mod_width = cx; - v->mod_height = cy; - error = v->server_reset(v, cx, cy, v->mod_bpp); + /* Server end has resized */ + v->server_width = cx; + v->server_height = cy; + error = resize_client(v, 1, cx, cy); + } + else if (encoding == ENC_EXTENDED_DESKTOP_SIZE) + { + layout.total_width = cx; + layout.total_height = cy; + error = read_extended_desktop_size_rect(v, &layout); + /* If this is a reply to a request from us, x == 1 */ + if (error == 0 && x != 1) + { + v->server_width = layout.total_width; + v->server_height = layout.total_height; + error = resize_client_from_layout(v, 1, &layout); + } + g_free(layout.s); } else { @@ -747,14 +1634,13 @@ lib_framebuffer_update(struct vnc *v) { if (v->suppress_output == 0) { - /* FramebufferUpdateRequest */ init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 1); + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 1); /* incremental == 1 : Changes only */ out_uint16_be(s, 0); out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); + out_uint16_be(s, v->server_width); + out_uint16_be(s, v->server_height); s_mark_end(s); error = lib_send_copy(v, s); } @@ -903,19 +1789,31 @@ lib_mod_process_message(struct vnc *v, struct stream *s) error = 0; if (error == 0) { - if (type == 0) /* framebuffer update */ + if (type == S2C_FRAMEBUFFER_UPDATE) { - error = lib_framebuffer_update(v); + switch (v->initial_resize_status) + { + case VRS_WAITING_FOR_FIRST_UPDATE: + error = lib_framebuffer_first_update(v); + break; + + case VRS_WAITING_FOR_RESIZE_CONFIRM: + error = lib_framebuffer_waiting_for_resize_confirm(v); + break; + + default: + error = lib_framebuffer_update(v); + } } - else if (type == 1) /* palette */ + else if (type == S2C_SET_COLOUR_MAP_ENTRIES) { error = lib_palette_update(v); } - else if (type == 2) /* bell */ + else if (type == S2C_BELL) { error = lib_bell_trigger(v); } - else if (type == 3) /* clipboard */ + else if (type == S2C_SERVER_CUT_TEXT) /* clipboard */ { log_message(LOG_LEVEL_DEBUG, "VNC got clip data"); error = lib_clip_data(v); @@ -938,8 +1836,6 @@ lib_mod_start(struct vnc *v, int w, int h, int bpp) v->server_set_fgcolor(v, 0); v->server_fill_rect(v, 0, 0, w, h); v->server_end_update(v); - v->server_width = w; - v->server_height = h; v->server_bpp = bpp; return 0; } @@ -1026,7 +1922,7 @@ lib_mod_connect(struct vnc *v) default: v->server_msg(v, "VNC error - only supporting 8, 15, 16, 24 and 32 " "bpp rdp connections", 0); - return 1; + return 1; } if (g_strcmp(v->ip, "") == 0) @@ -1055,7 +1951,7 @@ lib_mod_connect(struct vnc *v) v->server_msg(v, text, 0); g_sleep(v->delay_ms); } - + g_sprintf(text, "VNC connecting to %s %s", v->ip, con_port); v->server_msg(v, text, 0); @@ -1188,8 +2084,9 @@ lib_mod_connect(struct vnc *v) if (error == 0) { - in_uint16_be(s, v->mod_width); - in_uint16_be(s, v->mod_height); + in_uint16_be(s, v->server_width); + in_uint16_be(s, v->server_height); + init_stream(pixel_format, 8192); v->server_msg(v, "VNC receiving pixel format", 0); error = trans_force_read_s(v->trans, pixel_format, 16); @@ -1201,7 +2098,6 @@ lib_mod_connect(struct vnc *v) if (error == 0) { - v->mod_bpp = v->server_bpp; init_stream(s, 8192); v->server_msg(v, "VNC receiving name length", 0); error = trans_force_read_s(v->trans, s, 4); /* name len */ @@ -1236,15 +2132,14 @@ lib_mod_connect(struct vnc *v) /* should be connected */ if (error == 0) { - /* SetPixelFormat */ init_stream(s, 8192); - out_uint8(s, 0); + out_uint8(s, C2S_SET_PIXEL_FORMAT); out_uint8(s, 0); out_uint8(s, 0); out_uint8(s, 0); init_stream(pixel_format, 8192); - if (v->mod_bpp == 8) + if (v->server_bpp == 8) { out_uint8(pixel_format, 8); /* bits per pixel */ out_uint8(pixel_format, 8); /* depth */ @@ -1262,7 +2157,7 @@ lib_mod_connect(struct vnc *v) out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } - else if (v->mod_bpp == 15) + else if (v->server_bpp == 15) { out_uint8(pixel_format, 16); /* bits per pixel */ out_uint8(pixel_format, 15); /* depth */ @@ -1280,7 +2175,7 @@ lib_mod_connect(struct vnc *v) out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } - else if (v->mod_bpp == 16) + else if (v->server_bpp == 16) { out_uint8(pixel_format, 16); /* bits per pixel */ out_uint8(pixel_format, 16); /* depth */ @@ -1298,7 +2193,7 @@ lib_mod_connect(struct vnc *v) out_uint8(pixel_format, 0); /* blue shift */ out_uint8s(pixel_format, 3); /* pad */ } - else if (v->mod_bpp == 24 || v->mod_bpp == 32) + else if (v->server_bpp == 24 || v->server_bpp == 32) { out_uint8(pixel_format, 32); /* bits per pixel */ out_uint8(pixel_format, 24); /* depth */ @@ -1325,50 +2220,41 @@ lib_mod_connect(struct vnc *v) if (error == 0) { - /* SetEncodings */ + encoding_type e[10]; + unsigned int n = 0; + unsigned int i; + + /* These encodings are always supported */ + e[n++] = ENC_RAW; + e[n++] = ENC_COPY_RECT; + e[n++] = ENC_CURSOR; + e[n++] = ENC_DESKTOP_SIZE; + if (v->enabled_encodings_mask & MSK_EXTENDED_DESKTOP_SIZE) + { + e[n++] = ENC_EXTENDED_DESKTOP_SIZE; + } + else + { + log_message(LOG_LEVEL_INFO, + "VNC User disabled EXTENDED_DESKTOP_SIZE"); + } + init_stream(s, 8192); - out_uint8(s, 2); + out_uint8(s, C2S_SET_ENCODINGS); out_uint8(s, 0); - out_uint16_be(s, 4); - out_uint32_be(s, 0); /* raw */ - out_uint32_be(s, 1); /* copy rect */ - out_uint32_be(s, 0xffffff11); /* cursor */ - out_uint32_be(s, 0xffffff21); /* desktop size */ - v->server_msg(v, "VNC sending encodings", 0); + out_uint16_be(s, n); /* Number of encodings following */ + for (i = 0 ; i < n; ++i) + { + out_uint32_be(s, e[i]); + } s_mark_end(s); error = trans_force_write_s(v->trans, s); } if (error == 0) { - error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp); - } - - if (error == 0) - { - if (v->suppress_output == 0) - { - /* FramebufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); - v->server_msg(v, "VNC sending framebuffer update request", 0); - s_mark_end(s); - error = trans_force_write_s(v->trans, s); - } - } - - if (error == 0) - { - if (v->server_bpp != v->mod_bpp) - { - v->server_msg(v, "VNC error - server bpp and client bpp do not match", 0); - error = 1; - } + v->initial_resize_status = VRS_WAITING_FOR_FIRST_UPDATE; + error = send_update_request_for_resize_status(v); } if (error == 0) @@ -1426,6 +2312,39 @@ lib_mod_end(struct vnc *v) return 0; } +/**************************************************************************//** + * Initialises the client layout from the Windows monitor definition. + * + * @param [out] layout Our layout + * @param [in] client_info WM info + */ +static void +init_client_layout(struct vnc_screen_layout *layout, + const struct xrdp_client_info *client_info) +{ + int i; + + layout->total_width = client_info->width; + layout->total_height = client_info->height; + + layout->count = client_info->monitorCount; + layout->s = g_new(struct vnc_screen, layout->count); + + for (i = 0 ; i < client_info->monitorCount ; ++i) + { + /* Use minfo_wm, as this is normalised for a top-left of (0,0) + * as required by RFC6143 */ + layout->s[i].id = i; + layout->s[i].x = client_info->minfo_wm[i].left; + layout->s[i].y = client_info->minfo_wm[i].top; + layout->s[i].width = client_info->minfo_wm[i].right - + client_info->minfo_wm[i].left + 1; + layout->s[i].height = client_info->minfo_wm[i].bottom - + client_info->minfo_wm[i].top + 1; + layout->s[i].flags = 0; + } +} + /******************************************************************************/ int lib_mod_set_param(struct vnc *v, const char *name, const char *value) @@ -1459,6 +2378,31 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value) v->got_guid = 1; g_memcpy(v->guid, value, 16); } + else if (g_strcasecmp(name, "disabled_encodings_mask") == 0) + { + v->enabled_encodings_mask = ~g_atoi(value); + } + else if (g_strcasecmp(name, "client_info") == 0) + { + const struct xrdp_client_info *client_info = + (const struct xrdp_client_info *) value; + + g_free(v->client_layout.s); + + /* Save monitor information from the client */ + if (!client_info->multimon || client_info->monitorCount < 1) + { + set_single_screen_layout(&v->client_layout, + client_info->width, + client_info->height); + } + else + { + init_client_layout(&v->client_layout, client_info); + } + log_screen_layout(LOG_LEVEL_DEBUG, "client_info", &v->client_layout); + } + return 0; } @@ -1504,7 +2448,7 @@ lib_mod_check_wait_objs(struct vnc *v) /******************************************************************************/ /* return error */ int -lib_mod_frame_ack(struct vnc* v, int flags, int frame_id) +lib_mod_frame_ack(struct vnc *v, int flags, int frame_id) { return 0; } @@ -1512,7 +2456,7 @@ lib_mod_frame_ack(struct vnc* v, int flags, int frame_id) /******************************************************************************/ /* return error */ int -lib_mod_suppress_output(struct vnc* v, int suppress, +lib_mod_suppress_output(struct vnc *v, int suppress, int left, int top, int right, int bottom) { int error; @@ -1522,15 +2466,14 @@ lib_mod_suppress_output(struct vnc* v, int suppress, v->suppress_output = suppress; if (suppress == 0) { - /* FramebufferUpdateRequest */ make_stream(s); init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); + out_uint8(s, C2S_FRAMEBUFFER_UPDATE_REQUEST); + out_uint8(s, 0); /* incremental == 0 : Full contents */ out_uint16_be(s, 0); out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); + out_uint16_be(s, v->server_width); + out_uint16_be(s, v->server_height); s_mark_end(s); error = lib_send_copy(v, s); free_stream(s); @@ -1559,6 +2502,9 @@ mod_init(void) v->mod_check_wait_objs = lib_mod_check_wait_objs; v->mod_frame_ack = lib_mod_frame_ack; v->mod_suppress_output = lib_mod_suppress_output; + + /* Member variables */ + v->enabled_encodings_mask = -1; return (tintptr) v; } @@ -1574,6 +2520,7 @@ mod_exit(tintptr handle) return 0; } trans_delete(v->trans); + g_free(v->client_layout.s); g_free(v); return 0; } diff --git a/vnc/vnc.h b/vnc/vnc.h index 5aa83472..1e1034c0 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -26,98 +26,129 @@ #define CURRENT_MOD_VER 4 +/* Screen used for ExtendedDesktopSize / Set DesktopSize */ +struct vnc_screen +{ + int id; + int x; + int y; + int width; + int height; + int flags; +}; + +struct vnc_screen_layout +{ + int total_width; + int total_height; + unsigned int count; + /* For comparison, screens are sorted in increasing order of ID */ + struct vnc_screen *s; +}; + +/** + * Keep track of resize status at start of connection + */ +enum vnc_resize_status +{ + VRS_WAITING_FOR_FIRST_UPDATE, + VRS_WAITING_FOR_RESIZE_CONFIRM, + VRS_DONE +}; + struct vnc { - int size; /* size of this struct */ - int version; /* internal version */ - /* client functions */ - int (*mod_start)(struct vnc* v, int w, int h, int bpp); - int (*mod_connect)(struct vnc* v); - int (*mod_event)(struct vnc* v, int msg, long param1, long param2, - long param3, long param4); - int (*mod_signal)(struct vnc* v); - int (*mod_end)(struct vnc* v); - int (*mod_set_param)(struct vnc *v, const char *name, const char *value); - int (*mod_session_change)(struct vnc* v, int, int); - int (*mod_get_wait_objs)(struct vnc* v, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout); - int (*mod_check_wait_objs)(struct vnc* v); - int (*mod_frame_ack)(struct vnc* v, int flags, int frame_id); - int (*mod_suppress_output)(struct vnc* v, int suppress, - int left, int top, int right, int bottom); - tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod + int size; /* size of this struct */ + int version; /* internal version */ + /* client functions */ + int (*mod_start)(struct vnc *v, int w, int h, int bpp); + int (*mod_connect)(struct vnc *v); + int (*mod_event)(struct vnc *v, int msg, long param1, long param2, + long param3, long param4); + int (*mod_signal)(struct vnc *v); + int (*mod_end)(struct vnc *v); + int (*mod_set_param)(struct vnc *v, const char *name, const char *value); + int (*mod_session_change)(struct vnc *v, int, int); + int (*mod_get_wait_objs)(struct vnc *v, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout); + int (*mod_check_wait_objs)(struct vnc *v); + int (*mod_frame_ack)(struct vnc *v, int flags, int frame_id); + int (*mod_suppress_output)(struct vnc *v, int suppress, + int left, int top, int right, int bottom); + tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod functions above */ - /* server functions */ - int (*server_begin_update)(struct vnc* v); - int (*server_end_update)(struct vnc* v); - int (*server_fill_rect)(struct vnc* v, int x, int y, int cx, int cy); - int (*server_screen_blt)(struct vnc* v, int x, int y, int cx, int cy, - int srcx, int srcy); - int (*server_paint_rect)(struct vnc* v, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy); - int (*server_set_cursor)(struct vnc* v, int x, int y, char* data, char* mask); - int (*server_palette)(struct vnc* v, int* palette); - int (*server_msg)(struct vnc* v, const char *msg, int code); - int (*server_is_term)(struct vnc* v); - int (*server_set_clip)(struct vnc* v, int x, int y, int cx, int cy); - int (*server_reset_clip)(struct vnc* v); - int (*server_set_fgcolor)(struct vnc* v, int fgcolor); - int (*server_set_bgcolor)(struct vnc* v, int bgcolor); - int (*server_set_opcode)(struct vnc* v, int opcode); - int (*server_set_mixmode)(struct vnc* v, int mixmode); - int (*server_set_brush)(struct vnc* v, int x_origin, int y_origin, - int style, char* pattern); - int (*server_set_pen)(struct vnc* v, int style, - int width); - int (*server_draw_line)(struct vnc* v, int x1, int y1, int x2, int y2); - int (*server_add_char)(struct vnc* v, int font, int character, - int offset, int baseline, - int width, int height, char* data); - int (*server_draw_text)(struct vnc* v, int font, - int flags, int mixmode, int clip_left, int clip_top, - int clip_right, int clip_bottom, - int box_left, int box_top, - int box_right, int box_bottom, - int x, int y, char* data, int data_len); - int (*server_reset)(struct vnc* v, int width, int height, int bpp); - int (*server_query_channel)(struct vnc* v, int index, - char* channel_name, - int* channel_flags); - int (*server_get_channel_id)(struct vnc* v, const char *name); - int (*server_send_to_channel)(struct vnc* v, int channel_id, - char* data, int data_len, - int total_data_len, int flags); - int (*server_bell_trigger)(struct vnc* v); - tintptr server_dumby[100 - 25]; /* align, 100 minus the number of server + /* server functions */ + int (*server_begin_update)(struct vnc *v); + int (*server_end_update)(struct vnc *v); + int (*server_fill_rect)(struct vnc *v, int x, int y, int cx, int cy); + int (*server_screen_blt)(struct vnc *v, int x, int y, int cx, int cy, + int srcx, int srcy); + int (*server_paint_rect)(struct vnc *v, int x, int y, int cx, int cy, + char *data, int width, int height, int srcx, int srcy); + int (*server_set_cursor)(struct vnc *v, int x, int y, char *data, char *mask); + int (*server_palette)(struct vnc *v, int *palette); + int (*server_msg)(struct vnc *v, const char *msg, int code); + int (*server_is_term)(struct vnc *v); + int (*server_set_clip)(struct vnc *v, int x, int y, int cx, int cy); + int (*server_reset_clip)(struct vnc *v); + int (*server_set_fgcolor)(struct vnc *v, int fgcolor); + int (*server_set_bgcolor)(struct vnc *v, int bgcolor); + int (*server_set_opcode)(struct vnc *v, int opcode); + int (*server_set_mixmode)(struct vnc *v, int mixmode); + int (*server_set_brush)(struct vnc *v, int x_origin, int y_origin, + int style, char *pattern); + int (*server_set_pen)(struct vnc *v, int style, + int width); + int (*server_draw_line)(struct vnc *v, int x1, int y1, int x2, int y2); + int (*server_add_char)(struct vnc *v, int font, int character, + int offset, int baseline, + int width, int height, char *data); + int (*server_draw_text)(struct vnc *v, int font, + int flags, int mixmode, int clip_left, int clip_top, + int clip_right, int clip_bottom, + int box_left, int box_top, + int box_right, int box_bottom, + int x, int y, char *data, int data_len); + int (*server_reset)(struct vnc *v, int width, int height, int bpp); + int (*server_query_channel)(struct vnc *v, int index, + char *channel_name, + int *channel_flags); + int (*server_get_channel_id)(struct vnc *v, const char *name); + int (*server_send_to_channel)(struct vnc *v, int channel_id, + char *data, int data_len, + int total_data_len, int flags); + int (*server_bell_trigger)(struct vnc *v); + tintptr server_dumby[100 - 25]; /* align, 100 minus the number of server functions above */ - /* common */ - tintptr handle; /* pointer to self as long */ - tintptr wm; - tintptr painter; - tintptr si; - /* mod data */ - int server_width; - int server_height; - int server_bpp; - int mod_width; - int mod_height; - int mod_bpp; - char mod_name[256]; - int mod_mouse_state; - int palette[256]; - int vnc_desktop; - char username[256]; - char password[256]; - char ip[256]; - char port[256]; - int sck_closed; - int shift_state; /* 0 up, 1 down */ - int keylayout; - int clip_chanid; - struct stream *clip_data_s; - int delay_ms; - struct trans *trans; - int got_guid; - tui8 guid[16]; - int suppress_output; + /* common */ + tintptr handle; /* pointer to self as long */ + tintptr wm; + tintptr painter; + tintptr si; + /* mod data */ + int server_width; + int server_height; + int server_bpp; + char mod_name[256]; + int mod_mouse_state; + int palette[256]; + int vnc_desktop; + char username[256]; + char password[256]; + char ip[256]; + char port[256]; + int sck_closed; + int shift_state; /* 0 up, 1 down */ + int keylayout; + int clip_chanid; + struct stream *clip_data_s; + int delay_ms; + struct trans *trans; + int got_guid; + tui8 guid[16]; + int suppress_output; + unsigned int enabled_encodings_mask; + /* Resizeable support */ + struct vnc_screen_layout client_layout; + enum vnc_resize_status initial_resize_status; }; diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index 44fd5403..f882afd9 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -196,6 +196,10 @@ ip=127.0.0.1 port=-1 #xserverbpp=24 #delay_ms=2000 +; Disable requested encodings to support buggy VNC servers +; (1 = ExtendedDesktopSize) +#disabled_encodings_mask=0 + [vnc-any] name=vnc-any diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 1f5d010f..627f73c7 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -25,6 +25,8 @@ #include #endif +#include + #include "xrdp.h" #include "log.h" @@ -93,6 +95,30 @@ static const unsigned int g_crc_table[256] = (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) #define CRC_END(in_crc) (in_crc) = ((in_crc) ^ 0xFFFFFFFF) +/*****************************************************************************/ +/* Allocate bitmap for specified dimensions, checking for int overflow */ +static char * +alloc_bitmap_data(int width, int height, int Bpp) +{ + char *result = NULL; + if (width > 0 && height > 0 && Bpp > 0) + { + int len = width; + /* g_malloc() currently takes an 'int' size */ + if (len < INT_MAX / height) + { + len *= height; + if (len < INT_MAX / Bpp) + { + len *= Bpp; + result = (char *)malloc(len); + } + } + } + + return result; +} + /*****************************************************************************/ struct xrdp_bitmap * xrdp_bitmap_create(int width, int height, int bpp, @@ -123,14 +149,28 @@ xrdp_bitmap_create(int width, int height, int bpp, if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) { - self->data = (char *)g_malloc(width * height * Bpp, 0); + self->data = alloc_bitmap_data(width, height, Bpp); + if (self->data == NULL) + { + LLOGLN(0, ("xrdp_bitmap_create: size overflow %dx%dx%d", + width, height, Bpp)); + g_free(self); + return NULL; + } } #if defined(XRDP_PAINTER) if (self->type == WND_TYPE_SCREEN) /* noorders */ { LLOGLN(0, ("xrdp_bitmap_create: noorders")); - self->data = (char *) g_malloc(width * height * Bpp, 0); + self->data = alloc_bitmap_data(width, height, Bpp); + if (self->data == NULL) + { + LLOGLN(0, ("xrdp_bitmap_create: size overflow %dx%dx%d", + width, height, Bpp)); + g_free(self); + return NULL; + } } #endif diff --git a/xrdp/xrdp_keyboard.ini b/xrdp/xrdp_keyboard.ini index e0d7c6da..44b4bce4 100644 --- a/xrdp/xrdp_keyboard.ini +++ b/xrdp/xrdp_keyboard.ini @@ -59,6 +59,7 @@ layouts_map=default_layouts_map [default_rdp_layouts] rdp_layout_us=0x00000409 rdp_layout_us_dvorak=0x00010409 +rdp_layout_us_dvp=0x19360409 rdp_layout_dk=0x00000406 rdp_layout_de=0x00000407 rdp_layout_es=0x0000040A @@ -85,6 +86,7 @@ rdp_layout_pt=0x00000816 [default_layouts_map] rdp_layout_us=us rdp_layout_us_dvorak=dvorak +rdp_layout_us_dvp=us(dvp) rdp_layout_dk=dk rdp_layout_de=de rdp_layout_es=es @@ -122,6 +124,7 @@ layouts_map=default_layouts_map [rdp_layouts_map_mac] rdp_layout_us=us rdp_layout_us_dvorak=dvorak +rdp_layout_us_dvp=us(dvp) rdp_layout_dk=dk rdp_layout_de=de rdp_layout_es=es diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 64c75605..28f62d82 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -3261,6 +3261,9 @@ server_draw_text(struct xrdp_mod *mod, int font, } /*****************************************************************************/ + +/* Note : if this is called on a multimon setup, the client is resized + * to a single monitor */ int server_reset(struct xrdp_mod *mod, int width, int height, int bpp) { @@ -3279,10 +3282,11 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp) return 0; } - /* if same, don't need to do anything */ + /* if same (and only one monitor on client) don't need to do anything */ if (wm->client_info->width == width && - wm->client_info->height == height && - wm->client_info->bpp == bpp) + wm->client_info->height == height && + wm->client_info->bpp == bpp && + (wm->client_info->monitorCount == 0 || wm->client_info->multimon == 0)) { return 0; } diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 1f44f639..879ef12c 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -913,7 +913,7 @@ xrdp_wm_xor_pat(struct xrdp_wm *self, int x, int y, int cx, int cy) self->painter->brush.pattern[6] = 0xaa; self->painter->brush.pattern[7] = 0x55; self->painter->brush.x_origin = 0; - self->painter->brush.x_origin = 0; + self->painter->brush.y_origin = 0; self->painter->brush.style = 3; self->painter->bg_color = self->black; self->painter->fg_color = self->white; @@ -1532,6 +1532,12 @@ xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code) return 0; } + // workaround odd shift behavior + // see https://github.com/neutrinolabs/xrdp/issues/397 + if (scan_code == 42 && device_flags == (KBD_FLAG_UP | KBD_FLAG_EXT)) { + return 0; + } + if (device_flags & KBD_FLAG_UP) /* 0x8000 */ { self->keys[scan_code] = 0; diff --git a/xup/xup.c b/xup/xup.c index e6321651..a235194b 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1546,11 +1546,11 @@ lib_mod_set_param(struct mod *mod, const char *name, const char *value) { if (g_strcasecmp(name, "username") == 0) { - g_strncpy(mod->username, value, 255); + g_strncpy(mod->username, value, INFO_CLIENT_MAX_CB_LEN-1); } else if (g_strcasecmp(name, "password") == 0) { - g_strncpy(mod->password, value, 255); + g_strncpy(mod->password, value, INFO_CLIENT_MAX_CB_LEN-1); } else if (g_strcasecmp(name, "ip") == 0) { diff --git a/xup/xup.h b/xup/xup.h index ddd24e36..f7de3a17 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -24,6 +24,7 @@ #include "os_calls.h" #include "defines.h" #include "xrdp_client_info.h" +#include "xrdp_constants.h" #include "xrdp_rail.h" #define CURRENT_MOD_VER 4 @@ -154,8 +155,8 @@ struct mod int height; int bpp; int sck_closed; - char username[256]; - char password[256]; + char username[INFO_CLIENT_MAX_CB_LEN]; + char password[INFO_CLIENT_MAX_CB_LEN]; char ip[256]; char port[256]; int shift_state;