Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/neutrinolabs/xrdp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoichiro IWAO <meta@vmeta.jp>2022-03-17 09:20:14 +0300
committerKoichiro IWAO <meta@vmeta.jp>2022-03-17 09:20:14 +0300
commit8290e59a0121ac55c488f71cd5cafda83c7b2f95 (patch)
tree42f7812701b0013b9917e8eee58a4659f04d46ea
parent7e6194504e2b3c9708f28b30a890b498c22b3091 (diff)
parent4b092654832bfdbf6022fc0f596be6371998e156 (diff)
Merge branch 'devel' into v0.9v0.9.19
-rw-r--r--.github/workflows/build.yml2
-rw-r--r--NEWS.md39
-rw-r--r--README.md4
-rw-r--r--common/base64.c246
-rw-r--r--common/base64.h64
-rw-r--r--common/log.c159
-rw-r--r--common/log.h31
-rw-r--r--common/os_calls.c10
-rw-r--r--common/parse.h3
-rw-r--r--common/ssl_calls.c436
-rw-r--r--common/ssl_calls.h26
-rw-r--r--common/string_calls.c69
-rw-r--r--common/string_calls.h14
-rw-r--r--common/trans.c12
-rw-r--r--configure.ac4
-rw-r--r--docs/man/sesman.ini.5.in58
-rw-r--r--libxrdp/Makefile.am1
-rw-r--r--libxrdp/xrdp_channel.c16
-rw-r--r--libxrdp/xrdp_channel.h42
-rw-r--r--libxrdp/xrdp_iso.c3
-rw-r--r--libxrdp/xrdp_rdp.c14
-rwxr-xr-xscripts/run_cppcheck.sh2
-rw-r--r--sesman/access.c2
-rw-r--r--sesman/chansrv/chansrv_common.h7
-rw-r--r--sesman/chansrv/chansrv_config.c72
-rw-r--r--sesman/chansrv/chansrv_config.h2
-rw-r--r--sesman/chansrv/clipboard.c354
-rw-r--r--sesman/config.c89
-rw-r--r--sesman/config.h7
-rw-r--r--sesman/env.c4
-rw-r--r--sesman/scp.c2
-rw-r--r--sesman/scp_v0.c2
-rw-r--r--sesman/scp_v1.c2
-rw-r--r--sesman/scp_v1_mng.c2
-rw-r--r--sesman/sesman.c209
-rw-r--r--sesman/sesman.h23
-rw-r--r--sesman/sesman.ini.in19
-rw-r--r--sesman/session.c15
-rw-r--r--sesman/sig.c134
-rw-r--r--sesman/sig.h23
-rw-r--r--sesman/verify_user.c2
-rw-r--r--sesman/verify_user_bsd.c2
-rw-r--r--tests/common/Makefile.am6
-rw-r--r--tests/common/test_base64.c400
-rw-r--r--tests/common/test_common.h5
-rw-r--r--tests/common/test_common_main.c49
-rw-r--r--tests/common/test_os_calls.c3
-rw-r--r--tests/common/test_ssl_calls.c391
-rw-r--r--tests/common/test_string_calls.c348
-rw-r--r--tests/libxrdp/Makefile.am2
-rw-r--r--tests/libxrdp/test_monitor_processing.c3
-rw-r--r--tests/memtest/Makefile.am2
-rw-r--r--tests/xrdp/test_bitmap_load.c3
-rw-r--r--tests/xrdp/test_xrdp_main.c3
-rw-r--r--vnc/vnc.c1
-rw-r--r--vnc/vnc_clip.c2
-rw-r--r--xrdp/xrdp.c6
-rw-r--r--xrdp/xrdp_bitmap.c1
-rw-r--r--xrdp/xrdp_login_wnd.c10
59 files changed, 2962 insertions, 500 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d91f1dff..0b02237d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -127,7 +127,7 @@ jobs:
CC: gcc
# This is required to use a version of cppcheck other than that
# supplied with the operating system
- CPPCHECK_VER: 2.6
+ CPPCHECK_VER: 2.7
CPPCHECK_REPO: https://github.com/danmar/cppcheck.git
steps:
# This is currently the only way to get a version into
diff --git a/NEWS.md b/NEWS.md
index a27d2c3b..cc483986 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,40 @@
+# Release notes for xrdp v0.9.19 (2022/03/17)
+
+## General announcements
+* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
+
+## New features
+* Both inbound and outbound clipboards can now be restricted for text, files or images [Sponsored by @CyberTrust @clear-code and @kenhys] (#2087)
+
+## Bug fixes
+* [CVE-2022-23613](https://www.cve.org/CVERecord?id=CVE-2022-23613): Privilege escalation on xrdp-sesman (This fix is also in the out-of-band v0.9.18.1 release)
+* The versions of imlib2 used on RHEL 7 and 8 are now detected correctly (#2118)
+* Some situations where zombie processes could exist have been resolved (#2146, #2151, #2168)
+* Some null-pointer exceptions which can happen in the logging module have been addressed (#2149)
+* Some minor logging errors have been corrected (#2152)
+* The signal handling in sesman has been reworked to prevent race conditions when a child exits. This has also made it possible to reliably reload the sesman configuration with SIGHUP (#1729, #2168)
+
+## Internal changes
+* Versions 0.13 and later of checklib can undefine the pre-processor symbol `HAVE_STDINT_H`. The xrdp tests now build successfully against these versions (#2124)
+* OpenSSL packaging changes (#2130):-
+ - The OpenSSL 3 EVP interface is now fully supported
+ - When building against OpenSSL 3, an internal implementation of the RC4 cipher is used instead of the implementation from the OpenSSL legacy provider
+ - The wrapping of the OpenSSL library has been improved which should make it simpler to provide an alternative cryptographic provider in the future, if required
+ - The logging of TLS/non-TLS security negotiation has been improved
+* cppcheck version used for CI bumped to 2.7 (#2140)
+* The `s_check()` macro which is easily mis-used has been removed (#2144)
+* Status values for the DRDYNVC channel are now available in `libxrdp/xrdp_channel.h`
+
+## Changes for packagers or developers
+* On OpenSSL 3 systems, there is now no need to build with the `-Wno-error=deprecated-declarations` flag
+
+## Known issues
+
+* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
+* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
+
+-----------------------
+
# Release notes for xrdp v0.9.18.1 (2022/02/08)
This is a security fix release that includes fixes for the following privilege escalation vulnerability.
@@ -222,7 +259,7 @@ These changes are likely to impact operating system package builders and those b
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)
+* [CVE-2020-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.
diff --git a/README.md b/README.md
index 85eeba85..e2d05699 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.18.1
+[![Latest Version](https://img.shields.io/github/v/release/neutrinolabs/xrdp.svg?label=Latest%20Version)](https://github.com/neutrinolabs/xrdp/releases)
# xrdp - an open source RDP server
@@ -95,7 +95,7 @@ you would need **openssl-devel**, **pam-devel**, **libX11-devel**,
be needed depending on your configuration.
To compile xrdp from a checked out git repository, you would additionally
-need **autoconf**, **automake**, **libtool** and **pkgconfig**.
+need **autoconf**, **automake**, **libtool** and **pkg-config**.
### Get the source and build it
diff --git a/common/base64.c b/common/base64.c
index af01d7f5..0b8cfe67 100644
--- a/common/base64.c
+++ b/common/base64.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
+ * Copyright (C) 2022 Matt Burt, all xrdp contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,57 +26,229 @@
#include "string_calls.h"
-#include <openssl/bio.h>
-#include <openssl/evp.h>
+#include "base64.h"
-size_t
-base64_decoded_bytes(const char *src)
+/*
+ * Values for invalid and padding characters, used in the charmap
+ * for converting base64 to binary
+ *
+ * Thse value are specially chosen to make it easy to detect padding or
+ * invalid characters by or-ing together the values looked up in
+ * a base64 quantum */
+#define E_INVALID 0x40
+#define E_PAD 0x80
+
+/* Determine the character set on this platform */
+#if ('a' == 0x61 && 'z' == 0x7a ) && \
+ ('A' == 0x41 && 'Z' == 0x5a ) && \
+ ('0' == 0x30 && '9' == 0x39 )
+# define PLATFORM_IS_ASCII 1
+#else
+# error "Unrecognised character set on this platform"
+#endif /* character set check */
+
+
+/*
+ * Define a table to map the base64 character values to bit values.
+ */
+#ifdef PLATFORM_IS_ASCII
+#define CHARMAP_BASE 0x28
+#define E_IV E_INVALID /* For table alignment */
+const unsigned char charmap[] =
+{
+ /* 0x28 */ E_IV, E_IV, E_IV, 0x3e, E_IV, E_IV, E_IV, 0x3f,
+ /* 0x30 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ /* 0x38 */ 0x3c, 0x3d, E_IV, E_IV, E_IV, E_PAD, E_IV, E_IV,
+ /* 0x40 */ E_IV, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ /* 0x48 */ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ /* 0x50 */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ /* 0x58 */ 0x17, 0x18, 0x19, E_IV, E_IV, E_IV, E_IV, E_IV,
+ /* 0x60 */ E_IV, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ /* 0x68 */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ /* 0x70 */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ /* 0x78 */ 0x31, 0x32, 0x33
+};
+#undef E_IV
+#endif /* PLATFORM_IS_ASCII */
+
+
+/**
+ * Lookup a value in the charmap
+ *
+ * @param x - byte to lookup. Only referenced once so can safely have
+ * side effects.
+ * @param dest - destination to assign result to.
+ */
+#define CM_LOOKUP(x,dest) \
+ { \
+ unsigned int t = (unsigned int)(x) - CHARMAP_BASE;\
+ dest = (t < sizeof(charmap)) ? charmap[t] : E_INVALID; \
+ }
+
+/*****************************************************************************/
+
+int
+base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len)
{
- size_t len;
- size_t padding;
+ *actual_len = 0;
+ size_t src_len;
+ size_t src_i = 0;
+ size_t dst_i = 0;
+ unsigned int a; /* Four characters of base64 quantum */
+ unsigned int b;
+ unsigned int c;
+ unsigned int d;
+ unsigned int v;
+
+#define OUTPUT_CHAR(x) \
+ { \
+ if (dst_i < dst_len) \
+ { \
+ dst[dst_i] = (x);\
+ } \
+ ++dst_i; \
+ }
- len = g_strlen(src);
- padding = 0;
+ src_len = g_strlen(src);
- if (src[len - 1] == '=')
+ while (src_i < src_len)
{
- padding++;
+ if ((src_len - src_i) >= 4)
+ {
+ /* Usual case - full quantum */
+ CM_LOOKUP(src[src_i++], a);
+ CM_LOOKUP(src[src_i++], b);
+ CM_LOOKUP(src[src_i++], c);
+ CM_LOOKUP(src[src_i++], d);
+ }
+ else
+ {
+ /* Add padding on the end to make up the full quantum */
+ CM_LOOKUP(src[src_i++], a);
+ b = E_PAD;
+ c = E_PAD;
+ d = E_PAD;
+ if ((src_len - src_i) > 0)
+ {
+ CM_LOOKUP(src[src_i++], b);
+ }
+ if ((src_len - src_i) > 0)
+ {
+ CM_LOOKUP(src[src_i++], c);
+ }
+ }
+
+ /*
+ * Bitwise-or the translated quantum values together, so that
+ * any invalid or padding characters can be detected with a
+ * single test */
+ v = a | b | c | d;
+
+ if ((v & E_INVALID) != 0)
+ {
+ return -1; /* At least one invalid character */
+ }
- if (src[len - 2] == '=')
+ if ((v & E_PAD) == 0)
+ {
+ /* No padding - a full quantum */
+ v = (a << 18) | (b << 12) | (c << 6) | d;
+ OUTPUT_CHAR(v >> 16);
+ OUTPUT_CHAR((v >> 8) & 0xff);
+ OUTPUT_CHAR(v & 0xff);
+ }
+ else if (((a | b | c) & E_PAD) == 0)
+ {
+ /* No padding in the first 3 chars, so the padding must
+ * be at the end */
+ v = (a << 10) | (b << 4) | (c >> 2);
+ OUTPUT_CHAR(v >> 8);
+ OUTPUT_CHAR(v & 0xff);
+ }
+ else if (((a | b) & E_PAD) == 0 && c == d)
{
- padding++;
+ /* No padding in first two chars, so if the last two chars are
+ * equal, they must both be padding */
+ v = (a << 2) | (b >> 4);
+ OUTPUT_CHAR(v);
+ }
+ else
+ {
+ /* Illegal padding */
+ return -1;
}
}
- return len * 3 / 4 - padding;
+ *actual_len = dst_i;
+ return 0;
+
+#undef OUTPUT_CHAR
}
/*****************************************************************************/
-char *
-base64_decode(char *dst, const char *src, size_t len)
+size_t
+base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len)
{
- BIO *b64;
- BIO *bio;
- char *b64str;
- size_t estimated_decoded_bytes;
- size_t decoded_bytes;
-
- b64str = g_strdup(src);
- estimated_decoded_bytes = base64_decoded_bytes(b64str);
- dst[estimated_decoded_bytes] = '\0';
-
- b64 = BIO_new(BIO_f_base64());
- bio = BIO_new_mem_buf(b64str, len);
- bio = BIO_push(b64, bio);
- BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
- decoded_bytes = BIO_read(bio, dst, len);
- BIO_free_all(bio);
-
- /* if input is corrupt, return empty string */
- if (estimated_decoded_bytes != decoded_bytes)
+ char *p = dst;
+ size_t src_i = 0;
+ size_t max_src_len;
+ unsigned int v;
+ static const char *b64chr =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/=";
+
+ /* Each three octets of the source results in four bytes at the output,
+ * plus we need a terminator. So we can work out the maximum number of
+ * source octets we can process */
+ if (dst_len == 0)
+ {
+ max_src_len = 0;
+ }
+ else
+ {
+ max_src_len = (dst_len - 1) / 4 * 3;
+ }
+
+ if (src_len > max_src_len)
+ {
+ src_len = max_src_len;
+ }
+
+ while (src_i < src_len)
{
- g_strncpy(dst, "", sizeof(""));
+ switch (src_len - src_i)
+ {
+ case 1:
+ v = (unsigned int)(unsigned char)src[src_i++] << 4;
+ *p++ = b64chr[v >> 6];
+ *p++ = b64chr[v & 0x3f];
+ *p++ = b64chr[64];
+ *p++ = b64chr[64];
+ break;
+
+ case 2:
+ v = (unsigned int)(unsigned char)src[src_i++] << 10;
+ v |= (unsigned int)(unsigned char)src[src_i++] << 2;
+ *p++ = b64chr[v >> 12];
+ *p++ = b64chr[(v >> 6) & 0x3f];
+ *p++ = b64chr[v & 0x3f];
+ *p++ = b64chr[64];
+ break;
+
+ default:
+ v = (unsigned int)(unsigned char)src[src_i++] << 16;
+ v |= (unsigned int)(unsigned char)src[src_i++] << 8;
+ v |= (unsigned int)(unsigned char)src[src_i++];
+ *p++ = b64chr[v >> 18];
+ *p++ = b64chr[(v >> 12) & 0x3f];
+ *p++ = b64chr[(v >> 6) & 0x3f];
+ *p++ = b64chr[v & 0x3f];
+ break;
+ }
}
- return dst;
+ *p = '\0';
+
+ return src_len;
}
diff --git a/common/base64.h b/common/base64.h
index b53ed88f..1b341e9b 100644
--- a/common/base64.h
+++ b/common/base64.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
+ * Copyright (C) 2021 Koichiro Iwao, all xrdp contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,16 +17,66 @@
/**
* @file common/base64.h
* @brief Base64 encoder / decoder
+ *
+ * Base-64 is described in RFC4648. The following notes apply to this
+ * implementation:-
+ * - The only supported characters are [A-Za-z0-9+/=]. At present,
+ * embedded linefeeds and URL encodings are not supported.
+ *
*/
-#if !defined(SSL_CALLS_H)
-#define SSL_CALLS_H
+#if !defined(BASE64_CALLS_H)
+#define BASE64_CALLS_H
#include "arch.h"
+/*
+ * Decodes a base64 string
+ *
+ * @param src Pointer to null-terminated source
+ * @param dst Pointer to output buffer
+ * @param dst_len Length of above. No more than this is written to the
+ * output buffer
+ * @param actual_len Pointer to value to receive actual length of decoded data
+ * @return 0 for success, 1 for an invalid input string
+ *
+ * The following notes apply to this implementation:-
+ * - Embedded padding is supported, provided it only occurs at the end
+ * of a quantum as described in RFC4648(4). This allows concatenated
+ * encodings to be fed into the decoder.
+ * - Padding of the last quantum is assumed if not provided.
+ * - Excess padding of the last quantum is ignored.
+ *
+ * Only dst_len bytes at most are written to the output. The length
+ * returned in actual_len however represents how much buffer is needed for
+ * a correct result. This may be more than dst_len, and enables the caller
+ * to detect a potential buffer overflow
+ */
+int
+base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len);
+
+/*
+ * Encodes a buffer as base64
+ *
+ * @param src Pointer to source
+ * @param src_len Length of above.
+ * @param dst Pointer to output buffer for null-terminated string
+ * @param dst_len Length of above. No more than this is written to the
+ * output buffer
+ * @return Number of source characters processed
+ *
+ * The following notes apply to this implementation:-
+ * - Padding of the last quantum is always written if the number of
+ * source bytes is not divisible by 3.
+ *
+ * The number of source characters processed is always returned. If
+ * the destination buffer is too small for all the output plus a
+ * terminator, the returned value from this procedure will be less than
+ * src_len. In this case no padding characters will have been written,
+ * and the remaining characters can be converted with more calls to
+ * this procedure.
+ */
size_t
-base64_decoded_bytes(const char *src);
-char *
-base64_decode(char *dst, const char *src, size_t len);
+base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len);
-#endif
+#endif /* BASE64_CALLS_H */
diff --git a/common/log.c b/common/log.c
index b2bab18e..c0cc857f 100644
--- a/common/log.c
+++ b/common/log.c
@@ -224,7 +224,7 @@ internal_log_end(struct log_config *l_cfg)
}
/**
- * Converts a string representing th log level to a value
+ * Converts a string representing the log level to a value
* @param buf
* @return
*/
@@ -470,6 +470,7 @@ internalInitAndAllocStruct(void)
{
ret->fd = -1;
ret->enable_syslog = 0;
+#ifdef LOG_PER_LOGGER_LEVEL
ret->per_logger_level = list_create();
if (ret->per_logger_level != NULL)
{
@@ -481,6 +482,7 @@ internalInitAndAllocStruct(void)
g_free(ret);
ret = NULL;
}
+#endif
}
else
{
@@ -490,34 +492,71 @@ internalInitAndAllocStruct(void)
return ret;
}
-void
-internal_log_config_copy(struct log_config *dest, const struct log_config *src)
-{
- int i;
+/**
+ * Copies logging levels only from one log_config structure to another
+ **/
- dest->enable_syslog = src->enable_syslog;
- dest->fd = src->fd;
- dest->log_file = g_strdup(src->log_file);
+static void
+internal_log_config_copy_levels(struct log_config *dest,
+ const struct log_config *src)
+{
dest->log_level = src->log_level;
- dest->log_lock = src->log_lock;
- dest->log_lock_attr = src->log_lock_attr;
- dest->program_name = src->program_name;
dest->enable_syslog = src->enable_syslog;
dest->syslog_level = src->syslog_level;
dest->enable_console = src->enable_console;
dest->console_level = src->console_level;
- dest->enable_pid = src->enable_pid;
- dest->dump_on_start = src->dump_on_start;
+
+#ifdef LOG_PER_LOGGER_LEVEL
+ if (dest->per_logger_level == NULL)
+ {
+ dest->per_logger_level = list_create();
+ if (dest->per_logger_level == NULL)
+ {
+ return;
+ }
+ dest->per_logger_level->auto_free = 1;
+ }
+ else
+ {
+ list_clear(dest->per_logger_level);
+ }
+
+ if (src->per_logger_level == NULL)
+ {
+ return;
+ }
+
+ int i;
+
for (i = 0; i < src->per_logger_level->count; ++i)
{
struct log_logger_level *dst_logger =
(struct log_logger_level *)g_malloc(sizeof(struct log_logger_level), 1);
- g_memcpy(dst_logger,
- (struct log_logger_level *) list_get_item(src->per_logger_level, i),
- sizeof(struct log_logger_level));
+ *dst_logger = *(struct log_logger_level *) list_get_item(src->per_logger_level, i),
- list_add_item(dest->per_logger_level, (tbus) dst_logger);
+ list_add_item(dest->per_logger_level, (tbus) dst_logger);
+ }
+#endif
+}
+
+void
+internal_log_config_copy(struct log_config *dest, const struct log_config *src)
+{
+ if (src != NULL && dest != NULL)
+ {
+ dest->fd = src->fd;
+ g_free(dest->log_file);
+ dest->log_file = g_strdup(src->log_file);
+#ifdef LOG_ENABLE_THREAD
+ dest->log_lock = src->log_lock;
+ dest->log_lock_attr = src->log_lock_attr;
+#endif
+ dest->program_name = src->program_name;
+ dest->enable_pid = src->enable_pid;
+ dest->dump_on_start = src->dump_on_start;
+
+ internal_log_config_copy_levels(dest, src);
}
}
@@ -571,6 +610,7 @@ internal_log_location_overrides_level(const char *function_name,
const char *file_name,
enum logLevels *log_level_return)
{
+#ifdef LOG_PER_LOGGER_LEVEL
struct log_logger_level *logger = NULL;
int i;
@@ -591,6 +631,7 @@ internal_log_location_overrides_level(const char *function_name,
return 1;
}
}
+#endif
return 0;
}
@@ -662,11 +703,13 @@ log_config_free(struct log_config *config)
{
if (config != NULL)
{
+#ifdef LOG_PER_LOGGER_LEVEL
if (config->per_logger_level != NULL)
{
list_delete(config->per_logger_level);
config->per_logger_level = NULL;
}
+#endif
if (0 != config->log_file)
{
@@ -680,6 +723,62 @@ log_config_free(struct log_config *config)
return LOG_STARTUP_OK;
}
+/**
+ * Restarts the logging.
+ *
+ * The logging file is never changed, as it is common in xrdp to share a
+ * log file between parents and children. The end result would be
+ * confusing for the user.
+ */
+static enum logReturns
+log_restart_from_param(const struct log_config *lc)
+{
+ enum logReturns rv = LOG_GENERAL_ERROR;
+
+ if (g_staticLogConfig == NULL)
+ {
+ log_message(LOG_LEVEL_ALWAYS, "Log not already initialized");
+ }
+ else if (lc == NULL)
+ {
+ g_writeln("lc to log_start_from_param is NULL");
+ }
+ else
+ {
+ if (g_staticLogConfig->fd >= 0 &&
+ g_strcmp(g_staticLogConfig->log_file, lc->log_file) != 0)
+ {
+ log_message(LOG_LEVEL_WARNING,
+ "Unable to change log file name from %s to %s",
+ g_staticLogConfig->log_file,
+ lc->log_file);
+ }
+ /* Reconfigure syslog logging, allowing for a program_name change */
+ if (g_staticLogConfig->enable_syslog)
+ {
+ closelog();
+ }
+ if (lc->enable_syslog)
+ {
+ openlog(lc->program_name, LOG_CONS | LOG_PID, LOG_DAEMON);
+ }
+
+ /* Copy over simple values... */
+#ifdef LOG_ENABLE_THREAD
+ g_staticLogConfig->log_lock = lc->log_lock;
+ g_staticLogConfig->log_lock_attr = lc->log_lock_attr;
+#endif
+ g_staticLogConfig->program_name = lc->program_name;
+ g_staticLogConfig->enable_pid = lc->enable_pid;
+ g_staticLogConfig->dump_on_start = lc->dump_on_start;
+
+ /* ... and the log levels */
+ internal_log_config_copy_levels(g_staticLogConfig, lc);
+ rv = LOG_STARTUP_OK;
+ }
+ return rv;
+}
+
enum logReturns
log_start_from_param(const struct log_config *src_log_config)
{
@@ -728,7 +827,7 @@ log_start_from_param(const struct log_config *src_log_config)
*/
enum logReturns
log_start(const char *iniFile, const char *applicationName,
- bool_t dump_on_start)
+ unsigned int flags)
{
enum logReturns ret = LOG_GENERAL_ERROR;
struct log_config *config;
@@ -737,14 +836,24 @@ log_start(const char *iniFile, const char *applicationName,
if (config != NULL)
{
- config->dump_on_start = dump_on_start;
- ret = log_start_from_param(config);
- log_config_free(config);
-
- if (ret != LOG_STARTUP_OK)
+ config->dump_on_start = (flags & LOG_START_DUMP_CONFIG) ? 1 : 0;
+ if (flags & LOG_START_RESTART)
{
- g_writeln("Could not start log");
+ ret = log_restart_from_param(config);
+ if (ret != LOG_STARTUP_OK)
+ {
+ g_writeln("Could not restart log");
+ }
}
+ else
+ {
+ ret = log_start_from_param(config);
+ if (ret != LOG_STARTUP_OK)
+ {
+ g_writeln("Could not start log");
+ }
+ }
+ log_config_free(config);
}
else
{
@@ -794,7 +903,7 @@ log_hexdump_with_location(const char *function_name,
{
char *dump_buffer;
enum logReturns rv = LOG_STARTUP_OK;
- enum logLevels override_log_level;
+ enum logLevels override_log_level = LOG_LEVEL_NEVER;
bool_t override_destination_level = 0;
override_destination_level = internal_log_location_overrides_level(
diff --git a/common/log.h b/common/log.h
index 0194a530..17615560 100644
--- a/common/log.h
+++ b/common/log.h
@@ -162,6 +162,23 @@ enum logReturns
#endif
+/* Flags values for log_start() */
+
+/**
+ * Dump the log config on startup
+ */
+#define LOG_START_DUMP_CONFIG (1<<0)
+
+/**
+ * Restart the logging system.
+ *
+ * On a restart, existing files are not closed. This is because the
+ * files may be shared by sub-processes, and the result will not be what the
+ * user expects
+ */
+#define LOG_START_RESTART (1<<1)
+
+#ifdef LOG_PER_LOGGER_LEVEL
enum log_logger_type
{
LOG_TYPE_FILE = 0,
@@ -174,22 +191,27 @@ struct log_logger_level
enum log_logger_type logger_type;
char logger_name[LOGGER_NAME_SIZE + 1];
};
+#endif
struct log_config
{
- const char *program_name;
- char *log_file;
+ const char *program_name; /* Pointer to static storage */
+ char *log_file; /* Dynamically allocated */
int fd;
enum logLevels log_level;
int enable_console;
enum logLevels console_level;
int enable_syslog;
enum logLevels syslog_level;
+#ifdef LOG_PER_LOGGER_LEVEL
struct list *per_logger_level;
+#endif
int dump_on_start;
int enable_pid;
+#ifdef LOG_ENABLE_THREAD
pthread_mutex_t log_lock;
pthread_mutexattr_t log_lock_attr;
+#endif
};
/* internal functions, only used in log.c if this ifdef is defined.*/
@@ -294,13 +316,12 @@ internal_log_location_overrides_level(const char *function_name,
* @param iniFile
* @param applicationName the name that is used in the log for the running
* application
- * @param dump_on_start Whether to dump the config on stdout before
- * logging is started
+ * @param flags Flags to affect the operation of the call
* @return LOG_STARTUP_OK on success
*/
enum logReturns
log_start(const char *iniFile, const char *applicationName,
- bool_t dump_on_start);
+ unsigned int flags);
/**
* An alternative log_start where the caller gives the params directly.
diff --git a/common/os_calls.c b/common/os_calls.c
index dd2e964d..e7dea20e 100644
--- a/common/os_calls.c
+++ b/common/os_calls.c
@@ -2973,7 +2973,7 @@ g_waitchild(void)
/*****************************************************************************/
/* does not work in win32
- returns pid of process that exits or zero if signal occurred */
+ returns pid of process that exits or <= 0 if no process was found */
int
g_waitpid(int pid)
{
@@ -2989,14 +2989,6 @@ g_waitpid(int pid)
else
{
rv = waitpid(pid, 0, 0);
-
- if (rv == -1)
- {
- if (errno == EINTR) /* signal occurred */
- {
- rv = 0;
- }
- }
}
return rv;
diff --git a/common/parse.h b/common/parse.h
index b27bb0c9..a3721ef8 100644
--- a/common/parse.h
+++ b/common/parse.h
@@ -90,9 +90,6 @@ parser_stream_overflow_check(const struct stream *s, int n, int is_out,
#endif
/******************************************************************************/
-#define s_check(s) s_check_rem(s, 0)
-
-/******************************************************************************/
#define s_check_rem(s, n) ((s)->p + (n) <= (s)->end)
/******************************************************************************/
diff --git a/common/ssl_calls.c b/common/ssl_calls.c
index b305815f..168add76 100644
--- a/common/ssl_calls.c
+++ b/common/ssl_calls.c
@@ -44,6 +44,27 @@
#define SSL_WANT_READ_WRITE_TIMEOUT 100
+/*
+ * Globals used by openssl 3 and later */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static EVP_MD *g_md_md5; /* MD5 message digest */
+static EVP_MD *g_md_sha1; /* SHA1 message digest */
+static EVP_CIPHER *g_cipher_des_ede3_cbc; /* DES3 CBC cipher */
+static EVP_MAC *g_mac_hmac; /* HMAC MAC */
+#endif
+
+/* definition of ssl_tls */
+struct ssl_tls
+{
+ SSL *ssl; /* SSL * */
+ SSL_CTX *ctx; /* SSL_CTX * */
+ char *cert;
+ char *key;
+ struct trans *trans;
+ tintptr rwo; /* wait obj */
+ int error_logged; /* Error has already been logged */
+};
+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static inline HMAC_CTX *
HMAC_CTX_new(void)
@@ -106,12 +127,41 @@ DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+
+/*****************************************************************************/
+static void
+dump_error_stack(const char *prefix)
+{
+ /* Dump the error stack from the SSL library */
+ unsigned long code;
+ char buff[256];
+ while ((code = ERR_get_error()) != 0L)
+ {
+ ERR_error_string_n(code, buff, sizeof(buff));
+ LOG(LOG_LEVEL_ERROR, "%s: %s", prefix, buff);
+ }
+}
+
+/*****************************************************************************/
+/* As above, but used for TLS connection errors where only the first
+ error is logged */
+static void
+dump_ssl_error_stack(struct ssl_tls *self)
+{
+ if (!self->error_logged)
+ {
+ dump_error_stack("SSL");
+ self->error_logged = 1;
+ }
+}
+
/*****************************************************************************/
int
ssl_init(void)
{
SSL_load_error_strings();
SSL_library_init();
+
return 0;
}
@@ -119,16 +169,44 @@ ssl_init(void)
int
ssl_finish(void)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ /* De-allocate any allocated globals
+ * For OpenSSL 3, these can all safely be passed a NULL pointer */
+ EVP_MD_free(g_md_md5);
+ EVP_MD_free(g_md_sha1);
+ EVP_CIPHER_free(g_cipher_des_ede3_cbc);
+ EVP_MAC_free(g_mac_hmac);
+#endif
return 0;
}
-/* rc4 stuff */
+/* rc4 stuff
+ *
+ * For OpenSSL 3.0, the rc4 encryption algorithm is only provided by the
+ * legacy provider (see crypto(7)). Since RC4 is so simple, we can implement
+ * it directly rather than having to load the legacy provider. This will
+ * avoids problems if running on a system where openssl has been built
+ * without the legacy provider */
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+struct rc4_data
+{
+ /* See https://en.wikipedia.org/wiki/RC4 */
+ unsigned char S[256];
+ int i;
+ int j;
+};
+#endif
/*****************************************************************************/
void *
ssl_rc4_info_create(void)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
return g_malloc(sizeof(RC4_KEY), 1);
+#else
+ return g_malloc(sizeof(struct rc4_data), 1);
+#endif
}
/*****************************************************************************/
@@ -140,16 +218,77 @@ ssl_rc4_info_delete(void *rc4_info)
/*****************************************************************************/
void
-ssl_rc4_set_key(void *rc4_info, char *key, int len)
+ssl_rc4_set_key(void *rc4_info, const char *key, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
RC4_set_key((RC4_KEY *)rc4_info, len, (tui8 *)key);
+#else
+ unsigned char *S = ((struct rc4_data *)rc4_info)->S;
+ int i;
+ int j = 0;
+ unsigned char t;
+ for (i = 0 ; i < 256; ++i)
+ {
+ S[i] = i;
+ }
+ for (i = 0 ; i < 256; ++i)
+ {
+ j = (j + S[i] + key[i % len]) & 0xff;
+ t = S[i];
+ S[i] = S[j];
+ S[j] = t;
+ }
+ ((struct rc4_data *)rc4_info)->i = 0;
+ ((struct rc4_data *)rc4_info)->j = 0;
+#endif
}
/*****************************************************************************/
void
ssl_rc4_crypt(void *rc4_info, char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
RC4((RC4_KEY *)rc4_info, len, (tui8 *)data, (tui8 *)data);
+#else
+ unsigned char *S = ((struct rc4_data *)rc4_info)->S;
+ int i = ((struct rc4_data *)rc4_info)->i;
+ int j = ((struct rc4_data *)rc4_info)->j;
+ unsigned char *p = (unsigned char *)data;
+ unsigned char t;
+ unsigned char k;
+
+ /*
+ * Do some loop-unrolling for performance. Here are the steps
+ * for each byte */
+#define RC4_ROUND \
+ i = (i + 1) & 0xff; \
+ j = (j + S[i]) & 0xff; \
+ t = S[i]; \
+ S[i] = S[j]; \
+ S[j] = t; \
+ k = S[(S[i] + S[j]) & 0xff]; \
+ *p++ ^= k
+
+ while (len >= 8)
+ {
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ RC4_ROUND;
+ len -= 8;
+ }
+ while (len-- > 0)
+ {
+ RC4_ROUND;
+ }
+
+ ((struct rc4_data *)rc4_info)->i = i;
+ ((struct rc4_data *)rc4_info)->j = j;
+#endif
}
/* sha1 stuff */
@@ -158,35 +297,78 @@ ssl_rc4_crypt(void *rc4_info, char *data, int len)
void *
ssl_sha1_info_create(void)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
return g_malloc(sizeof(SHA_CTX), 1);
+#else
+ /*
+ * If we can't get the digest loaded, there's a problem with the
+ * library providers, so there's no point in us returning anything useful.
+ * If we do load the digest, it's used later */
+ if (g_md_sha1 == NULL)
+ {
+ if ((g_md_sha1 = EVP_MD_fetch(NULL, "sha1", NULL)) == NULL)
+ {
+ dump_error_stack("sha1");
+ return NULL;
+ }
+ }
+
+ return (void *)EVP_MD_CTX_new();
+#endif
}
/*****************************************************************************/
void
ssl_sha1_info_delete(void *sha1_info)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
g_free(sha1_info);
+#else
+ EVP_MD_CTX_free((EVP_MD_CTX *)sha1_info);
+#endif
}
/*****************************************************************************/
void
ssl_sha1_clear(void *sha1_info)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
SHA1_Init((SHA_CTX *)sha1_info);
+#else
+ if (sha1_info != NULL)
+ {
+ EVP_DigestInit_ex(sha1_info, g_md_sha1, NULL);
+ }
+#endif
}
/*****************************************************************************/
void
ssl_sha1_transform(void *sha1_info, const char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
SHA1_Update((SHA_CTX *)sha1_info, data, len);
+#else
+ if (sha1_info != NULL)
+ {
+ EVP_DigestUpdate((EVP_MD_CTX *)sha1_info, data, len);
+ }
+#endif
}
/*****************************************************************************/
void
ssl_sha1_complete(void *sha1_info, char *data)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
SHA1_Final((tui8 *)data, (SHA_CTX *)sha1_info);
+#else
+ if (sha1_info != NULL)
+ {
+ EVP_DigestFinal_ex((EVP_MD_CTX *)sha1_info, (unsigned char *)data,
+ NULL);
+ }
+#endif
}
/* md5 stuff */
@@ -195,35 +377,77 @@ ssl_sha1_complete(void *sha1_info, char *data)
void *
ssl_md5_info_create(void)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
return g_malloc(sizeof(MD5_CTX), 1);
+#else
+ /*
+ * If we can't get the digest loaded, there's a problem with the
+ * library providers, so there's no point in us returning anything useful.
+ * If we do load the digest, it's used later */
+ if (g_md_md5 == NULL)
+ {
+ if ((g_md_md5 = EVP_MD_fetch(NULL, "md5", NULL)) == NULL)
+ {
+ dump_error_stack("md5");
+ return NULL;
+ }
+ }
+
+ return (void *)EVP_MD_CTX_new();
+#endif
}
/*****************************************************************************/
void
ssl_md5_info_delete(void *md5_info)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
g_free(md5_info);
+#else
+ EVP_MD_CTX_free((EVP_MD_CTX *)md5_info);
+#endif
}
/*****************************************************************************/
void
ssl_md5_clear(void *md5_info)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
MD5_Init((MD5_CTX *)md5_info);
+#else
+ if (md5_info != NULL)
+ {
+ EVP_DigestInit_ex(md5_info, g_md_md5, NULL);
+ }
+#endif
}
/*****************************************************************************/
void
-ssl_md5_transform(void *md5_info, char *data, int len)
+ssl_md5_transform(void *md5_info, const char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
MD5_Update((MD5_CTX *)md5_info, data, len);
+#else
+ if (md5_info != NULL)
+ {
+ EVP_DigestUpdate((EVP_MD_CTX *)md5_info, data, len);
+ }
+#endif
}
/*****************************************************************************/
void
ssl_md5_complete(void *md5_info, char *data)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
MD5_Final((tui8 *)data, (MD5_CTX *)md5_info);
+#else
+ if (md5_info != NULL)
+ {
+ EVP_DigestFinal_ex((EVP_MD_CTX *)md5_info, (unsigned char *)data, NULL);
+ }
+#endif
}
/* FIPS stuff */
@@ -236,10 +460,30 @@ ssl_des3_encrypt_info_create(const char *key, const char *ivec)
const tui8 *lkey;
const tui8 *livec;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ /*
+ * For these versions of OpenSSL, there are no long-term guarantees the
+ * DES3 cipher will be available. We'll try to load it here so we
+ * can log any errors */
+ if (g_cipher_des_ede3_cbc == NULL)
+ {
+ g_cipher_des_ede3_cbc = EVP_CIPHER_fetch(NULL, "des-ede3-cbc", NULL);
+ if (g_cipher_des_ede3_cbc == NULL)
+ {
+ dump_error_stack("DES-EDE3-CBC");
+ return NULL;
+ }
+ }
+#endif
+
des3_ctx = EVP_CIPHER_CTX_new();
lkey = (const tui8 *) key;
livec = (const tui8 *) ivec;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
EVP_EncryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
+#else
+ EVP_EncryptInit_ex(des3_ctx, g_cipher_des_ede3_cbc, NULL, lkey, livec);
+#endif
EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
return des3_ctx;
}
@@ -252,10 +496,30 @@ ssl_des3_decrypt_info_create(const char *key, const char *ivec)
const tui8 *lkey;
const tui8 *livec;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ /*
+ * For these versions of OpenSSL, there are no long-term guarantees the
+ * DES3 cipher will be available. We'll try to load it here so we
+ * can log any errors */
+ if (g_cipher_des_ede3_cbc == NULL)
+ {
+ g_cipher_des_ede3_cbc = EVP_CIPHER_fetch(NULL, "des-ede3-cbc", NULL);
+ if (g_cipher_des_ede3_cbc == NULL)
+ {
+ dump_error_stack("DES-EDE3-CBC");
+ return NULL;
+ }
+ }
+#endif
+
des3_ctx = EVP_CIPHER_CTX_new();
lkey = (const tui8 *) key;
livec = (const tui8 *) ivec;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
EVP_DecryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
+#else
+ EVP_DecryptInit_ex(des3_ctx, g_cipher_des_ede3_cbc, NULL, lkey, livec);
+#endif
EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
return des3_ctx;
}
@@ -283,10 +547,13 @@ ssl_des3_encrypt(void *des3, int length, const char *in_data, char *out_data)
tui8 *lout_data;
des3_ctx = (EVP_CIPHER_CTX *) des3;
- lin_data = (const tui8 *) in_data;
- lout_data = (tui8 *) out_data;
- len = 0;
- EVP_EncryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+ if (des3_ctx != NULL)
+ {
+ lin_data = (const tui8 *) in_data;
+ lout_data = (tui8 *) out_data;
+ len = 0;
+ EVP_EncryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+ }
return 0;
}
@@ -300,10 +567,13 @@ ssl_des3_decrypt(void *des3, int length, const char *in_data, char *out_data)
tui8 *lout_data;
des3_ctx = (EVP_CIPHER_CTX *) des3;
- lin_data = (const tui8 *) in_data;
- lout_data = (tui8 *) out_data;
- len = 0;
- EVP_DecryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+ if (des3_ctx != NULL)
+ {
+ lin_data = (const tui8 *) in_data;
+ lout_data = (tui8 *) out_data;
+ len = 0;
+ EVP_DecryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
+ }
return 0;
}
@@ -311,16 +581,28 @@ ssl_des3_decrypt(void *des3, int length, const char *in_data, char *out_data)
void *
ssl_hmac_info_create(void)
{
- HMAC_CTX *hmac_ctx;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ return (HMAC_CTX *)HMAC_CTX_new();
+#else
+ /* Need a MAC algorithm loaded */
+ if (g_mac_hmac == NULL)
+ {
+ if ((g_mac_hmac = EVP_MAC_fetch(NULL, "hmac", NULL)) == NULL)
+ {
+ dump_error_stack("hmac");
+ return NULL;
+ }
+ }
- hmac_ctx = HMAC_CTX_new();
- return hmac_ctx;
+ return (void *)EVP_MAC_CTX_new(g_mac_hmac);
+#endif
}
/*****************************************************************************/
void
ssl_hmac_info_delete(void *hmac)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX *hmac_ctx;
hmac_ctx = (HMAC_CTX *) hmac;
@@ -328,34 +610,61 @@ ssl_hmac_info_delete(void *hmac)
{
HMAC_CTX_free(hmac_ctx);
}
+#else
+ EVP_MAC_CTX_free((EVP_MAC_CTX *)hmac);
+#endif
}
/*****************************************************************************/
void
ssl_hmac_sha1_init(void *hmac, const char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX *hmac_ctx;
hmac_ctx = (HMAC_CTX *) hmac;
HMAC_Init_ex(hmac_ctx, data, len, EVP_sha1(), NULL);
+#else
+ if (hmac != NULL)
+ {
+ char digest[] = "sha1";
+ OSSL_PARAM params[3];
+ size_t n = 0;
+ params[n++] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
+ params[n++] = OSSL_PARAM_construct_end();
+ if (EVP_MAC_init((EVP_MAC_CTX *)hmac, (unsigned char *)data,
+ len, params) == 0)
+ {
+ dump_error_stack("hmac-sha1");
+ }
+ }
+#endif
}
/*****************************************************************************/
void
ssl_hmac_transform(void *hmac, const char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX *hmac_ctx;
const tui8 *ldata;
hmac_ctx = (HMAC_CTX *) hmac;
ldata = (const tui8 *) data;
HMAC_Update(hmac_ctx, ldata, len);
+#else
+ if (hmac != NULL)
+ {
+ EVP_MAC_update((EVP_MAC_CTX *)hmac, (unsigned char *)data, len);
+ }
+#endif
}
/*****************************************************************************/
void
ssl_hmac_complete(void *hmac, char *data, int len)
{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX *hmac_ctx;
tui8 *ldata;
tui32 llen;
@@ -364,6 +673,12 @@ ssl_hmac_complete(void *hmac, char *data, int len)
ldata = (tui8 *) data;
llen = len;
HMAC_Final(hmac_ctx, ldata, &llen);
+#else
+ if (hmac != NULL)
+ {
+ EVP_MAC_final((EVP_MAC_CTX *)hmac, (unsigned char *)data, NULL, len);
+ }
+#endif
}
/*****************************************************************************/
@@ -455,7 +770,6 @@ ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
char *mod, int mod_len, char *pri, int pri_len)
{
BIGNUM *my_e;
- RSA *my_key;
char *lexp;
char *lmod;
char *lpri;
@@ -477,12 +791,44 @@ ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
ssl_reverse_it(lexp, exp_len);
my_e = BN_new();
BN_bin2bn((tui8 *)lexp, exp_len, my_e);
- my_key = RSA_new();
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ const BIGNUM *n = NULL;
+ const BIGNUM *d = NULL;
+ RSA *my_key = RSA_new();
error = RSA_generate_key_ex(my_key, key_size_in_bits, my_e, 0) == 0;
- const BIGNUM *n;
- const BIGNUM *d;
+ /* After this call, n and d point directly into my_key, and are valid
+ * until my_key is free'd */
RSA_get0_key(my_key, &n, NULL, &d);
+#else
+ BIGNUM *n = NULL;
+ BIGNUM *d = NULL;
+ OSSL_PARAM params[] =
+ {
+ OSSL_PARAM_construct_int("bits", &key_size_in_bits),
+ OSSL_PARAM_construct_end()
+ };
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+ EVP_PKEY *pkey = NULL;
+
+ if (pctx != NULL &&
+ EVP_PKEY_keygen_init(pctx) > 0 &&
+ EVP_PKEY_CTX_set_params(pctx, params) > 0 &&
+ EVP_PKEY_generate(pctx, &pkey) > 0 &&
+ EVP_PKEY_get_bn_param(pkey, "n", &n) > 0 &&
+ EVP_PKEY_get_bn_param(pkey, "d", &d) > 0)
+ {
+ error = 0;
+ }
+ else
+ {
+ error = 1;
+ }
+
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(pkey);
+#endif
if (error == 0)
{
@@ -517,7 +863,12 @@ ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
}
BN_free(my_e);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
RSA_free(my_key);
+#else
+ BN_free(n);
+ BN_clear_free(d);
+#endif
g_free(lexp);
g_free(lmod);
g_free(lpri);
@@ -529,7 +880,11 @@ ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
see also
* https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
* https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_tmp_dh_callback(3)
+ *
+ * We dont do this for OpenSSL 3 - we use SSL_CTX_set_dh_auto() instead, as this
+ * can cater for different key sizes on the certificate
*/
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
static DH *ssl_get_dh2236()
{
static unsigned char dh2236_p[] =
@@ -591,6 +946,7 @@ static DH *ssl_get_dh2236()
return dh;
}
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
/*****************************************************************************/
struct ssl_tls *
@@ -613,25 +969,6 @@ ssl_tls_create(struct trans *trans, const char *key, const char *cert)
return self;
}
-
-/*****************************************************************************/
-static void
-dump_ssl_error_stack(struct ssl_tls *self)
-{
- if (!self->error_logged)
- {
- /* Dump the error stack from the SSL library */
- unsigned long code;
- char buff[256];
- while ((code = ERR_get_error()) != 0L)
- {
- ERR_error_string_n(code, buff, sizeof(buff));
- LOG(LOG_LEVEL_ERROR, "SSL: %s", buff);
- }
- self->error_logged = 1;
- }
-}
-
/*****************************************************************************/
static int
ssl_tls_log_error(struct ssl_tls *self, const char *func, int value)
@@ -752,6 +1089,7 @@ ssl_tls_accept(struct ssl_tls *self, long ssl_protocols,
SSL_CTX_set_options(self->ctx, options);
/* set DH parameters */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
DH *dh = ssl_get_dh2236();
if (dh == NULL)
{
@@ -766,7 +1104,14 @@ ssl_tls_accept(struct ssl_tls *self, long ssl_protocols,
return 1;
}
DH_free(dh); // ok to free, copied into ctx by SSL_CTX_set_tmp_dh()
-
+#else
+ if (!SSL_CTX_set_dh_auto(self->ctx, 1))
+ {
+ LOG(LOG_LEVEL_ERROR, "TLS DHE auto failed to be enabled");
+ dump_ssl_error_stack(self);
+ return 1;
+ }
+#endif
#if defined(SSL_CTX_set_ecdh_auto)
if (!SSL_CTX_set_ecdh_auto(self->ctx, 1))
{
@@ -1058,16 +1403,23 @@ ssl_tls_can_recv(struct ssl_tls *tls, int sck, int millis)
/*****************************************************************************/
const char *
-ssl_get_version(const struct ssl_st *ssl)
+ssl_get_version(const struct ssl_tls *ssl)
{
- return SSL_get_version(ssl);
+ return SSL_get_version(ssl->ssl);
}
/*****************************************************************************/
const char *
-ssl_get_cipher_name(const struct ssl_st *ssl)
+ssl_get_cipher_name(const struct ssl_tls *ssl)
+{
+ return SSL_get_cipher_name(ssl->ssl);
+}
+
+/*****************************************************************************/
+tintptr
+ssl_get_rwo(const struct ssl_tls *ssl)
{
- return SSL_get_cipher_name(ssl);
+ return ssl->rwo;
}
/*****************************************************************************/
diff --git a/common/ssl_calls.h b/common/ssl_calls.h
index 121cb390..01b67406 100644
--- a/common/ssl_calls.h
+++ b/common/ssl_calls.h
@@ -22,6 +22,10 @@
#include "arch.h"
+/* Incomplete types */
+struct ssl_tls;
+struct trans;
+
int
ssl_init(void);
int
@@ -31,7 +35,7 @@ ssl_rc4_info_create(void);
void
ssl_rc4_info_delete(void *rc4_info);
void
-ssl_rc4_set_key(void *rc4_info, char *key, int len);
+ssl_rc4_set_key(void *rc4_info, const char *key, int len);
void
ssl_rc4_crypt(void *rc4_info, char *data, int len);
void *
@@ -51,7 +55,7 @@ ssl_md5_info_delete(void *md5_info);
void
ssl_md5_clear(void *md5_info);
void
-ssl_md5_transform(void *md5_info, char *data, int len);
+ssl_md5_transform(void *md5_info, const char *data, int len);
void
ssl_md5_complete(void *md5_info, char *data);
void *
@@ -81,18 +85,6 @@ int
ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
char *mod, int mod_len, char *pri, int pri_len);
-/* ssl_tls */
-struct ssl_tls
-{
- struct ssl_st *ssl; /* SSL * */
- struct ssl_ctx_st *ctx; /* SSL_CTX * */
- char *cert;
- char *key;
- struct trans *trans;
- tintptr rwo; /* wait obj */
- int error_logged; /* Error has already been logged */
-};
-
/* xrdp_tls.c */
struct ssl_tls *
ssl_tls_create(struct trans *trans, const char *key, const char *cert);
@@ -110,12 +102,14 @@ ssl_tls_write(struct ssl_tls *tls, const char *data, int length);
int
ssl_tls_can_recv(struct ssl_tls *tls, int sck, int millis);
const char *
-ssl_get_version(const struct ssl_st *ssl);
+ssl_get_version(const struct ssl_tls *ssl);
const char *
-ssl_get_cipher_name(const struct ssl_st *ssl);
+ssl_get_cipher_name(const struct ssl_tls *ssl);
int
ssl_get_protocols_from_string(const char *str, long *ssl_protocols);
const char *
get_openssl_version();
+tintptr
+ssl_get_rwo(const struct ssl_tls *ssl);
#endif
diff --git a/common/string_calls.c b/common/string_calls.c
index 9950fd09..18f54512 100644
--- a/common/string_calls.c
+++ b/common/string_calls.c
@@ -986,3 +986,72 @@ g_bitmask_to_str(int bitmask, const struct bitmask_string bitdefs[],
return rlen;
}
+
+int
+g_str_to_bitmask(const char *str, const struct bitmask_string bitdefs[],
+ const char *delim, char *unrecognised, int unrecognised_len)
+{
+ char *properties = NULL;
+ char *p = NULL;
+ int mask = 0;
+
+ if (unrecognised_len < 1)
+ {
+ /* No space left to tell unrecognised tokens */
+ return 0;
+ }
+ if (!unrecognised)
+ {
+ return 0;
+ }
+ /* ensure not to return with uninitialized buffer */
+ unrecognised[0] = '\0';
+ if (!str || !bitdefs || !delim)
+ {
+ return 0;
+ }
+ properties = g_strdup(str);
+ if (!properties)
+ {
+ return 0;
+ }
+ p = strtok(properties, delim);
+ while (p != NULL)
+ {
+ g_strtrim(p, 3);
+ const struct bitmask_string *b;
+ int found = 0;
+ for (b = &bitdefs[0] ; b->str != NULL; ++b)
+ {
+ if (0 == g_strcasecmp(p, b->str))
+ {
+ mask |= b->mask;
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0)
+ {
+ int length = g_strlen(unrecognised);
+ if (length > 0)
+ {
+ /* adding ",property" */
+ if (length + g_strlen(p) + 1 < unrecognised_len)
+ {
+ unrecognised[length] = delim[0];
+ length += 1;
+ g_strcpy(unrecognised + length, p);
+ }
+ }
+ else if (g_strlen(p) < unrecognised_len)
+ {
+ g_strcpy(unrecognised, p);
+ }
+ }
+ p = strtok(NULL, delim);
+ }
+
+ g_free(properties);
+ return mask;
+}
+
diff --git a/common/string_calls.h b/common/string_calls.h
index 990a98e6..87888c18 100644
--- a/common/string_calls.h
+++ b/common/string_calls.h
@@ -174,6 +174,20 @@ int
g_bitmask_to_str(int bitmask, const struct bitmask_string[],
char delim, char *buff, int bufflen);
+/***
+ * Converts a string containing a series of tokens to a bitmask.
+ * @param str Input string
+ * @param bitmask_string Array mapping tokens to bitmask values
+ * @param delim Delimiter for tokens in str
+ * @param[out] unrecognised Buffer for any unrecognised tokens
+ * @param unrecognised_len Length of unrecognised including '\0';
+ * @return bitmask value for recognised tokens
+ */
+int
+g_str_to_bitmask(const char *str, const struct bitmask_string[],
+ const char *delim, char *unrecognised,
+ int unrecognised_len);
+
int g_strlen(const char *text);
char *g_strchr(const char *text, int c);
char *g_strrchr(const char *text, int c);
diff --git a/common/trans.c b/common/trans.c
index 3afae55d..55d2a638 100644
--- a/common/trans.c
+++ b/common/trans.c
@@ -179,13 +179,9 @@ trans_get_wait_objs(struct trans *self, tbus *objs, int *count)
objs[*count] = self->sck;
(*count)++;
- if (self->tls != 0)
+ if (self->tls != NULL && (objs[*count] = ssl_get_rwo(self->tls)) != 0)
{
- if (self->tls->rwo != 0)
- {
- objs[*count] = self->tls->rwo;
- (*count)++;
- }
+ (*count)++;
}
return 0;
@@ -995,8 +991,8 @@ trans_set_tls_mode(struct trans *self, const char *key, const char *cert,
self->trans_send = trans_tls_send;
self->trans_can_recv = trans_tls_can_recv;
- self->ssl_protocol = ssl_get_version(self->tls->ssl);
- self->cipher_name = ssl_get_cipher_name(self->tls->ssl);
+ self->ssl_protocol = ssl_get_version(self->tls);
+ self->cipher_name = ssl_get_cipher_name(self->tls);
return 0;
}
diff --git a/configure.ac b/configure.ac
index bd0fc77c..015f81a8 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.18.1], [xrdp-devel@googlegroups.com])
+AC_INIT([xrdp], [0.9.19], [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])
@@ -224,7 +224,7 @@ case "$with_imlib2" in
use_imlib2=no
;;
yes)
- PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10],
+ PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.5],
[use_imlib2=yes],
[AC_MSG_ERROR([please install libimlib2-dev or imlib2-devel])])
;;
diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in
index 0f58c0ce..7291038f 100644
--- a/docs/man/sesman.ini.5.in
+++ b/docs/man/sesman.ini.5.in
@@ -221,10 +221,62 @@ login for all users is enabled.
have session management rights.
.TP
-\fBRestrictOutboundClipboard\fR=\fI[true|false]\fR
-If set to \fB1\fR, \fBtrue\fR or \fByes\fR, will restrict the clipboard
+\fBRestrictOutboundClipboard\fR=\fI[all|none|text|file|image]\fR
+If set to \fBall\fR, will restrict the clipboard
outbound from the server, to prevent data copied inside the xrdp session
-to be be pasted in the client host. Default value is \fBfalse\fR.
+to be pasted in the client. Default value is \fBnone\fR.
+In addition, you can control text/file/image transfer restrictions
+respectively. It also accepts comma separated list such as text,file,image.
+.br
+
+.br
+\fBnone\fR - No restriction about copying inbound clipboard data.
+.br
+\fBall\fR - Restrict to copy inbound clipboard data.
+.br
+\fBtext\fR - Restrict to copy only inbound text clipboard data.
+.br
+\fBfile\fR - Restrict to copy only inbound file clipboard data.
+.br
+\fBimage\fR - Restrict to copy only inbound image clipboard data.
+.br
+
+To keep compatibility, the following aliases are also available.
+.br
+\fBtrue\fR - an alias of \fBall\fR.
+.br
+\fBfalse\fR - an alias of \fBnone\fR.
+.br
+\fByes\fR - an alias of \fBall\fR.
+
+.TP
+\fBRestrictInboundClipboard\fR=\fI[none|all|text|file|image]\fR
+If set to \fBall\fR, will restrict the clipboard
+inbound from the client, to prevent data copied inside the client
+to be pasted in the xrdp session. Default value is \fBnone\fR.
+In addition, you can control text/file/image transfer restrictions
+respectively. It also accepts comma separated list such as text,file,image.
+.br
+
+.br
+\fBnone\fR - No restriction about copying inbound clipboard data.
+.br
+\fBall\fR - Restrict to copy inbound clipboard data.
+.br
+\fBtext\fR - Restrict to copy only inbound text clipboard data.
+.br
+\fBfile\fR - Restrict to copy only inbound file clipboard data.
+.br
+\fBimage\fR - Restrict to copy only inbound image clipboard data.
+.br
+
+To keep compatibility, the following aliases are also available.
+.br
+\fBtrue\fR - an alias of \fBall\fR.
+.br
+\fBfalse\fR - an alias of \fBnone\fR.
+.br
+\fByes\fR - an alias of \fBall\fR.
.TP
\fBAlwaysGroupCheck\fR=\fI[true|false]\fR
diff --git a/libxrdp/Makefile.am b/libxrdp/Makefile.am
index c843a531..49df6c65 100644
--- a/libxrdp/Makefile.am
+++ b/libxrdp/Makefile.am
@@ -45,6 +45,7 @@ libxrdp_la_SOURCES = \
xrdp_bitmap_compress.c \
xrdp_caps.c \
xrdp_channel.c \
+ xrdp_channel.h \
xrdp_fastpath.c \
xrdp_iso.c \
xrdp_jpeg_compress.c \
diff --git a/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c
index 16a8668e..f43804d7 100644
--- a/libxrdp/xrdp_channel.c
+++ b/libxrdp/xrdp_channel.c
@@ -24,6 +24,7 @@
#include "libxrdp.h"
#include "string_calls.h"
+#include "xrdp_channel.h"
#define CMD_DVC_OPEN_CHANNEL 0x10
#define CMD_DVC_DATA_FIRST 0x20
@@ -31,19 +32,6 @@
#define CMD_DVC_CLOSE_CHANNEL 0x40
#define CMD_DVC_CAPABILITY 0x50
-#define XRDP_DRDYNVC_STATUS_CLOSED 0
-#define XRDP_DRDYNVC_STATUS_OPEN_SENT 1
-#define XRDP_DRDYNVC_STATUS_OPEN 2
-#define XRDP_DRDYNVC_STATUS_CLOSE_SENT 3
-
-#define XRDP_DRDYNVC_STATUS_TO_STR(status) \
- ((status) == XRDP_DRDYNVC_STATUS_CLOSED ? "CLOSED" : \
- (status) == XRDP_DRDYNVC_STATUS_OPEN_SENT ? "OPEN_SENT" : \
- (status) == XRDP_DRDYNVC_STATUS_OPEN ? "OPEN" : \
- (status) == XRDP_DRDYNVC_STATUS_CLOSE_SENT ? "CLOSE_SENT" : \
- "unknown" \
- )
-
#define XRDP_DRDYNVC_CHANNEL_ID_TO_NAME(self, chan_id) \
(xrdp_channel_get_item((self), (chan_id)) != NULL \
? xrdp_channel_get_item((self), (chan_id))->name \
@@ -935,7 +923,7 @@ xrdp_channel_drdynvc_close(struct xrdp_channel *self, int chan_id)
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPEDYC] DYNVC_CLOSE "
"cbId %d, Sp 0, Cmd 0x%2.2x, ChannelId %d",
- cbChId, CMD_DVC_OPEN_CHANNEL, ChId);
+ cbChId, CMD_DVC_CLOSE_CHANNEL, ChId);
if (xrdp_channel_send(self, s, static_channel_id, total_data_len,
static_flags) != 0)
{
diff --git a/libxrdp/xrdp_channel.h b/libxrdp/xrdp_channel.h
new file mode 100644
index 00000000..9f795911
--- /dev/null
+++ b/libxrdp/xrdp_channel.h
@@ -0,0 +1,42 @@
+/**
+ * xrdp: A Remote Desktop Protocol server.
+ *
+ * MS-RDPEDYC : Definitions related to documentation in [MS-RDPEDYC]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * References to MS-RDPEDYC are currently correct for v20210406 of that
+ * document
+ */
+
+#if !defined(XRDP_CHANNEL_H)
+#define XRDP_CHANNEL_H
+
+/*
+ These are not directly defined in MS-RDPEDYC, but
+ they are derived statuses needed to implement it.
+*/
+#define XRDP_DRDYNVC_STATUS_CLOSED 0
+#define XRDP_DRDYNVC_STATUS_OPEN_SENT 1
+#define XRDP_DRDYNVC_STATUS_OPEN 2
+#define XRDP_DRDYNVC_STATUS_CLOSE_SENT 3
+
+#define XRDP_DRDYNVC_STATUS_TO_STR(status) \
+ ((status) == XRDP_DRDYNVC_STATUS_CLOSED ? "CLOSED" : \
+ (status) == XRDP_DRDYNVC_STATUS_OPEN_SENT ? "OPEN_SENT" : \
+ (status) == XRDP_DRDYNVC_STATUS_OPEN ? "OPEN" : \
+ (status) == XRDP_DRDYNVC_STATUS_CLOSE_SENT ? "CLOSE_SENT" : \
+ "unknown" \
+ )
+
+#endif /* XRDP_CHANNEL_H */
diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c
index f2593694..dde7a3ea 100644
--- a/libxrdp/xrdp_iso.c
+++ b/libxrdp/xrdp_iso.c
@@ -428,7 +428,8 @@ xrdp_iso_send_cc(struct xrdp_iso *self)
out_uint16_le(s, 8); /* length (must be 8) */
out_uint32_le(s, self->selectedProtocol); /* selectedProtocol */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding structure [MS-RDPBCGR] RDP_NEG_RSP "
- "flags 0, length 8, selectedProtocol 0x%8.8x",
+ "flags 0x%02x, length 8, selectedProtocol 0x%8.8x",
+ EXTENDED_CLIENT_DATA_SUPPORTED,
self->selectedProtocol);
}
}
diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c
index c2b23289..d08f068a 100644
--- a/libxrdp/xrdp_rdp.c
+++ b/libxrdp/xrdp_rdp.c
@@ -942,11 +942,21 @@ xrdp_rdp_incoming(struct xrdp_rdp *self)
/* log non-TLS connections */
else
{
+ int crypt_level = self->sec_layer->crypt_level;
+ const char *security_level =
+ (crypt_level == CRYPT_LEVEL_NONE) ? "none" :
+ (crypt_level == CRYPT_LEVEL_LOW) ? "low" :
+ (crypt_level == CRYPT_LEVEL_CLIENT_COMPATIBLE) ? "medium" :
+ (crypt_level == CRYPT_LEVEL_HIGH) ? "high" :
+ (crypt_level == CRYPT_LEVEL_FIPS) ? "fips" :
+ /* default */ "unknown";
+
LOG(LOG_LEVEL_INFO,
"Non-TLS connection established from %s port %s: "
- "encrypted with standard RDP security",
+ "with security level : %s",
self->client_info.client_addr,
- self->client_info.client_port);
+ self->client_info.client_port,
+ security_level);
}
return 0;
diff --git a/scripts/run_cppcheck.sh b/scripts/run_cppcheck.sh
index 2c152782..65ec254e 100755
--- a/scripts/run_cppcheck.sh
+++ b/scripts/run_cppcheck.sh
@@ -48,7 +48,7 @@ fi
# Any options/directories specified?
if [ $# -eq 0 ]; then
- set -- .
+ set -- -j 2 .
fi
# Display the cppcheck version and command for debugging
diff --git a/sesman/access.c b/sesman/access.c
index 4b8489aa..442d9e7b 100644
--- a/sesman/access.c
+++ b/sesman/access.c
@@ -31,8 +31,6 @@
#include "sesman.h"
#include "string_calls.h"
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
/******************************************************************************/
int
access_login_allowed(const char *user)
diff --git a/sesman/chansrv/chansrv_common.h b/sesman/chansrv/chansrv_common.h
index d15c8da7..656e608f 100644
--- a/sesman/chansrv/chansrv_common.h
+++ b/sesman/chansrv/chansrv_common.h
@@ -22,6 +22,13 @@
#include "parse.h"
#include "os_calls.h"
+/* Define bitmask values for restricting the clipboard */
+#define CLIP_RESTRICT_NONE 0
+#define CLIP_RESTRICT_TEXT (1<<0)
+#define CLIP_RESTRICT_FILE (1<<1)
+#define CLIP_RESTRICT_IMAGE (1<<2)
+#define CLIP_RESTRICT_ALL 0x7fffffff
+
int read_entire_packet(struct stream *src, struct stream **dest, int chan_flags, int length, int total_length);
#endif
diff --git a/sesman/chansrv/chansrv_config.c b/sesman/chansrv/chansrv_config.c
index adbecb5e..e3c30721 100644
--- a/sesman/chansrv/chansrv_config.c
+++ b/sesman/chansrv/chansrv_config.c
@@ -30,12 +30,14 @@
#include "file.h"
#include "os_calls.h"
+#include "chansrv_common.h"
#include "chansrv_config.h"
#include "string_calls.h"
/* Default settings */
#define DEFAULT_USE_UNIX_SOCKET 0
#define DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD 0
+#define DEFAULT_RESTRICT_INBOUND_CLIPBOARD 0
#define DEFAULT_ENABLE_FUSE_MOUNT 1
#define DEFAULT_FUSE_MOUNT_NAME "xrdp-client"
#define DEFAULT_FILE_UMASK 077
@@ -48,6 +50,21 @@ printflike(2, 3)
enum logReturns (*log_func_t)(const enum logLevels lvl,
const char *msg, ...);
+/* Map clipboard strings into bitmask values */
+static const struct bitmask_string clip_restrict_map[] =
+{
+ { CLIP_RESTRICT_TEXT, "text"},
+ { CLIP_RESTRICT_FILE, "file"},
+ { CLIP_RESTRICT_IMAGE, "image"},
+ { CLIP_RESTRICT_ALL, "all"},
+ { CLIP_RESTRICT_NONE, "none"},
+ /* Compatibility values */
+ { CLIP_RESTRICT_ALL, "true"},
+ { CLIP_RESTRICT_ALL, "yes"},
+ { CLIP_RESTRICT_NONE, "false"},
+ BITMASK_STRING_END_OF_LIST
+};
+
/***************************************************************************//**
* @brief Error logging function to use to log to stdout
*
@@ -125,9 +142,30 @@ read_config_security(log_func_t logmsg,
const char *name = (const char *)list_get_item(names, index);
const char *value = (const char *)list_get_item(values, index);
+ char unrecognised[256];
if (g_strcasecmp(name, "RestrictOutboundClipboard") == 0)
{
- cfg->restrict_outbound_clipboard = g_text2bool(value);
+ cfg->restrict_outbound_clipboard =
+ g_str_to_bitmask(value, clip_restrict_map, ",",
+ unrecognised, sizeof(unrecognised));
+ if (unrecognised[0] != '\0')
+ {
+ LOG(LOG_LEVEL_WARNING,
+ "Unrecognised tokens parsing 'RestrictOutboundClipboard' %s",
+ unrecognised);
+ }
+ }
+ if (g_strcasecmp(name, "RestrictInboundClipboard") == 0)
+ {
+ cfg->restrict_inbound_clipboard =
+ g_str_to_bitmask(value, clip_restrict_map, ",",
+ unrecognised, sizeof(unrecognised));
+ if (unrecognised[0] != '\0')
+ {
+ LOG(LOG_LEVEL_WARNING,
+ "Unrecognised tokens parsing 'RestrictInboundClipboard' %s",
+ unrecognised);
+ }
}
}
@@ -208,6 +246,7 @@ new_config(void)
cfg->use_unix_socket = DEFAULT_USE_UNIX_SOCKET;
cfg->enable_fuse_mount = DEFAULT_ENABLE_FUSE_MOUNT;
cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD;
+ cfg->restrict_inbound_clipboard = DEFAULT_RESTRICT_INBOUND_CLIPBOARD;
cfg->fuse_mount_name = fuse_mount_name;
cfg->file_umask = DEFAULT_FILE_UMASK;
cfg->use_nautilus3_flist_format = DEFAULT_USE_NAUTILUS3_FLIST_FORMAT;
@@ -286,10 +325,37 @@ config_dump(struct config_chansrv *config)
g_writeln(" UseUnixSocket (derived): %s",
g_bool2text(config->use_unix_socket));
+ char buf[256];
g_writeln("\nSecurity configuration:");
- g_writeln(" RestrictOutboundClipboard: %s",
- g_bool2text(config->restrict_outbound_clipboard));
+ if (config->restrict_outbound_clipboard == CLIP_RESTRICT_NONE)
+ {
+ g_writeln(" RestrictOutboundClipboard: %s", "none");
+ }
+ else if (config->restrict_outbound_clipboard == CLIP_RESTRICT_ALL)
+ {
+ g_writeln(" RestrictOutboundClipboard: %s", "all");
+ }
+ else
+ {
+ g_bitmask_to_str(config->restrict_outbound_clipboard,
+ clip_restrict_map, ',', buf, sizeof(buf));
+ g_writeln(" RestrictOutboundClipboard: %s", buf);
+ }
+ if (config->restrict_inbound_clipboard == CLIP_RESTRICT_NONE)
+ {
+ g_writeln(" RestrictInboundClipboard: %s", "none");
+ }
+ else if (config->restrict_inbound_clipboard == CLIP_RESTRICT_ALL)
+ {
+ g_writeln(" RestrictInboundClipboard: %s", "all");
+ }
+ else
+ {
+ g_bitmask_to_str(config->restrict_inbound_clipboard,
+ clip_restrict_map, ',', buf, sizeof(buf));
+ g_writeln(" RestrictInboundClipboard: %s", buf);
+ }
g_writeln("\nChansrv configuration:");
g_writeln(" EnableFuseMount %s",
g_bool2text(config->enable_fuse_mount));
diff --git a/sesman/chansrv/chansrv_config.h b/sesman/chansrv/chansrv_config.h
index f4acd592..b0327fea 100644
--- a/sesman/chansrv/chansrv_config.h
+++ b/sesman/chansrv/chansrv_config.h
@@ -31,6 +31,8 @@ struct config_chansrv
/** RestrictOutboundClipboard setting from sesman.ini */
int restrict_outbound_clipboard;
+ /** RestrictInboundClipboard setting from sesman.ini */
+ int restrict_inbound_clipboard;
/** * FuseMountName from sesman.ini */
char *fuse_mount_name;
diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c
index 245a51ee..d5422483 100644
--- a/sesman/chansrv/clipboard.c
+++ b/sesman/chansrv/clipboard.c
@@ -171,6 +171,7 @@ x-special/gnome-copied-files
#include "os_calls.h"
#include "string_calls.h"
#include "chansrv.h"
+#include "chansrv_common.h"
#include "chansrv_config.h"
#include "clipboard.h"
#include "clipboard_file.h"
@@ -1333,7 +1334,7 @@ clipboard_process_data_response(struct stream *s, int clip_msg_status,
return 0;
}
index = 0;
- while (s_check(s))
+ while (s_check_rem(s, 2))
{
in_uint16_le(s, wchr);
wtext[index] = wchr;
@@ -2005,14 +2006,33 @@ clipboard_event_selection_notify(XEvent *xevent)
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
if (g_clip_s2c.xrdp_clip_type == XRDP_CB_FILE)
{
- clipboard_send_data_response_for_file(g_clip_s2c.data,
- g_clip_s2c.total_bytes);
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(file) UTF8_STRING(%s) is restricted because of config",
+ g_clip_s2c.data);
+ }
+ else
+ {
+ clipboard_send_data_response_for_file(g_clip_s2c.data,
+ g_clip_s2c.total_bytes);
+ }
}
else
{
- clipboard_send_data_response_for_text(g_clip_s2c.data,
- g_clip_s2c.total_bytes);
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(text) UTF8_STRING(%s) is restricted because of config",
+ g_clip_s2c.data);
+ }
+ else
+ {
+ clipboard_send_data_response_for_text(g_clip_s2c.data,
+ g_clip_s2c.total_bytes);
+ }
}
+
}
}
else if (lxevent->target == XA_STRING)
@@ -2026,8 +2046,18 @@ clipboard_event_selection_notify(XEvent *xevent)
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
- clipboard_send_data_response_for_text(g_clip_s2c.data,
- g_clip_s2c.total_bytes);
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(text) XA_STRING(%s) is restricted because of config",
+ g_clip_s2c.data);
+ }
+ else
+ {
+ clipboard_send_data_response_for_text(g_clip_s2c.data,
+ g_clip_s2c.total_bytes);
+ }
+
}
}
else if (lxevent->target == g_image_bmp_atom)
@@ -2037,11 +2067,21 @@ clipboard_event_selection_notify(XEvent *xevent)
if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 14))
{
g_free(g_clip_s2c.data);
- g_clip_s2c.total_bytes = data_size;
- g_clip_s2c.data = (char *) g_malloc(data_size, 0);
- g_memcpy(g_clip_s2c.data, data, data_size);
- clipboard_send_data_response_for_image(g_clip_s2c.data + 14,
- data_size - 14);
+
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_IMAGE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(image) image/bmp is restricted because of config");
+ }
+ else
+ {
+ g_clip_s2c.total_bytes = data_size;
+ g_clip_s2c.data = (char *) g_malloc(data_size, 0);
+ g_memcpy(g_clip_s2c.data, data, data_size);
+ clipboard_send_data_response_for_image(g_clip_s2c.data + 14,
+ data_size - 14);
+ }
+
}
}
else if (lxevent->target == g_file_atom1)
@@ -2055,8 +2095,19 @@ clipboard_event_selection_notify(XEvent *xevent)
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
- clipboard_send_data_response_for_file(g_clip_s2c.data,
- g_clip_s2c.total_bytes);
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(file) text/uri-list(%s) is restricted because of config",
+ g_clip_s2c.data);
+ }
+ else
+ {
+ clipboard_send_data_response_for_file(g_clip_s2c.data,
+ g_clip_s2c.total_bytes);
+
+ }
+
}
}
else if (lxevent->target == g_file_atom2)
@@ -2070,8 +2121,18 @@ clipboard_event_selection_notify(XEvent *xevent)
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
- clipboard_send_data_response_for_file(g_clip_s2c.data,
- g_clip_s2c.total_bytes);
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(file) x-special/gnome-copied-files(%s) is restricted because of config",
+ g_clip_s2c.data);
+ }
+ else
+ {
+ clipboard_send_data_response_for_file(g_clip_s2c.data,
+ g_clip_s2c.total_bytes);
+ }
+
}
}
else
@@ -2090,35 +2151,81 @@ clipboard_event_selection_notify(XEvent *xevent)
if (got_file_atom != 0)
{
/* text/uri-list or x-special/gnome-copied-files */
- g_clip_s2c.type = got_file_atom;
- g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE;
- g_clip_s2c.converted = 0;
- g_clip_s2c.clip_time = lxevent->time;
- send_format_announce = 1;
+
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(file) is restricted because of config");
+ }
+ else
+ {
+ g_clip_s2c.type = got_file_atom;
+ g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE;
+ g_clip_s2c.converted = 0;
+ g_clip_s2c.clip_time = lxevent->time;
+ send_format_announce = 1;
+ }
+
}
else if (got_utf8)
{
- g_clip_s2c.type = g_utf8_atom;
- g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
- g_clip_s2c.converted = 0;
- g_clip_s2c.clip_time = lxevent->time;
- send_format_announce = 1;
+
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(text) is restricted because of config");
+ }
+ else
+ {
+ g_clip_s2c.type = g_utf8_atom;
+ g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
+ g_clip_s2c.converted = 0;
+ g_clip_s2c.clip_time = lxevent->time;
+ send_format_announce = 1;
+ }
+
}
else if (got_string)
{
- g_clip_s2c.type = XA_STRING;
- g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
- g_clip_s2c.converted = 0;
- g_clip_s2c.clip_time = lxevent->time;
- send_format_announce = 1;
+
+ /*
+ * In most cases, when copying text, TARGETS atom and UTF8_STRING atom exists,
+ * it means that this code block which checks STRING atom might not be never executed
+ * in recent platforms.
+ * Use echo foo | xclip -selection clipboard -noutf8 to reproduce it.
+ */
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(text) is restricted because of config");
+ }
+ else
+ {
+ g_clip_s2c.type = XA_STRING;
+ g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
+ g_clip_s2c.converted = 0;
+ g_clip_s2c.clip_time = lxevent->time;
+ send_format_announce = 1;
+ }
+
}
else if (got_bmp_image)
{
- g_clip_s2c.type = g_image_bmp_atom;
- g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP;
- g_clip_s2c.converted = 0;
- g_clip_s2c.clip_time = lxevent->time;
- send_format_announce = 1;
+
+ if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_IMAGE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "outbound clipboard(image) is restricted because of config");
+ }
+ else
+ {
+ g_clip_s2c.type = g_image_bmp_atom;
+ g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP;
+ g_clip_s2c.converted = 0;
+ g_clip_s2c.clip_time = lxevent->time;
+ send_format_announce = 1;
+ }
+
}
if (send_format_announce)
@@ -2187,16 +2294,23 @@ clipboard_event_selection_request(XEvent *xevent)
atom_buf[0] = g_targets_atom;
atom_buf[1] = g_timestamp_atom;
atom_buf[2] = g_multiple_atom;
- atom_buf[3] = XA_STRING;
- atom_buf[4] = g_utf8_atom;
- atom_count = 5;
- if (clipboard_find_format_id(CB_FORMAT_DIB) >= 0)
+ atom_count = 3;
+ if ((g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_TEXT) == 0)
+ {
+ atom_buf[atom_count] = XA_STRING;
+ atom_count++;
+ atom_buf[atom_count] = g_utf8_atom;
+ atom_count++;
+ }
+ if (clipboard_find_format_id(CB_FORMAT_DIB) >= 0 &&
+ (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE) == 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " reporting image/bmp");
atom_buf[atom_count] = g_image_bmp_atom;
atom_count++;
}
- if (clipboard_find_format_id(g_file_format_id) >= 0)
+ if (clipboard_find_format_id(g_file_format_id) >= 0 &&
+ (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE) == 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " reporting text/uri-list");
atom_buf[atom_count] = g_file_atom1;
@@ -2243,19 +2357,43 @@ clipboard_event_selection_request(XEvent *xevent)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: "
"text requested when files available");
- g_memcpy(&g_saved_selection_req_event, lxev,
- sizeof(g_saved_selection_req_event));
- g_clip_c2s.type = lxev->target;
- g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
- clipboard_send_data_request(g_file_format_id);
+
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard %s is restricted because of config",
+ lxev->target == XA_STRING ? "XA_STRING" : "UTF8_STRING");
+ clipboard_refuse_selection(lxev);
+ }
+ else
+ {
+ g_memcpy(&g_saved_selection_req_event, lxev,
+ sizeof(g_saved_selection_req_event));
+ g_clip_c2s.type = lxev->target;
+ g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
+ clipboard_send_data_request(g_file_format_id);
+ }
+
}
else
{
- g_memcpy(&g_saved_selection_req_event, lxev,
- sizeof(g_saved_selection_req_event));
- g_clip_c2s.type = lxev->target;
- g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
- clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
+
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_TEXT)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard %s is restricted because of config",
+ lxev->target == XA_STRING ? "XA_STRING" : "UTF8_STRING");
+ clipboard_refuse_selection(lxev);
+ }
+ else
+ {
+ g_memcpy(&g_saved_selection_req_event, lxev,
+ sizeof(g_saved_selection_req_event));
+ g_clip_c2s.type = lxev->target;
+ g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
+ clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
+ }
+
}
return 0;
}
@@ -2265,15 +2403,37 @@ clipboard_event_selection_request(XEvent *xevent)
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
- clipboard_provide_selection_c2s(lxev, lxev->target);
+
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard image/bmp converted is restricted because of config");
+ clipboard_refuse_selection(lxev);
+ }
+ else
+ {
+ clipboard_provide_selection_c2s(lxev, lxev->target);
+ }
return 0;
+
+ }
+
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard image/bmp is restricted because of config");
+ clipboard_refuse_selection(lxev);
+ }
+ else
+ {
+ g_memcpy(&g_saved_selection_req_event, lxev,
+ sizeof(g_saved_selection_req_event));
+ g_clip_c2s.type = g_image_bmp_atom;
+ g_clip_c2s.xrdp_clip_type = XRDP_CB_BITMAP;
+ clipboard_send_data_request(CB_FORMAT_DIB);
}
- g_memcpy(&g_saved_selection_req_event, lxev,
- sizeof(g_saved_selection_req_event));
- g_clip_c2s.type = g_image_bmp_atom;
- g_clip_c2s.xrdp_clip_type = XRDP_CB_BITMAP;
- clipboard_send_data_request(CB_FORMAT_DIB);
return 0;
+
}
else if (lxev->target == g_file_atom1)
{
@@ -2281,31 +2441,73 @@ clipboard_event_selection_request(XEvent *xevent)
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
- clipboard_provide_selection_c2s(lxev, lxev->target);
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard text/uri-list is restricted because of config");
+ clipboard_refuse_selection(lxev);
+ return 0;
+ }
+ else
+ {
+ clipboard_provide_selection_c2s(lxev, lxev->target);
+ return 0;
+ }
+ }
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard text/uri-list is restricted because of config");
+ clipboard_refuse_selection(lxev);
return 0;
}
- g_memcpy(&g_saved_selection_req_event, lxev,
- sizeof(g_saved_selection_req_event));
- g_clip_c2s.type = g_file_atom1;
- g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
- clipboard_send_data_request(g_file_format_id);
- return 0;
+ else
+ {
+ g_memcpy(&g_saved_selection_req_event, lxev,
+ sizeof(g_saved_selection_req_event));
+ g_clip_c2s.type = g_file_atom1;
+ g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
+ clipboard_send_data_request(g_file_format_id);
+ return 0;
+ }
+
}
else if (lxev->target == g_file_atom2)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_file_atom2");
+
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
- clipboard_provide_selection_c2s(lxev, lxev->target);
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard x-special/gnome-copied-files converted is restricted because of config");
+ clipboard_refuse_selection(lxev);
+ return 0;
+ }
+ else
+ {
+ clipboard_provide_selection_c2s(lxev, lxev->target);
+ return 0;
+ }
+ }
+ if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
+ {
+ LOG(LOG_LEVEL_DEBUG,
+ "inbound clipboard x-special/gnome-copied-files is restricted because of config");
+ clipboard_refuse_selection(lxev);
+ return 0;
+ }
+ else
+ {
+ g_memcpy(&g_saved_selection_req_event, lxev,
+ sizeof(g_saved_selection_req_event));
+ g_clip_c2s.type = g_file_atom2;
+ g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
+ clipboard_send_data_request(g_file_format_id);
return 0;
}
- g_memcpy(&g_saved_selection_req_event, lxev,
- sizeof(g_saved_selection_req_event));
- g_clip_c2s.type = g_file_atom2;
- g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
- clipboard_send_data_request(g_file_format_id);
- return 0;
}
else
{
@@ -2527,15 +2729,7 @@ clipboard_xevent(void *xevent)
switch (lxevent->type)
{
case SelectionNotify:
- if (g_cfg->restrict_outbound_clipboard == 0)
- {
- clipboard_event_selection_notify(lxevent);
- }
- else
- {
- LOG(LOG_LEVEL_INFO, "outbound clipboard is restricted because of config");
- return 1;
- }
+ clipboard_event_selection_notify(lxevent);
break;
case SelectionRequest:
clipboard_event_selection_request(lxevent);
diff --git a/sesman/config.c b/sesman/config.c
index 481ae760..61e9e403 100644
--- a/sesman/config.c
+++ b/sesman/config.c
@@ -34,6 +34,7 @@
#include "sesman.h"
#include "log.h"
#include "string_calls.h"
+#include "chansrv/chansrv_common.h"
/***************************************************************************//**
*
@@ -162,6 +163,26 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n,
return 0;
}
+/*
+ Map clipboard strings into bitmask values.
+ Duplicated definition exists in chansrv_config,
+ because it avoids build failure for xrdp-sesman and xrdp-sesrun.
+ It should be unified in the future.
+*/
+static const struct bitmask_string clip_restrict_map[] =
+{
+ { CLIP_RESTRICT_TEXT, "text"},
+ { CLIP_RESTRICT_FILE, "file"},
+ { CLIP_RESTRICT_IMAGE, "image"},
+ { CLIP_RESTRICT_ALL, "all"},
+ { CLIP_RESTRICT_NONE, "none"},
+ /* Compatibility values */
+ { CLIP_RESTRICT_ALL, "true"},
+ { CLIP_RESTRICT_ALL, "yes"},
+ { CLIP_RESTRICT_NONE, "false"},
+ BITMASK_STRING_END_OF_LIST
+};
+
/***************************************************************************//**
*
* @brief Reads sesman [Security] configuration section
@@ -190,6 +211,7 @@ config_read_security(int file, struct config_security *sc,
sc->ts_users_enable = 0;
sc->ts_admins_enable = 0;
sc->restrict_outbound_clipboard = 0;
+ sc->restrict_inbound_clipboard = 0;
file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v);
@@ -231,7 +253,31 @@ config_read_security(int file, struct config_security *sc,
if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD))
{
- sc->restrict_outbound_clipboard = g_text2bool((char *)list_get_item(param_v, i));
+ char unrecognised[256];
+ sc->restrict_outbound_clipboard =
+ g_str_to_bitmask((const char *)list_get_item(param_v, i),
+ clip_restrict_map, ",",
+ unrecognised, sizeof(unrecognised));
+ if (unrecognised[0] != '\0')
+ {
+ LOG(LOG_LEVEL_WARNING,
+ "Unrecognised tokens parsing 'RestrictOutboundClipboard' %s",
+ unrecognised);
+ }
+ }
+ if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD))
+ {
+ char unrecognised[256];
+ sc->restrict_inbound_clipboard =
+ g_str_to_bitmask((const char *)list_get_item(param_v, i),
+ clip_restrict_map, ",",
+ unrecognised, sizeof(unrecognised));
+ if (unrecognised[0] != '\0')
+ {
+ LOG(LOG_LEVEL_WARNING,
+ "Unrecognised tokens parsing 'RestrictInboundClipboard' %s",
+ unrecognised);
+ }
}
}
@@ -553,12 +599,41 @@ config_dump(struct config_sesman *config)
/* Security configuration */
g_writeln("Security configuration:");
- g_writeln(" AllowRootLogin: %d", sc->allow_root);
- g_writeln(" MaxLoginRetry: %d", sc->login_retry);
- g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check);
- g_writeln(" RestrictOutboundClipboard: %d", sc->restrict_outbound_clipboard);
+ g_writeln(" AllowRootLogin: %d", sc->allow_root);
+ g_writeln(" MaxLoginRetry: %d", sc->login_retry);
+ g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check);
+ if (sc->restrict_outbound_clipboard == CLIP_RESTRICT_NONE)
+ {
+ g_writeln(" RestrictOutboundClipboard: %s", "none");
+ }
+ else if (sc->restrict_outbound_clipboard == CLIP_RESTRICT_ALL)
+ {
+ g_writeln(" RestrictOutboundClipboard: %s", "all");
+ }
+ else
+ {
+ char buf[256];
+ g_bitmask_to_str(sc->restrict_outbound_clipboard,
+ clip_restrict_map, ',', buf, sizeof(buf));
+ g_writeln(" RestrictOutboundClipboard: %s", buf);
+ }
+ if (sc->restrict_inbound_clipboard == CLIP_RESTRICT_NONE)
+ {
+ g_writeln(" RestrictInboundClipboard: %s", "none");
+ }
+ else if (sc->restrict_inbound_clipboard == CLIP_RESTRICT_ALL)
+ {
+ g_writeln(" RestrictInboundClipboard: %s", "all");
+ }
+ else
+ {
+ char buf[256];
+ g_bitmask_to_str(sc->restrict_inbound_clipboard,
+ clip_restrict_map, ',', buf, sizeof(buf));
+ g_writeln(" RestrictInboundClipboard: %s", buf);
+ }
- g_printf( " TSUsersGroup: ");
+ g_printf( " TSUsersGroup: ");
if (sc->ts_users_enable)
{
g_printf("%d", sc->ts_users);
@@ -569,7 +644,7 @@ config_dump(struct config_sesman *config)
}
g_writeln("%s", "");
- g_printf( " TSAdminsGroup: ");
+ g_printf( " TSAdminsGroup: ");
if (sc->ts_admins_enable)
{
g_printf("%d", sc->ts_admins);
diff --git a/sesman/config.h b/sesman/config.h
index d9dbcefe..c6b72f8a 100644
--- a/sesman/config.h
+++ b/sesman/config.h
@@ -61,6 +61,7 @@
#define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins"
#define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck"
#define SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD "RestrictOutboundClipboard"
+#define SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD "RestrictInboundClipboard"
#define SESMAN_CFG_SESSIONS "Sessions"
#define SESMAN_CFG_SESS_MAX "MaxSessions"
@@ -134,6 +135,12 @@ struct config_security
* @brief if the clipboard should be enforced restricted. If true only allow client -> server, not vice versa.
*/
int restrict_outbound_clipboard;
+
+ /**
+ * @var restrict_inbound_clipboard
+ * @brief if the clipboard should be enforced restricted. If true only allow server -> client, not vice versa.
+ */
+ int restrict_inbound_clipboard;
};
/**
diff --git a/sesman/env.c b/sesman/env.c
index cdac0f17..f3b3dc63 100644
--- a/sesman/env.c
+++ b/sesman/env.c
@@ -36,9 +36,6 @@
#include "ssl_calls.h"
#include "string_calls.h"
-extern unsigned char g_fixedkey[8]; /* in sesman.c */
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
/******************************************************************************/
int
env_check_password_file(const char *filename, const char *passwd)
@@ -55,6 +52,7 @@ env_check_password_file(const char *filename, const char *passwd)
/* create password hash from password */
passwd_bytes = g_strlen(passwd);
sha1 = ssl_sha1_info_create();
+ ssl_sha1_clear(sha1);
ssl_sha1_transform(sha1, "xrdp_vnc", 8);
ssl_sha1_transform(sha1, passwd, passwd_bytes);
ssl_sha1_transform(sha1, passwd, passwd_bytes);
diff --git a/sesman/scp.c b/sesman/scp.c
index 36cf4045..62f6af39 100644
--- a/sesman/scp.c
+++ b/sesman/scp.c
@@ -33,8 +33,6 @@
#include "sesman.h"
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
/******************************************************************************/
enum SCP_SERVER_STATES_E
scp_process(struct trans *t, struct SCP_SESSION *sdata)
diff --git a/sesman/scp_v0.c b/sesman/scp_v0.c
index 100c5902..195169fa 100644
--- a/sesman/scp_v0.c
+++ b/sesman/scp_v0.c
@@ -30,8 +30,6 @@
#include "sesman.h"
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
/******************************************************************************/
enum SCP_SERVER_STATES_E
scp_v0_process(struct trans *t, struct SCP_SESSION *s)
diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c
index a8a59ebd..91a47e07 100644
--- a/sesman/scp_v1.c
+++ b/sesman/scp_v1.c
@@ -33,8 +33,6 @@
//#include "libscp_types.h"
#include "libscp.h"
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
static void
parseCommonStates(enum SCP_SERVER_STATES_E e, const char *f);
diff --git a/sesman/scp_v1_mng.c b/sesman/scp_v1_mng.c
index 1ae13476..2b7ff216 100644
--- a/sesman/scp_v1_mng.c
+++ b/sesman/scp_v1_mng.c
@@ -32,8 +32,6 @@
#include "libscp.h"
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
static void parseCommonStates(enum SCP_SERVER_STATES_E e, const char *f);
/******************************************************************************/
diff --git a/sesman/sesman.c b/sesman/sesman.c
index e2b057e6..3d15a83b 100644
--- a/sesman/sesman.c
+++ b/sesman/sesman.c
@@ -52,11 +52,11 @@ struct sesman_startup_params
int dump_config;
};
-int g_pid;
+struct config_sesman *g_cfg;
unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 };
-struct config_sesman *g_cfg; /* defined in config.h */
-
tintptr g_term_event = 0;
+tintptr g_sigchld_event = 0;
+tintptr g_reload_event = 0;
/**
* Items stored on the g_con_list
@@ -67,8 +67,9 @@ struct sesman_con
struct SCP_SESSION *s;
};
-static struct trans *g_list_trans = NULL;
+static struct trans *g_list_trans;
static struct list *g_con_list = NULL;
+static int g_pid;
/*****************************************************************************/
/**
@@ -263,7 +264,7 @@ sesman_close_all(void)
struct sesman_con *sc;
LOG_DEVEL(LOG_LEVEL_TRACE, "sesman_close_all:");
- trans_delete(g_list_trans);
+ sesman_delete_listening_transport();
for (index = 0; index < g_con_list->count; index++)
{
sc = (struct sesman_con *) list_get_item(g_con_list, index);
@@ -342,6 +343,86 @@ sesman_listen_conn_in(struct trans *self, struct trans *new_self)
/******************************************************************************/
/**
+ * Informs the main loop a termination signal has been received
+ */
+static void
+set_term_event(int sig)
+{
+ /* Don't try to use a wait obj in a child process */
+ if (g_getpid() == g_pid)
+ {
+ g_set_wait_obj(g_term_event);
+ }
+}
+
+/******************************************************************************/
+/**
+ * Informs the main loop a SIGCHLD has been received
+ */
+static void
+set_sigchld_event(int sig)
+{
+ /* Don't try to use a wait obj in a child process */
+ if (g_getpid() == g_pid)
+ {
+ g_set_wait_obj(g_sigchld_event);
+ }
+}
+
+/******************************************************************************/
+/**
+ * Informs the main loop a SIGHUP has been received
+ */
+static void
+set_reload_event(int sig)
+{
+ /* Don't try to use a wait obj in a child process */
+ if (g_getpid() == g_pid)
+ {
+ g_set_wait_obj(g_reload_event);
+ }
+}
+
+/******************************************************************************/
+void
+sesman_delete_listening_transport(void)
+{
+ trans_delete(g_list_trans);
+ g_list_trans = NULL;
+}
+
+/******************************************************************************/
+int
+sesman_create_listening_transport(const struct config_sesman *cfg)
+{
+ int rv = 1;
+ g_list_trans = trans_create(TRANS_MODE_TCP, 8192, 8192);
+ if (g_list_trans == NULL)
+ {
+ LOG(LOG_LEVEL_ERROR, "%s: trans_create failed", __func__);
+ }
+ else
+ {
+ LOG(LOG_LEVEL_DEBUG, "%s: address %s port %s",
+ __func__, cfg->listen_address, cfg->listen_port);
+ rv = trans_listen_address(g_list_trans, cfg->listen_port,
+ cfg->listen_address);
+ if (rv != 0)
+ {
+ LOG(LOG_LEVEL_ERROR, "%s: trans_listen_address failed", __func__);
+ sesman_delete_listening_transport();
+ }
+ else
+ {
+ g_list_trans->trans_conn_in = sesman_listen_conn_in;
+ }
+ }
+
+ return rv;
+}
+
+/******************************************************************************/
+/**
*
* @brief Starts sesman main loop
*
@@ -352,7 +433,6 @@ sesman_main_loop(void)
int error;
int robjs_count;
int wobjs_count;
- int cont;
int timeout;
int index;
intptr_t robjs[32];
@@ -365,33 +445,22 @@ sesman_main_loop(void)
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: list_create failed");
return 1;
}
- g_list_trans = trans_create(TRANS_MODE_TCP, 8192, 8192);
- if (g_list_trans == NULL)
+ if (sesman_create_listening_transport(g_cfg) != 0)
{
- LOG(LOG_LEVEL_ERROR, "sesman_main_loop: trans_create failed");
+ LOG(LOG_LEVEL_ERROR,
+ "sesman_main_loop: sesman_create_listening_transport failed");
list_delete(g_con_list);
return 1;
}
- LOG(LOG_LEVEL_DEBUG, "sesman_main_loop: address %s port %s",
- g_cfg->listen_address, g_cfg->listen_port);
- error = trans_listen_address(g_list_trans, g_cfg->listen_port,
- g_cfg->listen_address);
- if (error != 0)
- {
- LOG(LOG_LEVEL_ERROR, "sesman_main_loop: trans_listen_address "
- "failed");
- trans_delete(g_list_trans);
- list_delete(g_con_list);
- return 1;
- }
- g_list_trans->trans_conn_in = sesman_listen_conn_in;
- cont = 1;
- while (cont)
+ error = 0;
+ while (!error)
{
timeout = -1;
robjs_count = 0;
robjs[robjs_count++] = g_term_event;
+ robjs[robjs_count++] = g_sigchld_event;
+ robjs[robjs_count++] = g_reload_event;
wobjs_count = 0;
for (index = 0; index < g_con_list->count; index++)
{
@@ -413,34 +482,53 @@ sesman_main_loop(void)
{
break;
}
- error = trans_get_wait_objs_rw(g_list_trans, robjs, &robjs_count,
- wobjs, &wobjs_count, &timeout);
- if (error != 0)
+ if (g_list_trans != NULL)
{
- LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
- "trans_get_wait_objs_rw failed");
- break;
+ /* g_list_trans might be NULL on a reconfigure if sesman
+ * is unable to listen again */
+ error = trans_get_wait_objs_rw(g_list_trans, robjs, &robjs_count,
+ wobjs, &wobjs_count, &timeout);
+ if (error != 0)
+ {
+ LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
+ "trans_get_wait_objs_rw failed");
+ break;
+ }
}
- error = g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout);
- if (error != 0)
+ if (g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout) != 0)
{
- /* error, should not get here */
+ /* should not get here */
+ LOG(LOG_LEVEL_WARNING, "sesman_main_loop: "
+ "Unexpected error from g_obj_wait()");
g_sleep(100);
}
if (g_is_wait_obj_set(g_term_event)) /* term */
{
+ LOG(LOG_LEVEL_INFO, "sesman_main_loop: "
+ "sesman asked to terminate");
break;
}
+ if (g_is_wait_obj_set(g_sigchld_event)) /* A child has exited */
+ {
+ g_reset_wait_obj(g_sigchld_event);
+ sig_sesman_session_end();
+ }
+
+ if (g_is_wait_obj_set(g_reload_event)) /* We're asked to reload */
+ {
+ g_reset_wait_obj(g_reload_event);
+ sig_sesman_reload_cfg();
+ }
+
for (index = 0; index < g_con_list->count; index++)
{
scon = (struct sesman_con *)list_get_item(g_con_list, index);
if (scon != NULL)
{
- error = trans_check_wait_objs(scon->t);
- if (error != 0)
+ if (trans_check_wait_objs(scon->t) != 0)
{
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
"trans_check_wait_objs failed, removing trans");
@@ -451,12 +539,16 @@ sesman_main_loop(void)
}
}
}
- error = trans_check_wait_objs(g_list_trans);
- if (error != 0)
+
+ if (g_list_trans != NULL)
{
- LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
- "trans_check_wait_objs failed");
- break;
+ error = trans_check_wait_objs(g_list_trans);
+ if (error != 0)
+ {
+ LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
+ "trans_check_wait_objs failed");
+ break;
+ }
}
}
for (index = 0; index < g_con_list->count; index++)
@@ -465,7 +557,7 @@ sesman_main_loop(void)
delete_connection(scon);
}
list_delete(g_con_list);
- trans_delete(g_list_trans);
+ sesman_delete_listening_transport();
return 0;
}
@@ -627,8 +719,9 @@ main(int argc, char **argv)
}
/* starting logging subsystem */
- log_error = log_start(startup_params.sesman_ini, "xrdp-sesman",
- startup_params.dump_config);
+ log_error = log_start(
+ startup_params.sesman_ini, "xrdp-sesman",
+ (startup_params.dump_config) ? LOG_START_DUMP_CONFIG : 0);
if (log_error != LOG_STARTUP_OK)
{
@@ -709,20 +802,17 @@ main(int argc, char **argv)
/* signal handling */
g_pid = g_getpid();
- /* old style signal handling is now managed synchronously by a
- * separate thread. uncomment this block if you need old style
- * signal handling and comment out thread_sighandler_start()
- * going back to old style for the time being
- * problem with the sigaddset functions in sig.c - jts */
-#if 1
- g_signal_hang_up(sig_sesman_reload_cfg); /* SIGHUP */
- g_signal_user_interrupt(sig_sesman_shutdown); /* SIGINT */
- g_signal_terminate(sig_sesman_shutdown); /* SIGTERM */
- g_signal_child_stop(sig_sesman_session_end); /* SIGCHLD */
-#endif
-#if 0
- thread_sighandler_start();
-#endif
+ g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid);
+ g_term_event = g_create_wait_obj(text);
+ g_snprintf(text, 255, "xrdp_sesman_%8.8x_sigchld", g_pid);
+ g_sigchld_event = g_create_wait_obj(text);
+ g_snprintf(text, 255, "xrdp_sesman_%8.8x_reload", g_pid);
+ g_reload_event = g_create_wait_obj(text);
+
+ g_signal_hang_up(set_reload_event); /* SIGHUP */
+ g_signal_user_interrupt(set_term_event); /* SIGINT */
+ g_signal_terminate(set_term_event); /* SIGTERM */
+ g_signal_child_stop(set_sigchld_event); /* SIGCHLD */
if (daemon)
{
@@ -764,9 +854,6 @@ main(int argc, char **argv)
g_chmod_hex("/tmp/.X11-unix", 0x1777);
}
- g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid);
- g_term_event = g_create_wait_obj(text);
-
error = sesman_main_loop();
/* clean up PID file on exit */
@@ -775,6 +862,8 @@ main(int argc, char **argv)
g_file_delete(pid_file);
}
+ g_delete_wait_obj(g_reload_event);
+ g_delete_wait_obj(g_sigchld_event);
g_delete_wait_obj(g_term_event);
if (!daemon)
diff --git a/sesman/sesman.h b/sesman/sesman.h
index ebffff47..e7e7fe63 100644
--- a/sesman/sesman.h
+++ b/sesman/sesman.h
@@ -41,6 +41,13 @@
#include "libscp.h"
+/* Globals */
+extern struct config_sesman *g_cfg;
+extern unsigned char g_fixedkey[8];
+extern tintptr g_term_event;
+extern tintptr g_sigchld_event;
+extern tintptr g_reload_event;
+
/*
* Close all file descriptors used by sesman.
*
@@ -53,4 +60,20 @@
int
sesman_close_all(void);
+/*
+ * Remove the listening transport
+ *
+ * Needed if reloading the config and the listener has changed
+ */
+void
+sesman_delete_listening_transport(void);
+
+/*
+ * Create the listening socket transport
+ *
+ * @return 0 for success
+ */
+int
+sesman_create_listening_transport(const struct config_sesman *cfg);
+
#endif
diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in
index 7b8f0880..8c5f173f 100644
--- a/sesman/sesman.ini.in
+++ b/sesman/sesman.ini.in
@@ -19,9 +19,24 @@ TerminalServerAdmins=tsadmins
; When AlwaysGroupCheck=false access will be permitted
; if the group TerminalServerUsers is not defined.
AlwaysGroupCheck=false
-; When RestrictOutboundClipboard=true clipboard from the
+; When RestrictOutboundClipboard=all clipboard from the
; server is not pushed to the client.
-RestrictOutboundClipboard=false
+; In addition, you can control text/file/image transfer restrictions
+; respectively. It also accepts comma separated list such as text,file,image.
+; To keep compatibility, some aliases are also available:
+; true: an alias of all
+; false: an alias of none
+; yes: an alias of all
+RestrictOutboundClipboard=none
+; When RestrictInboundClipboard=all clipboard from the
+; client is not pushed to the server.
+; In addition, you can control text/file/image transfer restrictions
+; respectively. It also accepts comma separated list such as text,file,image.
+; To keep compatibility, some aliases are also available:
+; true: an alias of all
+; false: an alias of none
+; yes: an alias of all
+RestrictInboundClipboard=none
[Sessions]
;; X11DisplayOffset - x11 display number offset
diff --git a/sesman/session.c b/sesman/session.c
index 28fdb3d9..8be3855a 100644
--- a/sesman/session.c
+++ b/sesman/session.c
@@ -47,12 +47,8 @@
#define PR_SET_NO_NEW_PRIVS 38
#endif
-extern unsigned char g_fixedkey[8];
-extern struct config_sesman *g_cfg; /* in sesman.c */
-struct session_chain *g_sessions;
-int g_session_count;
-
-extern tbus g_term_event; /* in sesman.c */
+static struct session_chain *g_sessions;
+static int g_session_count;
/**
* Creates a string consisting of all parameters that is hosted in the param list
@@ -524,8 +520,13 @@ session_start_fork(tbus data, tui8 type, struct SCP_SESSION *s)
"Failed to clone the session data - out of memory");
g_exit(1);
}
- auth_start_session(data, display);
+
+ /* Wait objects created in a parent are not valid in a child */
+ g_delete_wait_obj(g_reload_event);
+ g_delete_wait_obj(g_sigchld_event);
g_delete_wait_obj(g_term_event);
+
+ auth_start_session(data, display);
sesman_close_all();
g_sprintf(geometry, "%dx%d", s->width, s->height);
g_sprintf(depth, "%d", s->bpp);
diff --git a/sesman/sig.c b/sesman/sig.c
index 53fb8bd1..14d4c820 100644
--- a/sesman/sig.c
+++ b/sesman/sig.c
@@ -28,52 +28,17 @@
#include <config_ac.h>
#endif
-#include <signal.h>
-
+#include "string_calls.h"
#include "sesman.h"
-extern int g_pid;
-extern struct config_sesman *g_cfg; /* in sesman.c */
-extern tbus g_term_event;
-
/******************************************************************************/
void
-sig_sesman_shutdown(int sig)
-{
- char pid_file[256];
-
- LOG(LOG_LEVEL_INFO, "shutting down sesman %d", 1);
-
- if (g_getpid() != g_pid)
- {
- LOG_DEVEL(LOG_LEVEL_DEBUG, "g_getpid() [%d] differs from g_pid [%d]", (g_getpid()), g_pid);
- return;
- }
-
- LOG_DEVEL(LOG_LEVEL_DEBUG, " - getting signal %d pid %d", sig, g_getpid());
-
- g_set_wait_obj(g_term_event);
-
- session_sigkill_all();
-
- g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH);
- g_file_delete(pid_file);
-}
-
-/******************************************************************************/
-void
-sig_sesman_reload_cfg(int sig)
+sig_sesman_reload_cfg(void)
{
int error;
struct config_sesman *cfg;
- LOG(LOG_LEVEL_WARNING, "receiving SIGHUP %d", 1);
-
- if (g_getpid() != g_pid)
- {
- LOG_DEVEL(LOG_LEVEL_DEBUG, "g_getpid() [%d] differs from g_pid [%d]", g_getpid(), g_pid);
- return;
- }
+ LOG(LOG_LEVEL_INFO, "receiving SIGHUP");
if ((cfg = config_read(g_cfg->sesman_ini)) == NULL)
{
@@ -81,8 +46,18 @@ sig_sesman_reload_cfg(int sig)
return;
}
- /* stop logging subsystem */
- log_end();
+ /* Deal with significant config changes */
+ if (g_strcmp(g_cfg->listen_address, cfg->listen_address) != 0 ||
+ g_strcmp(g_cfg->listen_port, cfg->listen_port) != 0)
+ {
+ LOG(LOG_LEVEL_INFO, "sesman listen address changed to %s:%s",
+ cfg->listen_address, cfg->listen_port);
+
+ /* We have to delete the old port before listening to the new one
+ * in case they overlap in scope */
+ sesman_delete_listening_transport();
+ sesman_create_listening_transport(cfg);
+ }
/* free old config data */
config_free(g_cfg);
@@ -90,8 +65,8 @@ sig_sesman_reload_cfg(int sig)
/* replace old config with newly read one */
g_cfg = cfg;
- /* start again logging subsystem */
- error = log_start(g_cfg->sesman_ini, "xrdp-sesman", 0);
+ /* Restart logging subsystem */
+ error = log_start(g_cfg->sesman_ini, "xrdp-sesman", LOG_START_RESTART);
if (error != LOG_STARTUP_OK)
{
@@ -113,80 +88,21 @@ sig_sesman_reload_cfg(int sig)
/******************************************************************************/
void
-sig_sesman_session_end(int sig)
+sig_sesman_session_end(void)
{
int pid;
- if (g_getpid() != g_pid)
- {
- return;
- }
-
- pid = g_waitchild();
-
- if (pid > 0)
- {
- session_kill(pid);
- }
-}
-
-/******************************************************************************/
-void *
-sig_handler_thread(void *arg)
-{
- int recv_signal;
- sigset_t sigmask;
- sigset_t oldmask;
- sigset_t waitmask;
-
- /* mask signals to be able to wait for them... */
- sigfillset(&sigmask);
- /* it is a good idea not to block SIGILL SIGSEGV */
- /* SIGFPE -- see sigaction(2) NOTES */
- pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
-
- /* building the signal wait mask... */
- sigemptyset(&waitmask);
- sigaddset(&waitmask, SIGHUP);
- sigaddset(&waitmask, SIGCHLD);
- sigaddset(&waitmask, SIGTERM);
- sigaddset(&waitmask, SIGINT);
-
- // sigaddset(&waitmask, SIGFPE);
- // sigaddset(&waitmask, SIGILL);
- // sigaddset(&waitmask, SIGSEGV);
-
+ LOG(LOG_LEVEL_DEBUG, "receiving SIGCHLD");
do
{
- LOG_DEVEL(LOG_LEVEL_DEBUG, "calling sigwait()");
- sigwait(&waitmask, &recv_signal);
+ pid = g_waitchild();
- switch (recv_signal)
+ if (pid > 0)
{
- case SIGHUP:
- //reload cfg
- //we must stop & restart logging, or copy logging cfg!!!!
- LOG_DEVEL(LOG_LEVEL_DEBUG, "sesman received SIGHUP");
- //return 0;
- break;
- case SIGCHLD:
- /* a session died */
- LOG_DEVEL(LOG_LEVEL_DEBUG, "sesman received SIGCHLD");
- sig_sesman_session_end(SIGCHLD);
- break;
- case SIGINT:
- /* we die */
- LOG_DEVEL(LOG_LEVEL_DEBUG, "sesman received SIGINT");
- sig_sesman_shutdown(recv_signal);
- break;
- case SIGTERM:
- /* we die */
- LOG_DEVEL(LOG_LEVEL_DEBUG, "sesman received SIGTERM");
- sig_sesman_shutdown(recv_signal);
- break;
+ LOG(LOG_LEVEL_INFO, "Process %d has exited", pid);
+
+ session_kill(pid);
}
}
- while (1);
-
- return 0;
+ while (pid > 0);
}
diff --git a/sesman/sig.h b/sesman/sig.h
index f7582686..447dde63 100644
--- a/sesman/sig.h
+++ b/sesman/sig.h
@@ -29,37 +29,18 @@
/**
*
- * @brief Shutdown signal code
- * @param sig The received signal
- *
- */
-void
-sig_sesman_shutdown(int sig);
-
-/**
- *
* @brief SIGHUP handling code
- * @param sig The received signal
*
*/
void
-sig_sesman_reload_cfg(int sig);
+sig_sesman_reload_cfg(void);
/**
*
* @brief SIGCHLD handling code
- * @param sig The received signal
*
*/
void
-sig_sesman_session_end(int sig);
-
-/**
- *
- * @brief signal handling thread
- *
- */
-void *
-sig_handler_thread(void *arg);
+sig_sesman_session_end(void);
#endif
diff --git a/sesman/verify_user.c b/sesman/verify_user.c
index 76918d68..2c72d38e 100644
--- a/sesman/verify_user.c
+++ b/sesman/verify_user.c
@@ -42,8 +42,6 @@
#define SECS_PER_DAY (24L*3600L)
#endif
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
static int
auth_crypt_pwd(const char *pwd, const char *pln, char *crp);
diff --git a/sesman/verify_user_bsd.c b/sesman/verify_user_bsd.c
index 4b7793d1..06489653 100644
--- a/sesman/verify_user_bsd.c
+++ b/sesman/verify_user_bsd.c
@@ -43,8 +43,6 @@
#define SECS_PER_DAY (24L*3600L)
#endif
-extern struct config_sesman *g_cfg; /* in sesman.c */
-
/******************************************************************************/
/* returns boolean */
long
diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am
index 5a5ca8d5..e6686e31 100644
--- a/tests/common/Makefile.am
+++ b/tests/common/Makefile.am
@@ -6,6 +6,8 @@ AM_CPPFLAGS = \
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
$(top_srcdir)/tap-driver.sh
+PACKAGE_STRING = "libcommon"
+
TESTS = test_common
check_PROGRAMS = test_common
@@ -13,7 +15,9 @@ test_common_SOURCES = \
test_common.h \
test_common_main.c \
test_string_calls.c \
- test_os_calls.c
+ test_os_calls.c \
+ test_ssl_calls.c \
+ test_base64.c
test_common_CFLAGS = \
@CHECK_CFLAGS@ \
diff --git a/tests/common/test_base64.c b/tests/common/test_base64.c
new file mode 100644
index 00000000..4a70c921
--- /dev/null
+++ b/tests/common/test_base64.c
@@ -0,0 +1,400 @@
+
+#if defined(HAVE_CONFIG_H)
+#include "config_ac.h"
+#endif
+
+#include "os_calls.h"
+#include "string_calls.h"
+#include "base64.h"
+
+#include "test_common.h"
+/*
+* These are the example test strings in RFC4648(10)
+*/
+static const char *rfc4648_ex1_text = "";
+static const char *rfc4648_ex1_b64 = "";
+static const char *rfc4648_ex2_text = "f";
+static const char *rfc4648_ex2_b64 = "Zg==";
+static const char *rfc4648_ex3_text = "fo";
+static const char *rfc4648_ex3_b64 = "Zm8=";
+static const char *rfc4648_ex4_text = "foo";
+static const char *rfc4648_ex4_b64 = "Zm9v";
+static const char *rfc4648_ex5_text = "foob";
+static const char *rfc4648_ex5_b64 = "Zm9vYg==";
+static const char *rfc4648_ex6_text = "fooba";
+static const char *rfc4648_ex6_b64 = "Zm9vYmE=";
+static const char *rfc4648_ex7_text = "foobar";
+static const char *rfc4648_ex7_b64 = "Zm9vYmFy";
+
+/* Every single valid base64 character, except padding */
+static const char *all_b64 =
+ "ABCDEFGHIJKL"
+ "MNOPQRSTUVWX"
+ "YZabcdefghij"
+ "klmnopqrstuv"
+ "wxyz01234567"
+ "89+/";
+
+/* What we should get as binary if we decode this */
+static const char all_b64_decoded[] =
+{
+ '\x00', '\x10', '\x83', '\x10', '\x51', '\x87', '\x20', '\x92', '\x8b',
+ '\x30', '\xd3', '\x8f', '\x41', '\x14', '\x93', '\x51', '\x55', '\x97',
+ '\x61', '\x96', '\x9b', '\x71', '\xd7', '\x9f', '\x82', '\x18', '\xa3',
+ '\x92', '\x59', '\xa7', '\xa2', '\x9a', '\xab', '\xb2', '\xdb', '\xaf',
+ '\xc3', '\x1c', '\xb3', '\xd3', '\x5d', '\xb7', '\xe3', '\x9e', '\xbb',
+ '\xf3', '\xdf', '\xbf'
+};
+
+static void
+test_rfc4648_to_b64(const char *plaintext, size_t len, const char *b64)
+{
+ char buff[256];
+ size_t result;
+
+ result = base64_encode(plaintext, len, buff, sizeof(buff));
+ ck_assert_int_eq(result, len);
+ ck_assert_str_eq(buff, b64);
+
+}
+
+/* Text-only encoder wrapper */
+static void
+test_rfc4648_to_b64_text(const char *plaintext, const char *b64)
+{
+ test_rfc4648_to_b64(plaintext, g_strlen(plaintext), b64);
+}
+
+/* Text-only decoder wrapper for valid base64 */
+static void
+test_rfc4648_from_b64_text(const char *b64, const char *text)
+{
+ char buff[256];
+ size_t actual_len;
+ int result;
+
+ result = base64_decode(b64, buff, sizeof(buff), &actual_len);
+ ck_assert_int_eq(result, 0);
+ ck_assert_int_lt(actual_len, sizeof(buff));
+ buff[actual_len] = '\0';
+ ck_assert_str_eq(buff, text);
+}
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex1_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex1_text, rfc4648_ex1_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex1_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex1_b64, rfc4648_ex1_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex2_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex2_text, rfc4648_ex2_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex2_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex2_b64, rfc4648_ex2_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex3_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex3_text, rfc4648_ex3_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex3_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex3_b64, rfc4648_ex3_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex4_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex4_text, rfc4648_ex4_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex4_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex4_b64, rfc4648_ex4_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex5_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex5_text, rfc4648_ex5_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex5_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex5_b64, rfc4648_ex5_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex6_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex6_text, rfc4648_ex6_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex6_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex6_b64, rfc4648_ex6_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex7_to)
+{
+ test_rfc4648_to_b64_text(rfc4648_ex7_text, rfc4648_ex7_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_rfc4648_ex7_from)
+{
+ test_rfc4648_from_b64_text(rfc4648_ex7_b64, rfc4648_ex7_text);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_all_valid_from)
+{
+ char buff[256];
+ size_t actual_len;
+ int result;
+ char *str_result;
+ char *str_expected;
+
+ result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
+ ck_assert_int_eq(result, 0);
+ ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
+ str_result = bin_to_hex(buff, actual_len);
+ str_expected = bin_to_hex(all_b64_decoded, sizeof(all_b64_decoded));
+ ck_assert_str_eq(str_result, str_expected);
+ free(str_result);
+ free(str_expected);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_all_valid_to)
+{
+ char buff[256];
+ size_t result;
+
+ result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
+ buff, sizeof(buff));
+ ck_assert_int_eq(result, sizeof(all_b64_decoded));
+ ck_assert_str_eq(buff, all_b64);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_all_invalid)
+{
+ char buff[256];
+ size_t actual_len;
+ char valid[256] = {0};
+ char encoded[5] = { "T0sh" }; /* Decodes to 'OK!' */
+ int result;
+
+ /* Make a note of all the valid b64 characters */
+ unsigned int i = 0;
+ unsigned char c;
+ while ((c = all_b64[i]) != '\0')
+ {
+ valid[c] = 1;
+ ++i;
+ }
+
+ /* Check the decoder's working on a simple string...*/
+ result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
+ ck_assert_int_eq(result, 0);
+ ck_assert_int_eq(actual_len, 3);
+ buff[actual_len] = '\0';
+ ck_assert_str_eq(buff, "OK!");
+
+ /* Now replace the 1st character with all invalid characters in turn,
+ * and check they're rejected */
+ for (i = 0 ; i < 256; ++i)
+ {
+ if (i != '\0' && !valid[i]) /* Don't try the string terminator char! */
+ {
+ encoded[0] = i;
+ result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
+ if (result == 0)
+ {
+ ck_abort_msg("Character 0x%02x was not rejected", i);
+ }
+ }
+ }
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_small_buffer_encode)
+{
+ char buff[10 * 4 + 1]; /* Enough space for 10 quanta */
+
+ size_t result;
+
+ result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
+ buff, sizeof(buff));
+ /* Should have read 10 lots of 24 bits from the input */
+ ck_assert_int_eq(result, 10 * 3);
+ ck_assert_str_eq(buff, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn");
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_small_buffer_decode)
+{
+ char buff[10]; /* Enough space for 10 chars */
+
+ size_t actual_len;
+ int result;
+ char *str_result;
+ char *str_expected;
+
+ result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
+ ck_assert_int_eq(result, 0);
+ ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
+ str_result = bin_to_hex(buff, sizeof(buff));
+ str_expected = bin_to_hex(all_b64_decoded, sizeof(buff));
+ ck_assert_str_eq(str_result, str_expected);
+ free(str_result);
+ free(str_expected);
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_add_pad_one)
+{
+ /* Check that a missing trailing '=' is added when decoding */
+ test_rfc4648_from_b64_text("Zm8", "fo"); /* RFC4648 example 3 */
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_add_pad_two)
+{
+ /* Check that two missing trailing '=' chars are added when decoding */
+ test_rfc4648_from_b64_text("Zg", "f"); /* RFC4648 example 2 */
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_bad_pad)
+{
+ char buff[16];
+ size_t actual_len;
+
+ /* Check all bad quanta with padding chars */
+ static const char *bad_pad[] =
+ {
+ "=AAA",
+ "A=AA",
+ "AA=A",
+ "==AA",
+ "=A=A",
+ "=AA=",
+ "A==A",
+ "A=A=",
+ "===A",
+ "A===",
+ NULL
+ };
+ const char **p;
+
+ for (p = bad_pad ; *p != NULL ; ++p)
+ {
+ int result = base64_decode(*p, buff, sizeof(buff), &actual_len);
+ if (result == 0)
+ {
+ ck_abort_msg("Padding '%s' was not rejected", *p);
+ }
+ }
+}
+END_TEST
+
+/******************************************************************************/
+START_TEST(test_b64_concat_pad)
+{
+ const char *src =
+ "VGVzdA==" /* Test */
+ "IA==" /* <space> */
+ "Y29uY2F0ZW5hdGVk" /* concatenated */
+ "IA==" /* <space> */
+ "cGFkZGluZw=="; /*padding */
+ const char *expected = "Test concatenated padding";
+ char buff[64];
+ size_t actual_len;
+ int result;
+
+ result = base64_decode(src, buff, sizeof(buff), &actual_len);
+ ck_assert_int_eq(result, 0);
+ ck_assert_int_eq(actual_len, g_strlen(expected));
+ buff[actual_len] = '\0';
+ ck_assert_str_eq(buff, expected);
+}
+END_TEST
+
+/******************************************************************************/
+Suite *
+make_suite_test_base64(void)
+{
+ Suite *s;
+ TCase *tc_b64;
+
+ s = suite_create("base64");
+
+ tc_b64 = tcase_create("base64");
+ suite_add_tcase(s, tc_b64);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex1_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex1_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex2_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex2_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex3_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex3_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex4_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex4_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex5_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex5_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex6_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex6_from);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex7_to);
+ tcase_add_test(tc_b64, test_b64_rfc4648_ex7_from);
+ tcase_add_test(tc_b64, test_b64_all_valid_from);
+ tcase_add_test(tc_b64, test_b64_all_valid_to);
+ tcase_add_test(tc_b64, test_b64_all_invalid);
+ tcase_add_test(tc_b64, test_b64_small_buffer_encode);
+ tcase_add_test(tc_b64, test_b64_small_buffer_decode);
+ tcase_add_test(tc_b64, test_b64_add_pad_one);
+ tcase_add_test(tc_b64, test_b64_add_pad_two);
+ tcase_add_test(tc_b64, test_b64_bad_pad);
+ tcase_add_test(tc_b64, test_b64_concat_pad);
+
+ return s;
+}
diff --git a/tests/common/test_common.h b/tests/common/test_common.h
index b9db8373..ed422ab4 100644
--- a/tests/common/test_common.h
+++ b/tests/common/test_common.h
@@ -4,7 +4,12 @@
#include <check.h>
+char *
+bin_to_hex(const char *input, int length);
+
Suite *make_suite_test_string(void);
Suite *make_suite_test_os_calls(void);
+Suite *make_suite_test_ssl_calls(void);
+Suite *make_suite_test_base64(void);
#endif /* TEST_COMMON_H */
diff --git a/tests/common/test_common_main.c b/tests/common/test_common_main.c
index 694a827a..a08bc7f7 100644
--- a/tests/common/test_common_main.c
+++ b/tests/common/test_common_main.c
@@ -4,9 +4,42 @@
#endif
#include <stdlib.h>
-#include <check.h>
+
+#include "log.h"
+#include "ssl_calls.h"
+
#include "test_common.h"
+/**
+ * Converts a binary buffer to a hexadecimal representation
+ *
+ * Result must be free'd after use
+ */
+char *
+bin_to_hex(const char *input, int length)
+{
+ int i;
+ char *result = (char *)malloc(length * 2 + 1);
+ if (result != NULL)
+ {
+ char *p = result;
+ const char *hexdigit = "0123456789abcdef";
+ for (i = 0 ; i < length ; ++i)
+ {
+ int c = input[i];
+ if (c < 0)
+ {
+ c += 256;
+ }
+ *p++ = hexdigit[ c / 16];
+ *p++ = hexdigit[ c % 16];
+ }
+ *p = '\0';
+ }
+
+ return result;
+}
+
int main (void)
{
int number_failed;
@@ -14,11 +47,25 @@ int main (void)
sr = srunner_create (make_suite_test_string());
srunner_add_suite(sr, make_suite_test_os_calls());
+ srunner_add_suite(sr, make_suite_test_ssl_calls());
+ srunner_add_suite(sr, make_suite_test_base64());
// srunner_add_suite(sr, make_list_suite());
srunner_set_tap(sr, "-");
+ /*
+ * Set up console logging */
+ struct log_config *lc = log_config_init_for_console(LOG_LEVEL_INFO, NULL);
+ log_start_from_param(lc);
+ log_config_free(lc);
+
+ /* Initialise the ssl module */
+ ssl_init();
+
srunner_run_all (sr, CK_ENV);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
+
+ ssl_finish();
+ log_end();
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/common/test_os_calls.c b/tests/common/test_os_calls.c
index 1c518e1d..ac785715 100644
--- a/tests/common/test_os_calls.c
+++ b/tests/common/test_os_calls.c
@@ -4,9 +4,10 @@
#endif
#include <stdlib.h>
-#include "test_common.h"
#include "os_calls.h"
+#include "test_common.h"
+
#ifndef TOP_SRCDIR
#define TOP_SRCDIR "."
#endif
diff --git a/tests/common/test_ssl_calls.c b/tests/common/test_ssl_calls.c
new file mode 100644
index 00000000..56d8935b
--- /dev/null
+++ b/tests/common/test_ssl_calls.c
@@ -0,0 +1,391 @@
+
+#if defined(HAVE_CONFIG_H)
+#include "config_ac.h"
+#endif
+
+#include "os_calls.h"
+#include "string_calls.h"
+#include "ssl_calls.h"
+
+#include "test_common.h"
+
+START_TEST(test_rc4_enc_ok)
+{
+ const char *key = "16_byte_key-----";
+ char text[] = "xrdp-test-suite-rc4-encryption";
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, key, g_strlen(key));
+ ssl_rc4_crypt(info, text, sizeof(text) - 1);
+ ssl_rc4_info_delete(info);
+ result = bin_to_hex(text, sizeof(text) - 1);
+ ck_assert(result != NULL);
+ /* Result should be the same as
+ * echo -n '<text>' | \
+ * openssl rc4 -K <hex-key> -e [-provider legacy] | \
+ * xxd -g0
+ *
+ * where <hex-key> is the string above in hexadecimal */
+ ck_assert_str_eq(result, "c080f175b2d85802dbf1042f07180ddc4be1d9bd4a44158f0aebf11c961b");
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_rc4_enc_tv0_ok)
+{
+ /*
+ * This is one of the 5 original RC4 test vectors posted in response to
+ * the 'RC4 Algorithm revealed' sci.crypt usenet posting */
+ unsigned char key[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ unsigned char text[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ const char *expected = "75b7878099e0c596";
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, (char *)key, sizeof(key));
+ ssl_rc4_crypt(info, (char *)text, sizeof(text));
+ ssl_rc4_info_delete(info);
+
+ result = bin_to_hex((char *)text, sizeof(text));
+ ck_assert(result != NULL);
+ ck_assert_str_eq(result, expected);
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_rc4_enc_tv1_ok)
+{
+ /*
+ * This is one of the 5 original RC4 test vectors posted in response to
+ * the 'RC4 Algorithm revealed' sci.crypt usenet posting */
+ unsigned char key[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ unsigned char text[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const char *expected = "7494c2e7104b0879";
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, (char *)key, sizeof(key));
+ ssl_rc4_crypt(info, (char *)text, sizeof(text));
+ ssl_rc4_info_delete(info);
+
+ result = bin_to_hex((char *)text, sizeof(text));
+ ck_assert(result != NULL);
+ ck_assert_str_eq(result, expected);
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_rc4_enc_tv2_ok)
+{
+ /*
+ * This is one of the 5 original RC4 test vectors posted in response to
+ * the 'RC4 Algorithm revealed' sci.crypt usenet posting */
+ unsigned char key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char text[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const char *expected = "de188941a3375d3a";
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, (char *)key, sizeof(key));
+ ssl_rc4_crypt(info, (char *)text, sizeof(text));
+ ssl_rc4_info_delete(info);
+
+ result = bin_to_hex((char *)text, sizeof(text));
+ ck_assert(result != NULL);
+ ck_assert_str_eq(result, expected);
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_rc4_enc_tv3_ok)
+{
+ /*
+ * This is one of the 5 original RC4 test vectors posted in response to
+ * the 'RC4 Algorithm revealed' sci.crypt usenet posting */
+ unsigned char key[] = {0xef, 0x01, 0x23, 0x45};
+ unsigned char text[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const char *expected = "d6a141a7ec3c38dfbd61";
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, (char *)key, sizeof(key));
+ ssl_rc4_crypt(info, (char *)text, sizeof(text));
+ ssl_rc4_info_delete(info);
+
+ result = bin_to_hex((char *)text, sizeof(text));
+ ck_assert(result != NULL);
+ ck_assert_str_eq(result, expected);
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_rc4_enc_tv4_ok)
+{
+ /*
+ * This is one of the 5 original RC4 test vectors posted in response to
+ * the 'RC4 Algorithm revealed' sci.crypt usenet posting */
+ unsigned char key[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ unsigned char text[] =
+ {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01
+ };
+ const char *expected =
+ "7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76533449b6778dca"
+ "d8c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b1b13b6"
+ "b919b847c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd3"
+ "77108f98fdcbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd"
+ "42a1bd311d7a4303dda5ab078896ae80c18b0af66dff319616eb784e495a"
+ "d2ce90d7f772a81747b65f62093b1e0db9e5ba532fafec47508323e67132"
+ "7df9444432cb7367cec82f5d44c0d00b67d650a075cd4b70dedd77eb9b10"
+ "231b6b5b741347396d62897421d43df9b42e446e358e9c11a9b2184ecbef"
+ "0cd8e7a877ef968f1390ec9b3d35a5585cb009290e2fcde7b5ec66d9084b"
+ "e44055a619d9dd7fc3166f9487f7cb272912426445998514c15d53a18c86"
+ "4ce3a2b7555793988126520eacf2e3066e230c91bee4dd5304f5fd0405b3"
+ "5bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1eaa595d8bfc0066ff8"
+ "d31509eb0c6caa006c807a623ef84c3d33c195d23ee320c40de0558157c8"
+ "22d4b8c569d849aed59d4e0fd7f379586b4b7ff684ed6a189f7486d49b9c"
+ "4bad9ba24b96abf924372c8a8fffb10d55354900a77a3db5f205e1b99fcd"
+ "8660863a159ad4abe40fa48934163ddde542a6585540fd683cbfd8c00f12"
+ "129a284deacc4cdefe58be7137541c047126c8d49e2755ab181ab7e940b0c0";
+
+ char *result;
+
+ void *info = ssl_rc4_info_create();
+ ssl_rc4_set_key(info, (char *)key, sizeof(key));
+ ssl_rc4_crypt(info, (char *)text, sizeof(text));
+ ssl_rc4_info_delete(info);
+
+ result = bin_to_hex((char *)text, sizeof(text));
+ ck_assert(result != NULL);
+ ck_assert_str_eq(result, expected);
+ g_free(result);
+}
+END_TEST
+
+START_TEST(test_sha1_hash_ok)
+{
+ const char *hash_string = "xrdp-test-suite-sha1-hash";
+ char digest[20];
+ char *result1;
+ char *result2;
+
+ void *info = ssl_sha1_info_create();
+ ssl_sha1_clear(info);
+ ssl_sha1_transform(info, hash_string, g_strlen(hash_string));
+ ssl_sha1_complete(info, digest);
+ result1 = bin_to_hex(digest, sizeof(digest));
+ ck_assert(result1 != NULL);
+ /* Check result with echo -n '<hash_string>' | sha1sum */
+ ck_assert_str_eq(result1, "3ea0ae84e97e6262c7cfe79ccd7ad2094c06885d");
+
+ /* Check a clear has the desired effect */
+ ssl_sha1_clear(info);
+ ssl_sha1_transform(info, hash_string, g_strlen(hash_string));
+ ssl_sha1_complete(info, digest);
+ result2 = bin_to_hex(digest, sizeof(digest));
+ ck_assert(result2 != NULL);
+ ck_assert_str_eq(result1, result2);
+
+ ssl_sha1_info_delete(info);
+ g_free(result1);
+ g_free(result2);
+}
+END_TEST
+
+START_TEST(test_md5_hash_ok)
+{
+ const char *hash_string = "xrdp-test-suite-md5-hash";
+ char digest[16];
+ char *result1;
+ char *result2;
+
+ void *info = ssl_md5_info_create();
+
+ ssl_md5_clear(info);
+ ssl_md5_transform(info, hash_string, g_strlen(hash_string));
+ ssl_md5_complete(info, digest);
+ result1 = bin_to_hex(digest, sizeof(digest));
+ ck_assert(result1 != NULL);
+ /* Check result with echo -n '<hash_string>' | md5sum */
+ ck_assert_str_eq(result1, "ddc599dc7ec62b8f78760b071704c007");
+
+ /* Check a clear has the desired effect */
+ ssl_md5_clear(info);
+ ssl_md5_transform(info, hash_string, g_strlen(hash_string));
+ ssl_md5_complete(info, digest);
+ result2 = bin_to_hex(digest, sizeof(digest));
+ ck_assert(result2 != NULL);
+ ck_assert_str_eq(result1, result2);
+
+ ssl_md5_info_delete(info);
+ g_free(result1);
+ g_free(result2);
+}
+END_TEST
+
+START_TEST(test_des3_enc_ok)
+{
+ const char *key = "24_byte_key-------------";
+ char plaintext[] = "xrdp-test-suite-des3-encryption-must-be-multiple-of-8-chars-long--------";
+ char ciphertext[sizeof(plaintext) - 1]; /* No terminator needed */
+ char plaintext2[sizeof(plaintext)];
+
+ char *result;
+
+ void *info = ssl_des3_encrypt_info_create(key, 0);
+ ssl_des3_encrypt(info, sizeof(plaintext) - 1, plaintext, ciphertext);
+ ssl_des3_info_delete(info);
+ result = bin_to_hex(ciphertext, sizeof(ciphertext));
+ ck_assert(result != NULL);
+ /* Result should be the same as
+ * echo -n '<text>' | \
+ * openssl des3 -iv 0000000000000000 -K <hex-key> -e -nopad | \
+ * od -t x1
+ *
+ * where <hex-key> is the string above in hexadecimal */
+ ck_assert_str_eq(result,
+ "856d70861827365e188781616e4f9dcc3009b2c5dc7785edcbc05fa825a4ea5e10b23735c0e971ca20f895f455b8845418963af6dd8e649719790eed6cbcee0fb97b743c60e32e8b");
+ g_free(result);
+
+ /* Let's go back again */
+ info = ssl_des3_decrypt_info_create(key, 0);
+ ssl_des3_decrypt(info, sizeof(ciphertext), ciphertext, plaintext2);
+ ssl_des3_info_delete(info);
+ plaintext2[sizeof(plaintext2) - 1] = '\0';
+
+ ck_assert_str_eq(plaintext, plaintext2);
+}
+END_TEST
+
+START_TEST(test_hmac_sha1_dgst_ok)
+{
+ const char *key = "20_byte_key---------";
+ const char *hash_string = "xrdp-test-suite-hmac-sha1-dgst";
+ char hmac[20];
+
+ char *result;
+
+ void *info = ssl_hmac_info_create();
+ ssl_hmac_sha1_init(info, key, g_strlen(key));
+ ssl_hmac_transform(info, hash_string, g_strlen(hash_string));
+ ssl_hmac_complete(info, hmac, sizeof(hmac));
+ ssl_hmac_info_delete(info);
+ result = bin_to_hex(hmac, sizeof(hmac));
+ ck_assert(result != NULL);
+ /* Result should be the same as
+ * echo -n '<text>' | openssl dgst -sha1 -hmac '<key>'
+ *
+ * or:-
+ *
+ * echo -n '<text>' | openssl mac -digest sha1 -macopt key:'<key>' hmac
+ */
+ ck_assert_str_eq(result, "af8c04e609e9f3cba53ad7815b60160dc69a9936");
+ g_free(result);
+
+}
+END_TEST
+
+START_TEST(test_gen_key_xrdp1)
+{
+#define RSA_TEST_BITS 2048
+ char modulus[RSA_TEST_BITS / 8] = {0};
+ char private_key[RSA_TEST_BITS / 8] = {0};
+ unsigned char exponent[4] =
+ {
+ 0x01, 0x00, 0x01, 0x00 /* 65537 in little-endian format */
+ };
+
+ /*
+ * We can't do much here because of the nature of the call, but we can
+ * at least check it completes without error */
+ int error;
+ error = ssl_gen_key_xrdp1(RSA_TEST_BITS,
+ (const char *)exponent, sizeof(exponent),
+ modulus, sizeof(modulus),
+ private_key, sizeof(private_key));
+ ck_assert(error == 0);
+
+ /* Both the modulus and the privatekey should be odd */
+ ck_assert((modulus[0] & 1) == 1);
+ ck_assert((private_key[0] & 1) == 1);
+#undef RSA_TEST_BITS
+}
+END_TEST
+
+/******************************************************************************/
+Suite *
+make_suite_test_ssl_calls(void)
+{
+ Suite *s;
+ TCase *tc_ssl_calls;
+
+ s = suite_create("SSL-Calls");
+
+ tc_ssl_calls = tcase_create("ssl_calls");
+ suite_add_tcase(s, tc_ssl_calls);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_ok);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_tv0_ok);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_tv1_ok);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_tv2_ok);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_tv3_ok);
+ tcase_add_test(tc_ssl_calls, test_rc4_enc_tv4_ok);
+ tcase_add_test(tc_ssl_calls, test_sha1_hash_ok);
+ tcase_add_test(tc_ssl_calls, test_md5_hash_ok);
+ tcase_add_test(tc_ssl_calls, test_des3_enc_ok);
+ tcase_add_test(tc_ssl_calls, test_hmac_sha1_dgst_ok);
+ tcase_add_test(tc_ssl_calls, test_gen_key_xrdp1);
+
+ return s;
+}
diff --git a/tests/common/test_string_calls.c b/tests/common/test_string_calls.c
index cd15c72f..1380357c 100644
--- a/tests/common/test_string_calls.c
+++ b/tests/common/test_string_calls.c
@@ -3,9 +3,10 @@
#include "config_ac.h"
#endif
-#include "test_common.h"
#include "string_calls.h"
+#include "test_common.h"
+
#define RESULT_LEN 1024
START_TEST(test_strnjoin__when_src_is_null__returns_empty_string)
@@ -323,6 +324,331 @@ START_TEST(test_bm2str__overflow_some_bits_undefined)
}
END_TEST
+START_TEST(test_str2bm__null_string)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask(NULL, bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__empty_string)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask("", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__null_bitdefs)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ rv = g_str_to_bitmask("BIT_0", NULL, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__null_delim)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask("BIT_0", bits, NULL, buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__null_buffer)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask("BIT_0", bits, ",", NULL, sizeof(buff));
+
+ ck_assert_str_eq(buff, "dummy");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__zero_buffer)
+{
+ int rv;
+ char buff[1];
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask("BIT_0", bits, ",", buff, 0);
+
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__zero_mask)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {0, "ZERO MASK"}, /* mask 0 should not be detected as end of list */
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0;
+ rv = g_str_to_bitmask("BIT_0", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__all_defined)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0 | 1 << 1;
+ rv = g_str_to_bitmask("BIT_0,BIT_1", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__no_defined)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 0;
+ rv = g_str_to_bitmask("BIT_2,BIT_3", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "BIT_2,BIT_3");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__some_defined)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ {1 << 2, "BIT_2"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 1;
+ rv = g_str_to_bitmask("a,BIT_1,b", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "a,b");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__trim_space)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ {1 << 2, "BIT_2"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
+ rv = g_str_to_bitmask("BIT_0 , BIT_1 , BIT_2", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__overflow_undefined)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ {1 << 2, "BIT_2"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 1;
+ rv = g_str_to_bitmask("123456789,BIT_1,abcdef", bits, ",", buff, sizeof(buff));
+
+ /* abcdef is not filled */
+ ck_assert_str_eq(buff, "123456789");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__delim_slash)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ {1 << 2, "BIT_2"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
+ rv = g_str_to_bitmask("BIT_0/BIT_1/BIT_2", bits, "/", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__no_delim)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ rv = g_str_to_bitmask("BIT_0,BIT_1", bits, "", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "BIT_0,BIT_1");
+ ck_assert_int_eq(rv, 0);
+}
+END_TEST
+
+START_TEST(test_str2bm__multiple_delim)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ {1 << 2, "BIT_2"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
+ rv = g_str_to_bitmask("BIT_0/BIT_1,BIT_2", bits, ",/", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__first_delim_is_semicolon)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ {1 << 1, "BIT_1"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 1;
+ rv = g_str_to_bitmask("a;b;BIT_1;c", bits, ";,", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "a;b;c");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
+START_TEST(test_str2bm__empty_token)
+{
+ int rv;
+ char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
+
+ static const struct bitmask_string bits[] =
+ {
+ {1 << 0, "BIT_0"},
+ BITMASK_STRING_END_OF_LIST
+ };
+
+ int bitmask = 1 << 0;
+ rv = g_str_to_bitmask(",BIT_0, ,", bits, ",", buff, sizeof(buff));
+
+ ck_assert_str_eq(buff, "");
+ ck_assert_int_eq(rv, bitmask);
+}
+END_TEST
+
/******************************************************************************/
START_TEST(test_strtrim__trim_left)
@@ -385,6 +711,7 @@ make_suite_test_string(void)
Suite *s;
TCase *tc_strnjoin;
TCase *tc_bm2str;
+ TCase *tc_str2bm;
TCase *tc_strtrim;
s = suite_create("String");
@@ -410,6 +737,25 @@ make_suite_test_string(void)
tcase_add_test(tc_bm2str, test_bm2str__some_bits_undefined);
tcase_add_test(tc_bm2str, test_bm2str__overflow_all_bits_defined);
tcase_add_test(tc_bm2str, test_bm2str__overflow_some_bits_undefined);
+ tc_str2bm = tcase_create("str2bm");
+ suite_add_tcase(s, tc_str2bm);
+ tcase_add_test(tc_str2bm, test_str2bm__null_string);
+ tcase_add_test(tc_str2bm, test_str2bm__empty_string);
+ tcase_add_test(tc_str2bm, test_str2bm__null_bitdefs);
+ tcase_add_test(tc_str2bm, test_str2bm__null_delim);
+ tcase_add_test(tc_str2bm, test_str2bm__null_buffer);
+ tcase_add_test(tc_str2bm, test_str2bm__zero_buffer);
+ tcase_add_test(tc_str2bm, test_str2bm__zero_mask);
+ tcase_add_test(tc_str2bm, test_str2bm__all_defined);
+ tcase_add_test(tc_str2bm, test_str2bm__no_defined);
+ tcase_add_test(tc_str2bm, test_str2bm__some_defined);
+ tcase_add_test(tc_str2bm, test_str2bm__trim_space);
+ tcase_add_test(tc_str2bm, test_str2bm__overflow_undefined);
+ tcase_add_test(tc_str2bm, test_str2bm__no_delim);
+ tcase_add_test(tc_str2bm, test_str2bm__delim_slash);
+ tcase_add_test(tc_str2bm, test_str2bm__multiple_delim);
+ tcase_add_test(tc_str2bm, test_str2bm__first_delim_is_semicolon);
+ tcase_add_test(tc_str2bm, test_str2bm__empty_token);
tc_strtrim = tcase_create("strtrim");
suite_add_tcase(s, tc_strtrim);
diff --git a/tests/libxrdp/Makefile.am b/tests/libxrdp/Makefile.am
index e98e8d9c..30138cbf 100644
--- a/tests/libxrdp/Makefile.am
+++ b/tests/libxrdp/Makefile.am
@@ -6,6 +6,8 @@ AM_CPPFLAGS = \
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
$(top_srcdir)/tap-driver.sh
+PACKAGE_STRING = "libxrdp"
+
TESTS = test_libxrdp
check_PROGRAMS = test_libxrdp
diff --git a/tests/libxrdp/test_monitor_processing.c b/tests/libxrdp/test_monitor_processing.c
index 969da780..951ffe68 100644
--- a/tests/libxrdp/test_monitor_processing.c
+++ b/tests/libxrdp/test_monitor_processing.c
@@ -2,10 +2,11 @@
#include "config_ac.h"
#endif
-#include "test_libxrdp.h"
#include "libxrdp.h"
#include "os_calls.h"
+#include "test_libxrdp.h"
+
struct xrdp_sec *sec_layer;
struct xrdp_rdp *rdp_layer;
struct xrdp_session *session;
diff --git a/tests/memtest/Makefile.am b/tests/memtest/Makefile.am
index 40669125..8660fc99 100644
--- a/tests/memtest/Makefile.am
+++ b/tests/memtest/Makefile.am
@@ -2,6 +2,8 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/common
+PACKAGE_STRING = "memtest"
+
check_PROGRAMS = \
memtest
diff --git a/tests/xrdp/test_bitmap_load.c b/tests/xrdp/test_bitmap_load.c
index 42b5a325..5c25504e 100644
--- a/tests/xrdp/test_bitmap_load.c
+++ b/tests/xrdp/test_bitmap_load.c
@@ -2,9 +2,10 @@
#include "config_ac.h"
#endif
-#include "test_xrdp.h"
#include "xrdp.h"
+#include "test_xrdp.h"
+
/* Where the image files are located */
#ifndef IMAGEDIR
#define IMAGEDIR "."
diff --git a/tests/xrdp/test_xrdp_main.c b/tests/xrdp/test_xrdp_main.c
index eb118a1e..d56dcb37 100644
--- a/tests/xrdp/test_xrdp_main.c
+++ b/tests/xrdp/test_xrdp_main.c
@@ -33,9 +33,10 @@
#include "log.h"
#include "os_calls.h"
-#include "test_xrdp.h"
#include <stdlib.h>
+#include "test_xrdp.h"
+
int main (void)
{
int number_failed;
diff --git a/vnc/vnc.c b/vnc/vnc.c
index 81e5ecd0..74861329 100644
--- a/vnc/vnc.c
+++ b/vnc/vnc.c
@@ -94,6 +94,7 @@ rfbHashEncryptBytes(char *bytes, const char *passwd)
/* create password hash from password */
passwd_bytes = g_strlen(passwd);
sha1 = ssl_sha1_info_create();
+ ssl_sha1_clear(sha1);
ssl_sha1_transform(sha1, "xrdp_vnc", 8);
ssl_sha1_transform(sha1, passwd, passwd_bytes);
ssl_sha1_transform(sha1, passwd, passwd_bytes);
diff --git a/vnc/vnc_clip.c b/vnc/vnc_clip.c
index ebbfae36..364bdff7 100644
--- a/vnc/vnc_clip.c
+++ b/vnc/vnc_clip.c
@@ -575,7 +575,7 @@ handle_cb_format_data_response(struct vnc *v, struct stream *s)
{
case CF_TEXT:
lastc = '\0';
- while (s_check(s))
+ while (s_check_rem(s, 1))
{
in_uint8(s, c);
if (c == '\n' && lastc == '\r')
diff --git a/xrdp/xrdp.c b/xrdp/xrdp.c
index ecaa9983..e91672fb 100644
--- a/xrdp/xrdp.c
+++ b/xrdp/xrdp.c
@@ -163,9 +163,7 @@ xrdp_shutdown(int sig)
static void
xrdp_child(int sig)
{
- int safety;
-
- for (safety = 0; (g_waitchild() >= 0) && (safety <= 10); safety++)
+ while (g_waitchild() > 0)
{
}
}
@@ -540,7 +538,7 @@ main(int argc, char **argv)
/* starting logging subsystem */
error = log_start(startup_params.xrdp_ini, "xrdp",
- startup_params.dump_config);
+ (startup_params.dump_config) ? LOG_START_DUMP_CONFIG : 0);
if (error != LOG_STARTUP_OK)
{
diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c
index efab0621..72aafff2 100644
--- a/xrdp/xrdp_bitmap.c
+++ b/xrdp/xrdp_bitmap.c
@@ -174,6 +174,7 @@ xrdp_bitmap_hash_crc(struct xrdp_bitmap *self)
return 1;
}
hash = ssl_md5_info_create();
+ ssl_md5_clear(hash);
ssl_md5_transform(hash, self->data, bytes);
ssl_md5_complete(hash, hash_data);
ssl_md5_info_delete(hash);
diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c
index a1d7e9a5..da5917b2 100644
--- a/xrdp/xrdp_login_wnd.c
+++ b/xrdp/xrdp_login_wnd.c
@@ -346,6 +346,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
struct xrdp_cfg_globals *globals;
char resultIP[256];
char *plain; /* base64 decoded string */
+ size_t plain_length; /* length of decoded base64 string */
size_t base64_length; /* length of base64 string */
globals = &self->xrdp_config->cfg_globals;
@@ -379,8 +380,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
{
base64_length = g_strlen(value + BASE64PREFIX_LEN);
plain = (char *)g_malloc(base64_length, 0);
- base64_decode(plain, value + BASE64PREFIX_LEN, base64_length);
- g_strncpy(value, plain, g_strlen(plain));
+ base64_decode(value + BASE64PREFIX_LEN,
+ plain, base64_length, &plain_length);
+ g_strncpy(value, plain, plain_length);
g_free(plain);
}
else if (g_strncmp(ASK, value, ASK_LEN) == 0)
@@ -421,7 +423,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
{
base64_length = g_strlen(value + ASK_LEN + BASE64PREFIX_LEN);
plain = (char *)g_malloc(base64_length, 0);
- base64_decode(plain, value + ASK_LEN + BASE64PREFIX_LEN, base64_length);
+ base64_decode(value + ASK_LEN + BASE64PREFIX_LEN,
+ plain, base64_length, &plain_length);
+ plain[plain_length] = '\0';
g_strncpy(b->caption1, plain, 255);
g_free(plain);
}