From b0bca1363e9ec9338c805efbcd100b79d10da296 Mon Sep 17 00:00:00 2001 From: Bolke de Bruin Date: Mon, 17 Aug 2020 08:52:17 +0200 Subject: [PATCH 1/3] Add support for token authentication This feature allows to embed a token in the username field. Tokens are separated from the username by the ASCII field separator character 0x1F (unicode 0x001F). --- SECURITY.md | 1 + common/xrdp_client_info.h | 2 ++ libxrdp/xrdp_rdp.c | 4 ++++ libxrdp/xrdp_sec.c | 14 +++++++++++++- xrdp/xrdp.ini.in | 2 ++ xrdp/xrdp_login_wnd.c | 8 +++++++- xrdp/xrdp_types.h | 1 + 7 files changed, 30 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index ae407850..f7416710 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,3 +12,4 @@ as possible. Our email eddress for security report is: * [xrdp-core@googlegroups.com](mailto:xrdp-core@googlegroups.com) + diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index fa7df6bf..3c43f34f 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -159,6 +159,8 @@ struct xrdp_client_info int use_cache_glyph_v2; int rail_enable; int suppress_output; + + int enable_token_login; }; #endif diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 7950840c..629dd88b 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -144,6 +144,10 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) { client_info->require_credentials = g_text2bool(value); } + else if (g_strcasecmp(item, "enable_token_login") == 0) + { + client_info->enable_token_login = g_text2bool(value); + } else if (g_strcasecmp(item, "use_fastpath") == 0) { if (g_strcasecmp(value, "output") == 0) diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 4ce0d509..fde6f110 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -675,6 +675,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) int len_ip = 0; int len_dll = 0; char tmpdata[256]; + const char *sep; /* initialize (zero out) local variables */ g_memset(tmpdata, 0, sizeof(char) * 256); @@ -808,7 +809,6 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) { return 1; } - DEBUG(("username %s", self->rdp_layer->client_info.username)); if (flags & RDP_LOGON_AUTO) { @@ -818,6 +818,17 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) } DEBUG(("flag RDP_LOGON_AUTO found")); } + else if (self->rdp_layer->client_info.enable_token_login + && len_user > 0 + && len_password == 0 + && (sep = g_strchr(self->rdp_layer->client_info.username, '\x1f')) != NULL) + { + DEBUG(("Logon token detected")); + g_strncpy(self->rdp_layer->client_info.password, sep + 1, + sizeof(self->rdp_layer->client_info.password) - 1); + self->rdp_layer->client_info.username[sep - self->rdp_layer->client_info.username] = '\0'; + self->rdp_layer->client_info.rdp_autologin = 1; + } else { if (!s_check_rem(s, len_password + 2)) @@ -831,6 +842,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; /* credentials on cmd line is mandatory */ } } + DEBUG(("username %s", self->rdp_layer->client_info.username)); if (unicode_utf16_in(s, len_program, self->rdp_layer->client_info.program, sizeof(self->rdp_layer->client_info.program) - 1) != 0) { diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index f882afd9..b66768f2 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -76,6 +76,8 @@ new_cursors=true use_fastpath=both ; when true, userid/password *must* be passed on cmd line #require_credentials=true +; when true, the userid will be used to try to authenticate +#enable_token_login=true ; You can set the PAM error text in a gateway setup (MAX 256 chars) #pamerrortxt=change your password according to policy at http://url diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index c09f8002..719eeb53 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -1001,6 +1001,11 @@ load_xrdp_config(struct xrdp_config *config, int bpp) else if (g_strncmp(n, "allow_multimon", 64) == 0) globals->allow_multimon = g_text2bool(v); + else if (g_strncmp(n, "enable_token_login", 64) == 0) { + log_message(LOG_LEVEL_DEBUG, "Token login detection enabled x"); + globals->enable_token_login = g_text2bool(v); + } + /* login screen values */ else if (g_strncmp(n, "ls_top_window_bg_color", 64) == 0) globals->ls_top_window_bg_color = HCOLOR(bpp, xrdp_wm_htoi(v)); @@ -1109,12 +1114,13 @@ load_xrdp_config(struct xrdp_config *config, int bpp) g_writeln("new_cursors: %d", globals->new_cursors); g_writeln("nego_sec_layer: %d", globals->nego_sec_layer); g_writeln("allow_multimon: %d", globals->allow_multimon); + g_writeln("enable_token_login: %d", globals->enable_token_login) g_writeln("ls_top_window_bg_color: %x", globals->ls_top_window_bg_color); g_writeln("ls_width: %d", globals->ls_width); g_writeln("ls_height: %d", globals->ls_height); g_writeln("ls_bg_color: %x", globals->ls_bg_color); - g_writeln("ls_title: %s", globals->ls_title); + g_writeln("ls_title: %s", globals->ls_title); g_writeln("ls_logo_filename: %s", globals->ls_logo_filename); g_writeln("ls_logo_x_pos: %d", globals->ls_logo_x_pos); g_writeln("ls_logo_y_pos: %d", globals->ls_logo_y_pos); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index b0c8b559..6faecd9e 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -566,6 +566,7 @@ struct xrdp_cfg_globals int new_cursors; int nego_sec_layer; int allow_multimon; + int enable_token_login; /* colors */ From a6a0e5e004dad5166b6b9b42bba7653ba363a40e Mon Sep 17 00:00:00 2001 From: Bolke de Bruin Date: Sun, 30 Aug 2020 21:20:21 +0200 Subject: [PATCH 2/3] Allow domain name to be concatenated to username If a server is multihomed (i.e. mutiple domains) the users are identified by their domain name. This change allows to concat the domain name to the username with a specific separator. --- common/os_calls.c | 13 +++++++++++++ common/os_calls.h | 1 + common/xrdp_client_info.h | 1 + libxrdp/xrdp_rdp.c | 6 +++++- libxrdp/xrdp_sec.c | 17 ++++++++++++----- xrdp/xrdp.ini.in | 4 ++++ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index 463af84c..5ed7db12 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -2590,6 +2590,19 @@ g_strcat(char *dest, const char *src) return strcat(dest, src); } +/*****************************************************************************/ +/* returns dest */ +char * +g_strncat(char *dest, const char *src, int len) +{ + if (dest == 0 || src == 0) + { + return dest; + } + + return strncat(dest, src, len); +} + /*****************************************************************************/ /* if in = 0, return 0 else return newly alloced copy of in */ char * diff --git a/common/os_calls.h b/common/os_calls.h index b52a84df..0245f0b9 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -124,6 +124,7 @@ const char *g_strchr(const char *text, int c); char* g_strcpy(char* dest, const char* src); char* g_strncpy(char* dest, const char* src, int len); char* g_strcat(char* dest, const char* src); +char* g_strncat(char* dest, const char* src, int len); char* g_strdup(const char* in); char* g_strndup(const char* in, const unsigned int maxlen); int g_strcmp(const char* c1, const char* c2); diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 3c43f34f..7aaee159 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -161,6 +161,7 @@ struct xrdp_client_info int suppress_output; int enable_token_login; + char domain_user_separator[16]; }; #endif diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 629dd88b..9167eaf1 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -280,7 +280,11 @@ xrdp_rdp_read_config(struct xrdp_client_info *client_info) client_info->key_file, g_get_strerror()); } } - + else if (g_strcasecmp(item, "domain_user_separator") == 0 + && g_strlen(value) > 0) + { + g_strncpy(client_info->domain_user_separator, value, sizeof(client_info->domain_user_separator) - 1); + } } list_delete(items); diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index fde6f110..7317c639 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -738,7 +738,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) if (len_domain >= INFO_CLIENT_MAX_CB_LEN) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain > 511")); + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain >= %d", INFO_CLIENT_MAX_CB_LEN)); return 1; } @@ -760,7 +760,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) if (len_user >= INFO_CLIENT_MAX_CB_LEN) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user > 511")); + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user >= %d", INFO_CLIENT_MAX_CB_LEN)); return 1; } @@ -772,7 +772,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) if (len_password >= INFO_CLIENT_MAX_CB_LEN) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password > 511")); + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password >= %d", INFO_CLIENT_MAX_CB_LEN)); return 1; } @@ -784,7 +784,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) if (len_program >= INFO_CLIENT_MAX_CB_LEN) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program > 511")); + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program >= %d", INFO_CLIENT_MAX_CB_LEN)); return 1; } @@ -796,7 +796,7 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) if (len_directory >= INFO_CLIENT_MAX_CB_LEN) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory > 511")); + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory >= %d", INFO_CLIENT_MAX_CB_LEN)); return 1; } @@ -842,6 +842,13 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) return 1; /* credentials on cmd line is mandatory */ } } + if (self->rdp_layer->client_info.domain_user_separator[0] != '\0' + && self->rdp_layer->client_info.domain[0] != '\0') + { + int size = sizeof(self->rdp_layer->client_info.username); + g_strncat(self->rdp_layer->client_info.username, self->rdp_layer->client_info.domain_user_separator, size - 1 - g_strlen(self->rdp_layer->client_info.domain_user_separator)); + g_strncat(self->rdp_layer->client_info.username, self->rdp_layer->client_info.domain, size - 1 - g_strlen(self->rdp_layer->client_info.domain)); + } DEBUG(("username %s", self->rdp_layer->client_info.username)); if (unicode_utf16_in(s, len_program, self->rdp_layer->client_info.program, sizeof(self->rdp_layer->client_info.program) - 1) != 0) diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index b66768f2..94b9d8b0 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -58,6 +58,10 @@ ssl_protocols=TLSv1.2, TLSv1.3 ; set TLS cipher suites #tls_ciphers=HIGH +; concats the domain name to the user if set for authentication with the separator +; for example when the server is multi homed with SSSd +#domain_user_separator=@ + ; Section name to use for automatic login if the client sends username ; and password. If empty, the domain name sent by the client is used. ; If empty and no domain name is given, the first suitable section in From 0b82f193180b62b94915bdd536915bfc1bfefb69 Mon Sep 17 00:00:00 2001 From: Bolke de Bruin Date: Wed, 9 Sep 2020 09:12:19 +0200 Subject: [PATCH 3/3] Improve documentation --- SECURITY.md | 3 ++- docs/man/xrdp.ini.5.in | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index f7416710..2fec6a31 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,7 +9,8 @@ If you find a security vulnerability please kindly inform us about the problem i so that we can fix the security problem to protect a lot of users around the world as soon as possible. -Our email eddress for security report is: +Our email address for security report is below. This is a private mailing list and not open +for public viewing. * [xrdp-core@googlegroups.com](mailto:xrdp-core@googlegroups.com) diff --git a/docs/man/xrdp.ini.5.in b/docs/man/xrdp.ini.5.in index d7bce514..daa62afd 100644 --- a/docs/man/xrdp.ini.5.in +++ b/docs/man/xrdp.ini.5.in @@ -120,6 +120,18 @@ The default for RDP is \fB3389\fP. .TP \fBrequire_credentials\fP=\fI[true|false]\fP +If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP will scan the user name provided by the +client for the ASCII field separator character (0x1F). It will then copy over what is after the +separator as the password supplied by the user and treats it as autologon. If not specified, +defaults to \fBfalse\fP. + +.TP +\domain_user_separator\fP=\separator\fP +If specified the domain name supplied by the client is appended to the username separated +by \fBseparator\fP. + +.TP +\enable_token_login\fP=\fI[true|false]\fP If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients to include username and password initial connection phase. In other words, xrdp doesn't allow clients to show login screen if set to true. If not specified, defaults to \fBfalse\fP.