diff --git a/SECURITY.md b/SECURITY.md index ae407850..2fec6a31 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,6 +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/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 fa7df6bf..7aaee159 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -159,6 +159,9 @@ struct xrdp_client_info int use_cache_glyph_v2; int rail_enable; int suppress_output; + + int enable_token_login; + char domain_user_separator[16]; }; #endif 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. diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 7950840c..9167eaf1 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) @@ -276,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 4ce0d509..7317c639 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); @@ -737,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; } @@ -759,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; } @@ -771,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; } @@ -783,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; } @@ -795,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; } @@ -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,14 @@ 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 f882afd9..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 @@ -76,6 +80,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 */