Hello community, here is the log from the commit of package xrdp for openSUSE:Factory checked in at 2020-07-28 17:25:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xrdp (Old) and /work/SRC/openSUSE:Factory/.xrdp.new.3592 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xrdp" Tue Jul 28 17:25:26 2020 rev:37 rq:823049 version:0.9.13.1 Changes: -------- --- /work/SRC/openSUSE:Factory/xrdp/xrdp.changes 2020-06-22 17:46:29.861958394 +0200 +++ /work/SRC/openSUSE:Factory/.xrdp.new.3592/xrdp.changes 2020-07-28 17:25:57.385946810 +0200 @@ -1,0 +2,15 @@ +Fri Jul 10 02:27:32 UTC 2020 - Yifan Jiang <[email protected]> + +- Update xrdp.keyring according to: + https://github.com/neutrinolabs/xrdp/issues/1627 + +------------------------------------------------------------------- +Thu Jul 2 07:07:16 UTC 2020 - Yifan Jiang <[email protected]> + +- Update to version 0.9.13.1 + + This is a security fix release that includes fixes for the + following local buffer overflow vulnerability (bsc#1173580): + https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-4044 +- Rebase xrdp-fate318398-change-expired-password.patch + +------------------------------------------------------------------- Old: ---- xrdp-0.9.13.tar.gz xrdp-0.9.13.tar.gz.asc New: ---- xrdp-0.9.13.1.tar.gz xrdp-0.9.13.1.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xrdp.spec ++++++ --- /var/tmp/diff_new_pack.RvhaWF/_old 2020-07-28 17:25:59.593949316 +0200 +++ /var/tmp/diff_new_pack.RvhaWF/_new 2020-07-28 17:25:59.597949321 +0200 @@ -22,7 +22,7 @@ %endif Name: xrdp -Version: 0.9.13 +Version: 0.9.13.1 Release: 0 Summary: Remote desktop protocol (RDP) server License: Apache-2.0 AND GPL-2.0-or-later ++++++ xrdp-0.9.13.tar.gz -> xrdp-0.9.13.1.tar.gz ++++++ ++++ 2944 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/NEWS.md new/xrdp-0.9.13.1/NEWS.md --- old/xrdp-0.9.13/NEWS.md 2020-03-11 05:33:03.000000000 +0100 +++ new/xrdp-0.9.13.1/NEWS.md 2020-06-30 08:44:05.000000000 +0200 @@ -1,3 +1,17 @@ +# 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. + +* [CVE-2022-4044: Local users can perform a buffer overflow attack against the xrdp-sesman service and then impersonate it](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-4044) + +This update is recommended for all xrdp users. + +## Special thanks + +Thanks to [Ashley Newson](https://github.com/ashleynewson) reporting the vulnerability and reviewing fix. + +----------------------- + # Release notes for xrdp v0.9.13 (2020/03/11) This release is an intermediate bugfix release. The previous version v0.9.12 has some regressions on drive redirection. @@ -111,7 +125,7 @@ ----------------------- -## Release notes for xrdp v0.9.9 (2018/12/25) +# Release notes for xrdp v0.9.9 (2018/12/25) ## Release cycle From the next release, release cycle will be changed from quarterly to every diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/README.md new/xrdp-0.9.13.1/README.md --- old/xrdp-0.9.13/README.md 2020-03-11 05:33:03.000000000 +0100 +++ new/xrdp-0.9.13.1/README.md 2020-06-30 08:46:54.000000000 +0200 @@ -2,7 +2,7 @@ [](https://gitter.im/neutrinolabs/xrdp-questions)  -*Current Version:* 0.9.13 +*Current Version:* 0.9.13.1 # xrdp - an open source RDP server diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/compile new/xrdp-0.9.13.1/compile --- old/xrdp-0.9.13/compile 2020-03-11 05:40:11.000000000 +0100 +++ new/xrdp-0.9.13.1/compile 2020-06-30 08:54:07.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # Written by Tom Tromey <[email protected]>. # # This program is free software; you can redistribute it and/or modify @@ -53,7 +53,7 @@ MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN* | MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/configure.ac new/xrdp-0.9.13.1/configure.ac --- old/xrdp-0.9.13/configure.ac 2020-03-11 05:33:03.000000000 +0100 +++ new/xrdp-0.9.13.1/configure.ac 2020-06-30 08:47:42.000000000 +0200 @@ -1,7 +1,7 @@ # Process this file with autoconf to produce a configure script AC_PREREQ(2.65) -AC_INIT([xrdp], [0.9.13], [[email protected]]) +AC_INIT([xrdp], [0.9.13.1], [[email protected]]) AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in) AM_INIT_AUTOMAKE([1.7.2 foreign]) AC_CONFIG_MACRO_DIR([m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/libpainter/compile new/xrdp-0.9.13.1/libpainter/compile --- old/xrdp-0.9.13/libpainter/compile 2020-03-11 05:40:02.000000000 +0100 +++ new/xrdp-0.9.13.1/libpainter/compile 2020-06-30 08:53:57.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # Written by Tom Tromey <[email protected]>. # # This program is free software; you can redistribute it and/or modify @@ -53,7 +53,7 @@ MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN* | MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/libpainter/missing new/xrdp-0.9.13.1/libpainter/missing --- old/xrdp-0.9.13/libpainter/missing 2020-03-11 05:40:02.000000000 +0100 +++ new/xrdp-0.9.13.1/libpainter/missing 2020-06-30 08:53:57.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard <[email protected]>, 1996. # This program is free software; you can redistribute it and/or modify diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/librfxcodec/compile new/xrdp-0.9.13.1/librfxcodec/compile --- old/xrdp-0.9.13/librfxcodec/compile 2020-03-11 05:40:08.000000000 +0100 +++ new/xrdp-0.9.13.1/librfxcodec/compile 2020-06-30 08:54:03.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # Written by Tom Tromey <[email protected]>. # # This program is free software; you can redistribute it and/or modify @@ -53,7 +53,7 @@ MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN* | MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/librfxcodec/missing new/xrdp-0.9.13.1/librfxcodec/missing --- old/xrdp-0.9.13/librfxcodec/missing 2020-03-11 05:40:08.000000000 +0100 +++ new/xrdp-0.9.13.1/librfxcodec/missing 2020-06-30 08:54:03.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard <[email protected]>, 1996. # This program is free software; you can redistribute it and/or modify diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/missing new/xrdp-0.9.13.1/missing --- old/xrdp-0.9.13/missing 2020-03-11 05:40:11.000000000 +0100 +++ new/xrdp-0.9.13.1/missing 2020-06-30 08:54:07.000000000 +0200 @@ -3,7 +3,7 @@ scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard <[email protected]>, 1996. # This program is free software; you can redistribute it and/or modify diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/sesman/libscp/libscp_types.h new/xrdp-0.9.13.1/sesman/libscp/libscp_types.h --- old/xrdp-0.9.13/sesman/libscp/libscp_types.h 2019-10-01 13:38:59.000000000 +0200 +++ new/xrdp-0.9.13.1/sesman/libscp/libscp_types.h 2020-06-30 08:07:06.000000000 +0200 @@ -59,6 +59,10 @@ #include "libscp_types_mng.h" +/* Max server incoming and outgoing message size, used to stop memory + exhaustion attempts (CVE-2020-4044) */ +#define SCP_MAX_MESSAGE_SIZE 8192 + struct SCP_CONNECTION { int in_sck; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/sesman/libscp/libscp_v0.c new/xrdp-0.9.13.1/sesman/libscp/libscp_v0.c --- old/xrdp-0.9.13/sesman/libscp/libscp_v0.c 2019-10-01 13:38:59.000000000 +0200 +++ new/xrdp-0.9.13.1/sesman/libscp/libscp_v0.c 2020-06-30 08:07:06.000000000 +0200 @@ -34,13 +34,72 @@ extern struct log_config *s_log; +/** Maximum length of a string (two bytes + len), excluding the terminator + * + * Practially this is limited by [MS-RDPBCGR] TS_INFO_PACKET + * */ +#define STRING16_MAX_LEN 512 + +/** + * Reads a big-endian uint16 followed by a string into a buffer + * + * Buffer is null-terminated on success + * + * @param s Input stream + * @param [out] Output buffer (must be >= (STRING16_MAX_LEN+1) chars) + * @param param Parameter we're reading + * @param line Line number reference + * @return != 0 if string read OK + */ +static +int in_string16(struct stream *s, char str[], const char *param, int line) +{ + int result; + + if (!s_check_rem(s, 2)) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: %s len missing", + line, param); + result = 0; + } + else + { + unsigned int sz; + + in_uint16_be(s, sz); + if (sz > STRING16_MAX_LEN) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: %s too long (%u chars)", + line, param, sz); + result = 0; + } + else + { + result = s_check_rem(s, sz); + if (!result) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: %s data missing", + line, param); + } + else + { + in_uint8a(s, str, sz); + str[sz] = '\0'; + } + } + } + return result; +} /* client API */ /******************************************************************************/ enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { tui32 version; - tui32 size; + int size; tui16 sz; init_stream(c->in_s, c->in_s->size); @@ -71,10 +130,24 @@ } sz = g_strlen(s->username); + if (sz > STRING16_MAX_LEN) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: username too long", + __LINE__); + return SCP_CLIENT_STATE_SIZE_ERR; + } out_uint16_be(c->out_s, sz); out_uint8a(c->out_s, s->username, sz); sz = g_strlen(s->password); + if (sz > STRING16_MAX_LEN) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: password too long", + __LINE__); + return SCP_CLIENT_STATE_SIZE_ERR; + } out_uint16_be(c->out_s, sz); out_uint8a(c->out_s, s->password, sz); out_uint16_be(c->out_s, s->width); @@ -111,14 +184,16 @@ in_uint32_be(c->in_s, size); - if (size < 14) + if (size < (8 + 2 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: packet size error", __LINE__); + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: msg size = %d", + __LINE__, size); return SCP_CLIENT_STATE_SIZE_ERR; } /* getting payload */ - init_stream(c->in_s, c->in_s->size); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { @@ -126,6 +201,8 @@ return SCP_CLIENT_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + /* check code */ in_uint16_be(c->in_s, sz); @@ -151,43 +228,38 @@ return SCP_CLIENT_STATE_END; } -/* server API */ -/******************************************************************************/ -enum SCP_SERVER_STATES_E -scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk) +/** + * Initialises a V0 session object + * + * At the time of the call, the version has been read from the connection + * + * @param c Connection + * @param [out] session pre-allocated session object + * @return SCP_SERVER_STATE_OK for success + */ +static enum SCP_SERVER_STATES_E +scp_v0s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session) { - tui32 version = 0; - tui32 size; - struct SCP_SESSION *session = 0; - tui16 sz; + int size; + tui16 height; + tui16 width; + tui16 bpp; tui32 code = 0; - char *buf = 0; + char buf[STRING16_MAX_LEN + 1]; - if (!skipVchk) - { - LOG_DBG("[v0:%d] starting connection", __LINE__); - - if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - c->in_s->end = c->in_s->data + 8; - in_uint32_be(c->in_s, version); - - if (version != 0) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } - } - else - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - } + scp_session_set_version(session, 0); + /* Check for a header and a code value in the length */ in_uint32_be(c->in_s, size); + if (size < (8 + 2) || size > SCP_MAX_MESSAGE_SIZE) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: msg size = %d", + __LINE__, size); + return SCP_SERVER_STATE_SIZE_ERR; + } - init_stream(c->in_s, 8196); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) { @@ -201,16 +273,6 @@ if (code == 0 || code == 10 || code == 20) { - session = scp_session_create(); - - if (0 == session) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - scp_session_set_version(session, version); - if (code == 0) { scp_session_set_type(session, SCP_SESSION_TYPE_XVNC); @@ -225,154 +287,130 @@ } /* reading username */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; + if (!in_string16(c->in_s, buf, "username", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_username(session, buf)) { - scp_session_destroy(session); log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__); - g_free(buf); return SCP_SERVER_STATE_INTERNAL_ERR; } - g_free(buf); /* reading password */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; + if (!in_string16(c->in_s, buf, "passwd", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_password(session, buf)) { - scp_session_destroy(session); log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); - g_free(buf); return SCP_SERVER_STATE_INTERNAL_ERR; } - g_free(buf); - /* width */ - in_uint16_be(c->in_s, sz); - scp_session_set_width(session, sz); - /* height */ - in_uint16_be(c->in_s, sz); - scp_session_set_height(session, sz); - /* bpp */ - in_uint16_be(c->in_s, sz); - if (0 != scp_session_set_bpp(session, (tui8)sz)) + /* width + height + bpp */ + if (!s_check_rem(c->in_s, 2 + 2 + 2)) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: width+height+bpp missing", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + in_uint16_be(c->in_s, width); + scp_session_set_width(session, width); + in_uint16_be(c->in_s, height); + scp_session_set_height(session, height); + in_uint16_be(c->in_s, bpp); + if (0 != scp_session_set_bpp(session, (tui8)bpp)) { - scp_session_destroy(session); log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: unsupported bpp: %d", - __LINE__, (tui8)sz); + __LINE__, (tui8)bpp); return SCP_SERVER_STATE_INTERNAL_ERR; } if (s_check_rem(c->in_s, 2)) { /* reading domain */ - in_uint16_be(c->in_s, sz); - - if (sz > 0) + if (!in_string16(c->in_s, buf, "domain", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + if (buf[0] != '\0') { - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; scp_session_set_domain(session, buf); - g_free(buf); } } if (s_check_rem(c->in_s, 2)) { /* reading program */ - in_uint16_be(c->in_s, sz); + if (!in_string16(c->in_s, buf, "program", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } - if (sz > 0) + if (buf[0] != '\0') { - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; scp_session_set_program(session, buf); - g_free(buf); } } if (s_check_rem(c->in_s, 2)) { /* reading directory */ - in_uint16_be(c->in_s, sz); + if (!in_string16(c->in_s, buf, "directory", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } - if (sz > 0) + if (buf[0] != '\0') { - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; scp_session_set_directory(session, buf); - g_free(buf); } } if (s_check_rem(c->in_s, 2)) { /* reading client IP address */ - in_uint16_be(c->in_s, sz); - - if (sz > 0) + if (!in_string16(c->in_s, buf, "client IP", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + if (buf[0] != '\0') { - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; scp_session_set_client_ip(session, buf); - g_free(buf); } } } else if (code == SCP_GW_AUTHENTICATION) { - /* g_writeln("Command is SCP_GW_AUTHENTICATION"); */ - session = scp_session_create(); - - if (0 == session) - { - /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);*/ - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - scp_session_set_version(session, version); scp_session_set_type(session, SCP_GW_AUTHENTICATION); /* reading username */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; + if (!in_string16(c->in_s, buf, "username", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } /* g_writeln("Received user name: %s",buf); */ if (0 != scp_session_set_username(session, buf)) { - scp_session_destroy(session); /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);*/ - g_free(buf); return SCP_SERVER_STATE_INTERNAL_ERR; } - g_free(buf); /* reading password */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; + if (!in_string16(c->in_s, buf, "passwd", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } /* g_writeln("Received password: %s",buf); */ if (0 != scp_session_set_password(session, buf)) { - scp_session_destroy(session); /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */ - g_free(buf); return SCP_SERVER_STATE_INTERNAL_ERR; } - g_free(buf); } else { @@ -380,10 +418,67 @@ return SCP_SERVER_STATE_SEQUENCE_ERR; } - (*s) = session; return SCP_SERVER_STATE_OK; } + +/* server API */ +/******************************************************************************/ +enum SCP_SERVER_STATES_E +scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk) +{ + enum SCP_SERVER_STATES_E result = SCP_SERVER_STATE_OK; + struct SCP_SESSION *session = NULL; + tui32 version = 0; + + if (!skipVchk) + { + LOG_DBG("[v0:%d] starting connection", __LINE__); + + if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + c->in_s->end = c->in_s->data + 8; + in_uint32_be(c->in_s, version); + + if (version != 0) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); + result = SCP_SERVER_STATE_VERSION_ERR; + } + } + else + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + result = SCP_SERVER_STATE_NETWORK_ERR; + } + } + + if (result == SCP_SERVER_STATE_OK) + { + session = scp_session_create(); + if (NULL == session) + { + log_message(LOG_LEVEL_WARNING, + "[v0:%d] connection aborted: no memory", + __LINE__); + result = SCP_SERVER_STATE_INTERNAL_ERR; + } + else + { + result = scp_v0s_init_session(c, session); + if (result != SCP_SERVER_STATE_OK) + { + scp_session_destroy(session); + session = NULL; + } + } + } + + (*s) = session; + + return result; +} + /******************************************************************************/ enum SCP_SERVER_STATES_E scp_v0s_allow_connection(struct SCP_CONNECTION *c, SCP_DISPLAY d, const tui8 *guid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/sesman/libscp/libscp_v1s.c new/xrdp-0.9.13.1/sesman/libscp/libscp_v1s.c --- old/xrdp-0.9.13/sesman/libscp/libscp_v1s.c 2019-10-01 13:38:59.000000000 +0200 +++ new/xrdp-0.9.13.1/sesman/libscp/libscp_v1s.c 2020-06-30 08:07:06.000000000 +0200 @@ -35,16 +35,194 @@ //extern struct log_config* s_log; +/** + * Reads a uint8 followed by a string into a buffer + * + * Buffer is null-terminated on success + * + * @param s Input stream + * @param [out] Output buffer (must be >= 256 chars) + * @param param Parameter we're reading + * @param line Line number reference + * @return != 0 if string read OK + * + * @todo + * This needs to be merged with the func of the same name in + * libscp_v1s_mng.c + */ +static +int in_string8(struct stream *s, char str[], const char *param, int line) +{ + int result; + + if (!s_check_rem(s, 1)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: %s len missing", + line, param); + result = 0; + } + else + { + unsigned int sz; + + in_uint8(s, sz); + result = s_check_rem(s, sz); + if (!result) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: %s data missing", + line, param); + } + else + { + in_uint8a(s, str, sz); + str[sz] = '\0'; + } + } + return result; +} +/* server API */ + +/** + * Initialises a V1 session object + * + * This is called after the V1 header, command set and command have been read + * + * @param c Connection + * @param [out] session pre-allocated session object + * @return SCP_SERVER_STATE_OK for success + */ +static enum SCP_SERVER_STATES_E +scp_v1s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session) +{ + tui8 type; + tui16 height; + tui16 width; + tui8 bpp; + tui8 sz; + char buf[256]; + + scp_session_set_version(session, 1); + + /* Check there's data for the session type, the height, the width, the + * bpp, the resource sharing indicator and the locale */ + if (!s_check_rem(c->in_s, 1 + 2 + 2 + 1 + 1 + 17)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: short packet", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + in_uint8(c->in_s, type); + + if ((type != SCP_SESSION_TYPE_XVNC) && (type != SCP_SESSION_TYPE_XRDP)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__); + return SCP_SERVER_STATE_SESSION_TYPE_ERR; + } + + scp_session_set_type(session, type); + + in_uint16_be(c->in_s, height); + scp_session_set_height(session, height); + in_uint16_be(c->in_s, width); + scp_session_set_width(session, width); + in_uint8(c->in_s, bpp); + if (0 != scp_session_set_bpp(session, bpp)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: unsupported bpp: %d", + __LINE__, bpp); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + in_uint8(c->in_s, sz); + scp_session_set_rsr(session, sz); + in_uint8a(c->in_s, buf, 17); + buf[17] = '\0'; + scp_session_set_locale(session, buf); + + /* Check there's enough data left for at least an IPv4 address (+len) */ + if (!s_check_rem(c->in_s, 1 + 4)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: IP addr len missing", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + in_uint8(c->in_s, sz); + + if (sz == SCP_ADDRESS_TYPE_IPV4) + { + tui32 ipv4; + in_uint32_be(c->in_s, ipv4); + scp_session_set_addr(session, sz, &ipv4); + } + else if (sz == SCP_ADDRESS_TYPE_IPV6) + { + if (!s_check_rem(c->in_s, 16)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: IP addr missing", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + in_uint8a(c->in_s, buf, 16); + scp_session_set_addr(session, sz, buf); + } + + /* reading hostname */ + if (!in_string8(c->in_s, buf, "hostname", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + + if (0 != scp_session_set_hostname(session, buf)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading username */ + if (!in_string8(c->in_s, buf, "username", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + + if (0 != scp_session_set_username(session, buf)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading password */ + if (!in_string8(c->in_s, buf, "passwd", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + + if (0 != scp_session_set_password(session, buf)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + return SCP_SERVER_STATE_OK; +} + /* server API */ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk) { + enum SCP_SERVER_STATES_E result; struct SCP_SESSION *session; tui32 version; - tui32 size; + int size; tui16 cmdset; tui16 cmd; - tui8 sz; - char buf[257]; + + (*s) = NULL; if (!skipVchk) { @@ -68,13 +246,15 @@ in_uint32_be(c->in_s, size); - if (size < 12) + /* Check the message is big enough for the header, the command set, and + * the command (but not too big) */ + if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) { log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } - init_stream(c->in_s, c->in_s->size); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) { @@ -82,6 +262,8 @@ return SCP_SERVER_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + /* reading command set */ in_uint16_be(c->in_s, cmdset); @@ -111,98 +293,27 @@ session = scp_session_create(); - if (0 == session) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - scp_session_set_version(session, 1); - - in_uint8(c->in_s, sz); - - if ((sz != SCP_SESSION_TYPE_XVNC) && (sz != SCP_SESSION_TYPE_XRDP)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__); - return SCP_SERVER_STATE_SESSION_TYPE_ERR; - } - - scp_session_set_type(session, sz); - - in_uint16_be(c->in_s, cmd); - scp_session_set_height(session, cmd); - in_uint16_be(c->in_s, cmd); - scp_session_set_width(session, cmd); - in_uint8(c->in_s, sz); - if (0 != scp_session_set_bpp(session, sz)) + if (NULL == session) { - scp_session_destroy(session); log_message(LOG_LEVEL_WARNING, - "[v1s:%d] connection aborted: unsupported bpp: %d", - __LINE__, sz); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - in_uint8(c->in_s, sz); - scp_session_set_rsr(session, sz); - in_uint8a(c->in_s, buf, 17); - buf[17] = '\0'; - scp_session_set_locale(session, buf); - - in_uint8(c->in_s, sz); - - if (sz == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->in_s, size); - scp_session_set_addr(session, sz, &size); - } - else if (sz == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->in_s, buf, 16); - scp_session_set_addr(session, sz, buf); - } - - buf[256] = '\0'; - /* reading hostname */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - - if (0 != scp_session_set_hostname(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; + "[v1s:%d] connection aborted: internal error " + "(malloc returned NULL)", __LINE__); + result = SCP_SERVER_STATE_INTERNAL_ERR; } - - /* reading username */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - - if (0 != scp_session_set_username(session, buf)) + else { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - /* reading password */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - - if (0 != scp_session_set_password(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; + result = scp_v1s_init_session(c, session); + if (result != SCP_SERVER_STATE_OK) + { + scp_session_destroy(session); + session = NULL; + } } /* returning the struct */ (*s) = session; - return SCP_SERVER_STATE_OK; + return result; } enum SCP_SERVER_STATES_E @@ -242,13 +353,12 @@ scp_v1s_request_password(struct SCP_CONNECTION *c, struct SCP_SESSION *s, const char *reason) { - tui8 sz; tui32 version; - tui32 size; + int size; tui16 cmdset; tui16 cmd; int rlen; - char buf[257]; + char buf[256]; init_stream(c->in_s, c->in_s->size); init_stream(c->out_s, c->out_s->size); @@ -296,13 +406,17 @@ in_uint32_be(c->in_s, size); - if (size < 12) + /* Check the message is big enough for the header, the command set, and + * the command (but not too big) */ + if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); + log_message(LOG_LEVEL_WARNING, + "[v1s:%d] connection aborted: size error", + __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } - init_stream(c->in_s, c->in_s->size); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) { @@ -310,6 +424,8 @@ return SCP_SERVER_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + in_uint16_be(c->in_s, cmdset); if (cmdset != SCP_COMMAND_SET_DEFAULT) @@ -326,11 +442,11 @@ return SCP_SERVER_STATE_SEQUENCE_ERR; } - buf[256] = '\0'; /* reading username */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); + if (!in_string8(c->in_s, buf, "username", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_username(s, buf)) { @@ -339,9 +455,10 @@ } /* reading password */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); + if (!in_string8(c->in_s, buf, "passwd", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_password(s, buf)) { @@ -422,7 +539,7 @@ scp_v1s_list_sessions(struct SCP_CONNECTION *c, int sescnt, struct SCP_DISCONNECTED_SESSION *ds, SCP_SID *sid) { tui32 version = 1; - tui32 size = 12; + int size = 12; tui16 cmd = 40; int pktcnt; int idx; @@ -468,13 +585,15 @@ in_uint32_be(c->in_s, size); - if (size < 12) + /* Check the message is big enough for the header, the command set, and + * the command (but not too big) */ + if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) { log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } - init_stream(c->in_s, c->in_s->size); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) { @@ -482,6 +601,8 @@ return SCP_SERVER_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) @@ -606,14 +727,16 @@ in_uint32_be(c->in_s, size); - if (size < 12) + /* Check the message is big enough for the header, the command set, and + * the command (but not too big) */ + if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) { log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); return SCP_SERVER_STATE_SIZE_ERR; } /* rest of the packet */ - init_stream(c->in_s, c->in_s->size); + init_stream(c->in_s, size - 8); if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) { @@ -621,6 +744,8 @@ return SCP_SERVER_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_DEFAULT) @@ -633,6 +758,11 @@ if (cmd == 43) { + if (!s_check_rem(c->in_s, 4)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: missing session", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } /* select session */ in_uint32_be(c->in_s, (*sid)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/sesman/libscp/libscp_v1s_mng.c new/xrdp-0.9.13.1/sesman/libscp/libscp_v1s_mng.c --- old/xrdp-0.9.13/sesman/libscp/libscp_v1s_mng.c 2019-10-01 13:38:59.000000000 +0200 +++ new/xrdp-0.9.13.1/sesman/libscp/libscp_v1s_mng.c 2020-06-30 08:07:06.000000000 +0200 @@ -38,17 +38,79 @@ static enum SCP_SERVER_STATES_E _scp_v1s_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s); -/* server API */ -enum SCP_SERVER_STATES_E -scp_v1s_mng_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s) +/** + * Reads a uint8 followed by a string into a buffer + * + * Buffer is null-terminated on success + * + * @param s Input stream + * @param [out] Output buffer (must be >= 256 chars) + * @param param Parameter we're reading + * @param line Line number reference + * @return != 0 if string read OK + * + * @todo + * This needs to be merged with the func of the same name in + * libscp_v1s.c + */ +static +int in_string8(struct stream *s, char str[], const char *param, int line) +{ + int result; + + if (!s_check_rem(s, 1)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s_mng:%d] connection aborted: %s len missing", + line, param); + result = 0; + } + else + { + unsigned int sz; + + in_uint8(s, sz); + result = s_check_rem(s, sz); + if (!result) + { + log_message(LOG_LEVEL_WARNING, + "[v1s_mng:%d] connection aborted: %s data missing", + line, param); + } + else + { + in_uint8a(s, str, sz); + str[sz] = '\0'; + } + } + return result; +} +/** + * Initialises a V1 management session object + * + * At call time, the command set value has been read from the wire, and + * the command still needs to be processed. + * + * @param c Connection + * @param [out] session pre-allocated session object + * @return SCP_SERVER_STATE_START_MANAGE for success + */ +static enum SCP_SERVER_STATES_E +scp_v1s_mng_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session) { - struct SCP_SESSION *session; tui32 ipaddr; tui16 cmd; tui8 sz; - char buf[257]; + char buf[256]; + + scp_session_set_version(session, 1); /* reading command */ + if (!s_check_rem(c->in_s, 2)) + { + /* Caller should have checked this */ + return SCP_SERVER_STATE_SIZE_ERR; + } in_uint16_be(c->in_s, cmd); if (cmd != 1) /* manager login */ @@ -56,41 +118,39 @@ return SCP_SERVER_STATE_SEQUENCE_ERR; } - session = scp_session_create(); - - if (0 == session) + /* reading username */ + if (!in_string8(c->in_s, buf, "username", __LINE__)) { - return SCP_SERVER_STATE_INTERNAL_ERR; + return SCP_SERVER_STATE_SIZE_ERR; } - scp_session_set_version(session, 1); - scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE); - - /* reading username */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_username(session, buf)) { - scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } /* reading password */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); + if (!in_string8(c->in_s, buf, "passwd", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_password(session, buf)) { - scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } - /* reading remote address */ - in_uint8(c->in_s, sz); + /* reading remote address + * Check there's enough data left for at least an IPv4 address (+len) */ + if (!s_check_rem(c->in_s, 1 + 4)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s_mng:%d] connection aborted: IP addr len missing", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + in_uint8(c->in_s, sz); if (sz == SCP_ADDRESS_TYPE_IPV4) { in_uint32_be(c->in_s, ipaddr); @@ -98,25 +158,57 @@ } else if (sz == SCP_ADDRESS_TYPE_IPV6) { + if (!s_check_rem(c->in_s, 16)) + { + log_message(LOG_LEVEL_WARNING, + "[v1s_mng:%d] connection aborted: IP addr missing", + __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } in_uint8a(c->in_s, buf, 16); scp_session_set_addr(session, sz, buf); } /* reading hostname */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); + if (!in_string8(c->in_s, buf, "hostname", __LINE__)) + { + return SCP_SERVER_STATE_SIZE_ERR; + } if (0 != scp_session_set_hostname(session, buf)) { - scp_session_destroy(session); return SCP_SERVER_STATE_INTERNAL_ERR; } - /* returning the struct */ + return SCP_SERVER_STATE_START_MANAGE; +} + +enum SCP_SERVER_STATES_E +scp_v1s_mng_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s) +{ + enum SCP_SERVER_STATES_E result; + struct SCP_SESSION *session; + + session = scp_session_create(); + if (NULL == session) + { + result = SCP_SERVER_STATE_INTERNAL_ERR; + } + else + { + scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE); + + result = scp_v1s_mng_init_session(c, session); + if (result != SCP_SERVER_STATE_START_MANAGE) + { + scp_session_destroy(session); + session = NULL; + } + } + (*s) = session; - return SCP_SERVER_STATE_START_MANAGE; + return result; } /* 002 */ @@ -289,7 +381,7 @@ _scp_v1s_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { tui32 version; - tui32 size; + int size; tui16 cmd; // tui8 dim; // char buf[257]; @@ -312,7 +404,15 @@ in_uint32_be(c->in_s, size); - init_stream(c->in_s, c->in_s->size); + /* Check the message is big enough for the header, the command set, and + * the command (but not too big) */ + if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: size error", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + init_stream(c->in_s, size - 8); /* read the rest of the packet */ if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) @@ -321,6 +421,8 @@ return SCP_SERVER_STATE_NETWORK_ERR; } + c->in_s->end = c->in_s->data + (size - 8); + in_uint16_be(c->in_s, cmd); if (cmd != SCP_COMMAND_SET_MANAGE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xrdp-0.9.13/sesman/scp.c new/xrdp-0.9.13.1/sesman/scp.c --- old/xrdp-0.9.13/sesman/scp.c 2019-10-01 13:38:59.000000000 +0200 +++ new/xrdp-0.9.13.1/sesman/scp.c 2020-06-30 08:07:06.000000000 +0200 @@ -48,8 +48,8 @@ make_stream(scon.in_s); make_stream(scon.out_s); - init_stream(scon.in_s, 8192); - init_stream(scon.out_s, 8192); + init_stream(scon.in_s, SCP_MAX_MESSAGE_SIZE); + init_stream(scon.out_s, SCP_MAX_MESSAGE_SIZE); switch (scp_vXs_accept(&scon, &(sdata))) { @@ -76,10 +76,12 @@ scp_v1_mng_process(&scon, sdata); break; case SCP_SERVER_STATE_VERSION_ERR: - /* an unknown scp version was requested, so we shut down the */ - /* connection (and log the fact) */ + case SCP_SERVER_STATE_SIZE_ERR: + /* an unknown scp version was requested, or the message sizes + are inconsistent. Shut down the connection and log the + fact */ log_message(LOG_LEVEL_WARNING, - "unknown protocol version specified. connection refused."); + "protocol violation. connection refused."); break; case SCP_SERVER_STATE_NETWORK_ERR: log_message(LOG_LEVEL_WARNING, "libscp network error."); ++++++ xrdp-fate318398-change-expired-password.patch ++++++ --- /var/tmp/diff_new_pack.RvhaWF/_old 2020-07-28 17:25:59.913949679 +0200 +++ /var/tmp/diff_new_pack.RvhaWF/_new 2020-07-28 17:25:59.913949679 +0200 @@ -1,19 +1,19 @@ -Index: b/sesman/auth.h +Index: xrdp-0.9.13.1/sesman/auth.h =================================================================== ---- a/sesman/auth.h 2017-10-26 13:30:12.000000000 +0800 -+++ b/sesman/auth.h 2018-01-04 16:40:32.178890000 +0800 -@@ -106,4 +106,6 @@ +--- xrdp-0.9.13.1.orig/sesman/auth.h ++++ xrdp-0.9.13.1/sesman/auth.h +@@ -106,4 +106,6 @@ auth_check_pwd_chg(const char *user); int auth_change_pwd(const char *user, const char *newpwd); +int +auth_change_pwd_pam(char* user, char* pass, char* newpwd); #endif -Index: b/sesman/libscp/libscp_session.c +Index: xrdp-0.9.13.1/sesman/libscp/libscp_session.c =================================================================== ---- a/sesman/libscp/libscp_session.c 2017-10-26 13:30:12.000000000 +0800 -+++ b/sesman/libscp/libscp_session.c 2018-01-04 16:40:32.178890000 +0800 -@@ -75,6 +75,10 @@ +--- xrdp-0.9.13.1.orig/sesman/libscp/libscp_session.c ++++ xrdp-0.9.13.1/sesman/libscp/libscp_session.c +@@ -75,6 +75,10 @@ scp_session_set_type(struct SCP_SESSION s->type = SCP_GW_AUTHENTICATION; break; @@ -24,7 +24,7 @@ case SCP_SESSION_TYPE_MANAGE: s->type = SCP_SESSION_TYPE_MANAGE; s->mng = (struct SCP_MNG_DATA *)g_malloc(sizeof(struct SCP_MNG_DATA), 1); -@@ -231,6 +235,32 @@ +@@ -231,6 +235,32 @@ scp_session_set_password(struct SCP_SESS return 1; } @@ -57,10 +57,10 @@ return 0; } -Index: b/sesman/libscp/libscp_types.h +Index: xrdp-0.9.13.1/sesman/libscp/libscp_types.h =================================================================== ---- a/sesman/libscp/libscp_types.h 2017-10-04 12:44:21.000000000 +0800 -+++ b/sesman/libscp/libscp_types.h 2018-01-04 16:40:32.178890000 +0800 +--- xrdp-0.9.13.1.orig/sesman/libscp/libscp_types.h ++++ xrdp-0.9.13.1/sesman/libscp/libscp_types.h @@ -47,6 +47,7 @@ * XRDP sends this command to let sesman verify if the user is allowed * to use the gateway */ @@ -69,7 +69,7 @@ #define SCP_ADDRESS_TYPE_IPV4 0x00 #define SCP_ADDRESS_TYPE_IPV6 0x01 -@@ -77,6 +78,7 @@ +@@ -81,6 +82,7 @@ struct SCP_SESSION char locale[18]; char* username; char* password; @@ -77,41 +77,33 @@ char* hostname; tui8 addr_type; tui32 ipv4addr; -Index: b/sesman/libscp/libscp_v0.c +Index: xrdp-0.9.13.1/sesman/libscp/libscp_v0.c =================================================================== ---- a/sesman/libscp/libscp_v0.c 2017-12-27 22:30:25.000000000 +0800 -+++ b/sesman/libscp/libscp_v0.c 2018-01-04 17:09:58.859805998 +0800 -@@ -329,9 +329,8 @@ +--- xrdp-0.9.13.1.orig/sesman/libscp/libscp_v0.c ++++ xrdp-0.9.13.1/sesman/libscp/libscp_v0.c +@@ -383,9 +383,9 @@ scp_v0s_init_session(struct SCP_CONNECTI } } } - else if (code == SCP_GW_AUTHENTICATION) + else if (code == SCP_GW_AUTHENTICATION || code == SCP_GW_CHAUTHTOK) { -- /* g_writeln("Command is SCP_GW_AUTHENTICATION"); */ - session = scp_session_create(); - - if (0 == session) -@@ -341,7 +340,7 @@ - } - - scp_session_set_version(session, version); - scp_session_set_type(session, SCP_GW_AUTHENTICATION); + scp_session_set_type(session, code); /* reading username */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); -@@ -358,6 +357,23 @@ + if (!in_string16(c->in_s, buf, "username", __LINE__)) + { +@@ -399,6 +399,23 @@ scp_v0s_init_session(struct SCP_CONNECTI + return SCP_SERVER_STATE_INTERNAL_ERR; } - g_free(buf); + if (code == SCP_GW_CHAUTHTOK) + { + /* reading new password */ -+ in_uint16_be(c->in_s, sz); -+ buf = g_new0(char, sz + 1); -+ in_uint8a(c->in_s, buf, sz); -+ buf[sz] = '\0'; ++ if (!in_string16(c->in_s, buf, "passwd", __LINE__)) ++ { ++ return SCP_SERVER_STATE_SIZE_ERR; ++ } + + if (0 != scp_session_set_newpass(session, buf)) + { @@ -123,9 +115,9 @@ + } + /* reading password */ - in_uint16_be(c->in_s, sz); - buf = g_new0(char, sz + 1); -@@ -435,12 +451,13 @@ + if (!in_string16(c->in_s, buf, "passwd", __LINE__)) + { +@@ -530,12 +547,13 @@ scp_v0s_deny_connection(struct SCP_CONNE /******************************************************************************/ enum SCP_SERVER_STATES_E @@ -141,11 +133,11 @@ out_uint16_be(c->out_s, value); /* reply code */ out_uint16_be(c->out_s, 0); /* dummy data */ s_mark_end(c->out_s); -Index: b/sesman/libscp/libscp_v0.h +Index: xrdp-0.9.13.1/sesman/libscp/libscp_v0.h =================================================================== ---- a/sesman/libscp/libscp_v0.h 2017-07-19 12:23:49.000000000 +0800 -+++ b/sesman/libscp/libscp_v0.h 2018-01-04 16:40:32.182893999 +0800 -@@ -79,6 +79,6 @@ +--- xrdp-0.9.13.1.orig/sesman/libscp/libscp_v0.h ++++ xrdp-0.9.13.1/sesman/libscp/libscp_v0.h +@@ -79,6 +79,6 @@ scp_v0s_deny_connection(struct SCP_CONNE * @return */ enum SCP_SERVER_STATES_E @@ -153,11 +145,11 @@ +scp_v0s_replyauthentication(struct SCP_CONNECTION* c, unsigned short int value, tui8 type); #endif -Index: b/sesman/scp_v0.c +Index: xrdp-0.9.13.1/sesman/scp_v0.c =================================================================== ---- a/sesman/scp_v0.c 2017-10-26 13:30:12.000000000 +0800 -+++ b/sesman/scp_v0.c 2018-01-04 16:40:32.182893999 +0800 -@@ -42,6 +42,13 @@ +--- xrdp-0.9.13.1.orig/sesman/scp_v0.c ++++ xrdp-0.9.13.1/sesman/scp_v0.c +@@ -42,6 +42,13 @@ scp_v0_process(struct SCP_CONNECTION *c, int errorcode = 0; bool_t do_auth_end = 1; @@ -171,7 +163,7 @@ data = auth_userpass(s->username, s->password, &errorcode); if (s->type == SCP_GW_AUTHENTICATION) -@@ -53,14 +60,14 @@ +@@ -53,14 +60,14 @@ scp_v0_process(struct SCP_CONNECTION *c, if (1 == access_login_allowed(s->username)) { /* the user is member of the correct groups. */ @@ -188,7 +180,7 @@ log_message(LOG_LEVEL_INFO, "Username okey but group problem for " "user: %s", s->username); /* g_writeln("user password ok, but group problem"); */ -@@ -71,7 +78,7 @@ +@@ -71,7 +78,7 @@ scp_v0_process(struct SCP_CONNECTION *c, /* g_writeln("username or password error"); */ log_message(LOG_LEVEL_INFO, "Username or password error for user: %s", s->username); @@ -197,11 +189,11 @@ } } else if (data) -Index: b/sesman/verify_user_pam.c +Index: xrdp-0.9.13.1/sesman/verify_user_pam.c =================================================================== ---- a/sesman/verify_user_pam.c 2017-11-27 09:42:43.000000000 +0800 -+++ b/sesman/verify_user_pam.c 2018-01-04 16:40:32.182893999 +0800 -@@ -38,6 +38,7 @@ +--- xrdp-0.9.13.1.orig/sesman/verify_user_pam.c ++++ xrdp-0.9.13.1/sesman/verify_user_pam.c +@@ -38,6 +38,7 @@ struct t_user_pass { char user[256]; char pass[256]; @@ -209,7 +201,7 @@ }; struct t_auth_info -@@ -86,6 +87,55 @@ +@@ -86,6 +87,55 @@ verify_pam_conv(int num_msg, const struc } /******************************************************************************/ @@ -265,7 +257,7 @@ static void get_service_name(char *service_name) { -@@ -103,6 +153,52 @@ +@@ -103,6 +153,52 @@ get_service_name(char *service_name) } /******************************************************************************/ @@ -318,11 +310,11 @@ /* returns long, zero is no go Stores the detailed error code in the errorcode variable*/ -Index: b/xrdp/xrdp_login_wnd.c +Index: xrdp-0.9.13.1/xrdp/xrdp_login_wnd.c =================================================================== ---- a/xrdp/xrdp_login_wnd.c 2017-11-27 09:42:43.000000000 +0800 -+++ b/xrdp/xrdp_login_wnd.c 2018-01-04 16:40:32.182893999 +0800 -@@ -187,7 +187,14 @@ +--- xrdp-0.9.13.1.orig/xrdp/xrdp_login_wnd.c ++++ xrdp-0.9.13.1/xrdp/xrdp_login_wnd.c +@@ -187,7 +187,14 @@ xrdp_wm_cancel_clicked(struct xrdp_bitma { if (wnd->wm != 0) { @@ -338,7 +330,7 @@ { g_set_wait_obj(wnd->wm->pro_layer->self_term_event); } -@@ -245,7 +252,29 @@ +@@ -245,7 +252,29 @@ xrdp_wm_ok_clicked(struct xrdp_bitmap *w } else { @@ -369,7 +361,7 @@ } return 0; -@@ -545,6 +574,32 @@ +@@ -545,6 +574,32 @@ xrdp_wm_login_notify(struct xrdp_bitmap return 0; } @@ -402,7 +394,7 @@ /******************************************************************************/ static int xrdp_wm_login_fill_in_combo(struct xrdp_wm *self, struct xrdp_bitmap *b) -@@ -825,6 +880,103 @@ +@@ -825,6 +880,103 @@ xrdp_login_wnd_create(struct xrdp_wm *se return 0; } @@ -506,11 +498,11 @@ /** * Load configuration from xrdp.ini file -Index: b/xrdp/xrdp_mm.c +Index: xrdp-0.9.13.1/xrdp/xrdp_mm.c =================================================================== ---- a/xrdp/xrdp_mm.c 2017-12-27 22:30:26.000000000 +0800 -+++ b/xrdp/xrdp_mm.c 2018-01-04 16:40:32.182893999 +0800 -@@ -1458,7 +1458,7 @@ +--- xrdp-0.9.13.1.orig/xrdp/xrdp_mm.c ++++ xrdp-0.9.13.1/xrdp/xrdp_mm.c +@@ -1781,7 +1781,7 @@ xrdp_mm_sesman_data_in(struct trans *tra /*********************************************************************/ /* return 0 on success */ static int @@ -519,7 +511,7 @@ { int reply; int rec = 32+1; /* 32 is reserved for PAM failures this means connect failure */ -@@ -1486,7 +1486,8 @@ +@@ -1809,7 +1809,8 @@ access_control(char *username, char *pas make_stream(out_s); init_stream(out_s, 500); s_push_layer(out_s, channel_hdr, 8); @@ -529,7 +521,7 @@ index = g_strlen(username); out_uint16_be(out_s, index); out_uint8a(out_s, username, index); -@@ -1494,6 +1495,14 @@ +@@ -1817,6 +1818,14 @@ access_control(char *username, char *pas index = g_strlen(password); out_uint16_be(out_s, index); out_uint8a(out_s, password, index); @@ -544,7 +536,7 @@ s_mark_end(out_s); s_pop_layer(out_s, channel_hdr); out_uint32_be(out_s, 0); /* version */ -@@ -1523,15 +1532,19 @@ +@@ -1846,15 +1855,19 @@ access_control(char *username, char *pas in_uint16_be(in_s, pAM_errorcode); /* this variable holds the PAM error code if the variable is >32 it is a "invented" code */ in_uint16_be(in_s, dummy); @@ -568,7 +560,7 @@ } else { -@@ -1849,7 +1862,7 @@ +@@ -2172,7 +2185,7 @@ xrdp_mm_connect(struct xrdp_mm *self) char port[8]; char chansrvport[256]; #ifndef USE_NOPAM @@ -577,7 +569,7 @@ char pam_auth_sessionIP[256]; char pam_auth_password[256]; char pam_auth_username[256]; -@@ -1889,7 +1902,7 @@ +@@ -2212,7 +2225,7 @@ xrdp_mm_connect(struct xrdp_mm *self) #ifndef USE_NOPAM else if (g_strcasecmp(name, "pamusername") == 0) { @@ -586,7 +578,7 @@ g_strncpy(pam_auth_username, value, 255); } else if (g_strcasecmp(name, "pamsessionmng") == 0) -@@ -1917,45 +1930,56 @@ +@@ -2240,45 +2253,56 @@ xrdp_mm_connect(struct xrdp_mm *self) } #ifndef USE_NOPAM @@ -674,7 +666,7 @@ } #endif -@@ -2048,6 +2072,59 @@ +@@ -2374,6 +2398,59 @@ xrdp_mm_connect(struct xrdp_mm *self) return rv; } @@ -734,11 +726,11 @@ /*****************************************************************************/ int xrdp_mm_get_wait_objs(struct xrdp_mm *self, -Index: b/xrdp/xrdp_types.h +Index: xrdp-0.9.13.1/xrdp/xrdp_types.h =================================================================== ---- a/xrdp/xrdp_types.h 2017-07-19 12:23:49.000000000 +0800 -+++ b/xrdp/xrdp_types.h 2018-01-04 16:40:32.182893999 +0800 -@@ -325,6 +325,7 @@ +--- xrdp-0.9.13.1.orig/xrdp/xrdp_types.h ++++ xrdp-0.9.13.1/xrdp/xrdp_types.h +@@ -329,6 +329,7 @@ struct xrdp_wm struct xrdp_cache* cache; int palette[256]; struct xrdp_bitmap* login_window; @@ -746,11 +738,11 @@ /* generic colors */ int black; int grey; -Index: b/xrdp/xrdp_wm.c +Index: xrdp-0.9.13.1/xrdp/xrdp_wm.c =================================================================== ---- a/xrdp/xrdp_wm.c 2018-01-04 16:40:31.998709999 +0800 -+++ b/xrdp/xrdp_wm.c 2018-01-04 16:40:32.182893999 +0800 -@@ -1896,6 +1896,34 @@ +--- xrdp-0.9.13.1.orig/xrdp/xrdp_wm.c ++++ xrdp-0.9.13.1/xrdp/xrdp_wm.c +@@ -1990,6 +1990,34 @@ xrdp_wm_login_mode_changed(struct xrdp_w self->dragging = 0; xrdp_wm_set_login_mode(self, 11); } @@ -785,7 +777,7 @@ return 0; } -@@ -1940,11 +1968,19 @@ +@@ -2034,11 +2062,19 @@ xrdp_wm_log_wnd_notify(struct xrdp_bitma xrdp_bitmap_invalidate(wm->screen, &rect); /* if module is gone, reset the session when ok is clicked */ @@ -806,7 +798,7 @@ } } } -@@ -2006,6 +2042,9 @@ +@@ -2100,6 +2136,9 @@ xrdp_wm_show_log(struct xrdp_wm *self) return 0; } ++++++ xrdp.keyring ++++++ --- /var/tmp/diff_new_pack.RvhaWF/_old 2020-07-28 17:25:59.949949720 +0200 +++ /var/tmp/diff_new_pack.RvhaWF/_new 2020-07-28 17:25:59.953949725 +0200 @@ -1,85 +1,125 @@ -pub 2048R/337B1F18 2016-09-19 [expires: 2018-09-19] -uid [ unknown] Idan Freiberg <[email protected]> -sub 2048R/F0F5E810 2016-09-19 - -pub 4096R/01BF10EB 2017-06-20 [expires: 2019-06-20] -uid [ unknown] Koichiro IWAO <[email protected]> -sub 4096R/CCDE08AA 2017-06-20 [expires: 2019-06-20] - -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2 -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 -=IksA +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 +AsS4Zp5tGw== +=Gas0 -----END PGP PUBLIC KEY BLOCK-----
