From 851bed680c35f0ca5fa7228d7c46791ee211bfc5 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 8 Sep 2022 15:10:37 +0100 Subject: [PATCH] Update sesman tools for new interfaces The sesman tools sesrun and sesadmin now use the separate authentication/authorization (AA) interface introduced to sesman by the previous comment. sesrun can use either password or UDS authentication. With some limitations, this can allow for automatic creation of sessions for local users without a password being needed. sesadmin now operates using UDS logins only and so a username and password are not required. To use sesadmin for another user, use su/sudo/doas to authenticate as the other user. --- docs/man/xrdp-sesadmin.8.in | 8 +- docs/man/xrdp-sesrun.8.in | 24 ++++- sesman/tools/sesadmin.c | 92 +++++++++--------- sesman/tools/sesrun.c | 180 ++++++++++++++++++++++++++++-------- 4 files changed, 213 insertions(+), 91 deletions(-) diff --git a/docs/man/xrdp-sesadmin.8.in b/docs/man/xrdp-sesadmin.8.in index 6727772b..953f3f67 100644 --- a/docs/man/xrdp-sesadmin.8.in +++ b/docs/man/xrdp-sesadmin.8.in @@ -18,13 +18,11 @@ command. A summary of options is included below. .TP .BI \-u= username -\fIUsername\fP for authentication on the server. -Defaults to \fBroot\fP. +Retained for compatibility, but ignored. .TP .BI \-p= password -The \fIpassword\fP to authenticate with. -The default is to ask for the password interactively. +Retained for compatibility, but ignored. .TP .BI \-i= port @@ -39,7 +37,7 @@ Valid commands are: .RS 4 .TP .B list -List currently active sessions. +List active sessions for the current user. .TP .BI kill: sid Kills the session specified the given \fIsession id\fP. diff --git a/docs/man/xrdp-sesrun.8.in b/docs/man/xrdp-sesrun.8.in index 256c4f7a..96585ece 100644 --- a/docs/man/xrdp-sesrun.8.in +++ b/docs/man/xrdp-sesrun.8.in @@ -4,18 +4,28 @@ .SH "SYNTAX" .B xrdp\-sesrun -.I [ options ] username +.I --help +.br + +.B xrdp\-sesrun +.I [ options ] [ username ] .SH "DESCRIPTION" \fBxrdp\-sesrun\fR starts a session using \fBxrdp\-sesman\fR(8). .br -This is a tool useful for testing, it simply behaves like xrdp when some +This is a tool useful for testing. It simply behaves like xrdp when some user logs in a new session and authenticates, thus starting a new session. -Default values for the options are set at compile-time. Run the utility without -a username to see what the defaults are for your installation. +Default values for the options are set at compile-time. Run the utility with +the '--help' option to see what the defaults are for your installation. -The utility prompts for a password if neither \fB-p\fR or \fB-F\fR is used. +If no username is used, the current username is used, and no password +needs to be provided. In this instance, it is important that any necessary +authentication tokens for a GUI session (e.g. a Kerberos ticket) have +already been acquired. + +If a username is provided, a password must also be provided. In this instance +the utility prompts for a password if neither \fB-p\fR or \fB-F\fR is used. .SH "OPTIONS" .TP @@ -60,6 +70,10 @@ Override the default logging level. One of "error", "warn", "info", .SH "EXAMPLES" .TP .B +xrdp-sesrun +Create a default session for the current user. +.TP +.B xrdp-sesrun -F 0 user1 #include -char user[257]; -char pass[257]; char cmnd[257]; char port[257]; @@ -47,12 +45,9 @@ int main(int argc, char **argv) //int end; int idx; //int sel; - char *pwd; struct log_config *logging; int rv = 1; - user[0] = '\0'; - pass[0] = '\0'; cmnd[0] = '\0'; port[0] = '\0'; @@ -64,11 +59,11 @@ int main(int argc, char **argv) { if (0 == g_strncmp(argv[idx], "-u=", 3)) { - g_strncpy(user, (argv[idx]) + 3, 256); + g_printf("** Ignoring unused argument '-u'"); } else if (0 == g_strncmp(argv[idx], "-p=", 3)) { - g_strncpy(pass, (argv[idx]) + 3, 256); + g_printf("** Ignoring unused argument '-p'"); } else if (0 == g_strncmp(argv[idx], "-i=", 3)) { @@ -80,48 +75,57 @@ int main(int argc, char **argv) } } - if (0 == g_strncmp(port, "", 1)) - { - g_strncpy(port, "3350", 256); - } - - if (0 == g_strncmp(user, "", 1)) - { - cmndHelp(); - return 0; - } - if (0 == g_strncmp(cmnd, "", 1)) { cmndHelp(); return 0; } - if (0 == g_strncmp(pass, "", 1)) - { - pwd = getpass("password:"); - g_strncpy(pass, pwd, 256); - - } - - t = scp_connect(port, NULL); - + t = scp_connect(port, "xrdp-sesadmin", NULL); if (t == NULL) { LOG(LOG_LEVEL_ERROR, "scp_connect() error"); } - else if (0 == g_strncmp(cmnd, "list", 5)) + else { - rv = cmndList(t); - } - else if (0 == g_strncmp(cmnd, "kill:", 5)) - { - rv = cmndKill(t); + enum scp_login_status login_result; + + /* Log in as the current user */ + if ((rv = scp_send_uds_login_request(t)) == 0 && + (rv = wait_for_sesman_reply(t, E_SCP_LOGIN_RESPONSE)) == 0) + { + rv = scp_get_login_response(t, &login_result, NULL); + if (rv == 0) + { + if (login_result != E_SCP_LOGIN_OK) + { + char msg[256]; + scp_login_status_to_str(login_result, msg, sizeof(msg)); + g_printf("Login failed; %s\n", msg); + rv = 1; + } + } + scp_msg_in_reset(t); // Done with this message + } } - g_memset(pass, '\0', sizeof(pass)); + if (rv == 0) + { + if (0 == g_strncmp(cmnd, "list", 5)) + { + rv = cmndList(t); + } + else if (0 == g_strncmp(cmnd, "kill:", 5)) + { + rv = cmndKill(t); + } + } + if (rv == 0) + { + rv = scp_send_close_connection_request(t); + } trans_delete(t); log_end(); @@ -133,10 +137,7 @@ cmndHelp(void) { fprintf(stderr, "sesadmin - a console sesman administration tool\n"); fprintf(stderr, "syntax: sesadmin [] COMMAND [OPTIONS]\n\n"); - fprintf(stderr, "-u=: username to connect to sesman [MANDATORY]\n"); - fprintf(stderr, "-p=: password to connect to sesman (asked if not given)\n"); - fprintf(stderr, "-s=: sesman host (default is localhost)\n"); - fprintf(stderr, "-i= : sesman port (default 3350)\n"); + fprintf(stderr, "-i= : sesman port (can be defaulted)\n"); fprintf(stderr, "-c= : command to execute on the server [MANDATORY]\n"); fprintf(stderr, " it can be one of those:\n"); fprintf(stderr, " list\n"); @@ -146,9 +147,14 @@ cmndHelp(void) static void print_session(const struct scp_session_info *s) { + char *username; + const char *uptr; + g_getuser_info_by_uid(s->uid, &username, NULL, NULL, NULL, NULL); + uptr = (username == NULL) ? "" : username; + printf("Session ID: %d\n", s->sid); printf("\tDisplay: :%u\n", s->display); - printf("\tUser: %s\n", s->username); + printf("\tUser: %s\n", uptr); printf("\tSession type: %s\n", SCP_SESSION_TYPE_TO_STR(s->type)); printf("\tScreen size: %dx%d, color depth %d\n", s->width, s->height, s->bpp); @@ -157,6 +163,7 @@ print_session(const struct scp_session_info *s) { printf("\tStart IP address: %s\n", s->start_ip_addr); } + g_free(username); } static int @@ -168,7 +175,7 @@ cmndList(struct trans *t) enum scp_list_sessions_status status; struct scp_session_info *p; - int rv = scp_send_list_sessions_request(t, user, pass); + int rv = scp_send_list_sessions_request(t); sessions->auto_free = 1; @@ -188,11 +195,6 @@ cmndList(struct trans *t) switch (status) { - case E_SCP_LS_AUTHENTICATION_FAIL: - printf("Connection denied (authentication error)\n"); - rv = 1; - break; - case E_SCP_LS_SESSION_INFO: list_add_item(sessions, (tintptr)p); break; diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index b785f5d0..dc2d0c82 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -94,7 +94,7 @@ struct session_params const char *directory; const char *shell; - const char *connection_description; + const char *ip_addr; const char *username; char password[MAX_PASSWORD_LEN + 1]; @@ -165,7 +165,9 @@ usage(void) g_printf("xrdp session starter v" PACKAGE_VERSION "\n"); g_printf("\nusage:\n"); - g_printf("sesrun [options] username\n\n"); + g_printf("sesrun --help\n" + "\nor\n" + "sesrun [options] [username]\n\n"); g_printf("options:\n"); g_printf(" -g Default:%dx%d\n", DEFAULT_WIDTH, DEFAULT_HEIGHT); @@ -176,9 +178,11 @@ usage(void) " -p TESTING ONLY - DO NOT USE IN PRODUCTION\n" " -F Read password from this file descriptor\n" " -c Alternative sesman.ini file\n"); - g_printf("Supported types are %s\n", + g_printf("\nSupported types are %s\n", sesstype_list); - g_printf("Password is prompted if -p or -F are not specified\n"); + g_printf("\nIf username is omitted, the current user is used.\n" + "If username is provided, password is needed.\n" + " Password is prompted for if -p or -F are not specified\n"); } @@ -286,7 +290,7 @@ parse_program_args(int argc, char *argv[], struct session_params *sp, sp->directory = ""; sp->shell = ""; - sp->connection_description = ""; + sp->ip_addr = ""; sp->username = NULL; sp->password[0] = '\0'; @@ -367,33 +371,109 @@ parse_program_args(int argc, char *argv[], struct session_params *sp, } } - if (argc <= optind) + if (argc == optind) { - LOG(LOG_LEVEL_ERROR, "No user name specified"); - params_ok = 0; + // No username was specified + if (password_set) + { + LOG(LOG_LEVEL_WARNING, "No username - ignoring specified password"); + sp->password[0] = '\0'; + } + sp->username = NULL; } else if ((argc - optind) > 1) { LOG(LOG_LEVEL_ERROR, "Unexpected arguments after username"); params_ok = 0; } - else + else if (params_ok) { + // A username is specified sp->username = argv[optind]; - } - - if (params_ok && !password_set) - { - const char *p = getpass("Password: "); - if (p != NULL) + if (!password_set) { - g_strcpy(sp->password, p); + const char *p = getpass("Password: "); + if (p == NULL) + { + params_ok = 0; + } + else + { + g_snprintf(sp->password, sizeof(sp->password), "%s", p); + } } } return params_ok; } +/**************************************************************************//** + * Sends an SCP login request + * + * A sys login request (i.e. username / password) is used if a username + * is specified. Otherwise we use a uds login request for the current user. + * + * @param t SCP connection + * @param sp Data for request + */ +static int +send_login_request(struct trans *t, const struct session_params *sp) +{ + int rv; + LOG(LOG_LEVEL_DEBUG, "ip_addr:\"%s\"", sp->ip_addr); + if (sp->username != NULL) + { + /* Only log the password in development builds */ + LOG_DEVEL(LOG_LEVEL_DEBUG, "password:\"%s\"", sp->password); + + rv = scp_send_sys_login_request(t, sp->username, + sp->password, sp->ip_addr); + } + else + { + rv = scp_send_uds_login_request(t); + } + + return rv; +} + +/**************************************************************************//** + * Receives an SCP login response + * + * @param t SCP transport to receive reply on + * @param[out] server_closed != 0 if server has gone away + * @return 0 for successful authentication + */ +static int +handle_login_response(struct trans *t, int *server_closed) +{ + enum scp_login_status login_result; + + int rv = wait_for_sesman_reply(t, E_SCP_LOGIN_RESPONSE); + if (rv != 0) + { + *server_closed = 1; + } + else + { + rv = scp_get_login_response(t, &login_result, server_closed); + if (rv == 0) + { + if (login_result != E_SCP_LOGIN_OK) + { + char msg[256]; + scp_login_status_to_str(login_result, msg, sizeof(msg)); + g_printf("Login failed; %s\n", msg); + rv = 1; + } + } + scp_msg_in_reset(t); // Done with this message + } + + return rv; +} + + /**************************************************************************//** * Sends an SCP create session request * @@ -405,18 +485,13 @@ send_create_session_request(struct trans *t, const struct session_params *sp) { LOG(LOG_LEVEL_DEBUG, "width:%d height:%d bpp:%d code:%d\n" - "directory:\"%s\"\n" - "shell:\"%s\" connection_description:\"%s\"", + "directory:\"%s\" shell:\"%s\"", sp->width, sp->height, sp->bpp, sp->session_type, - sp->directory, - sp->shell, sp->connection_description); - /* Only log the password in development builds */ - LOG_DEVEL(LOG_LEVEL_DEBUG, "password:\"%s\"", sp->password); + sp->directory, sp->shell); return scp_send_create_session_request( - t, sp->username, sp->password, sp->session_type, - sp->width, sp->height, sp->bpp, sp->shell, sp->directory, - sp->connection_description); + t, sp->session_type, + sp->width, sp->height, sp->bpp, sp->shell, sp->directory); } /**************************************************************************//** @@ -428,21 +503,24 @@ send_create_session_request(struct trans *t, const struct session_params *sp) static int handle_create_session_response(struct trans *t) { - int auth_result; + enum scp_screate_status status; int display; struct guid guid; int rv = wait_for_sesman_reply(t, E_SCP_CREATE_SESSION_RESPONSE); if (rv == 0) { - rv = scp_get_create_session_response(t, &auth_result, + rv = scp_get_create_session_response(t, &status, &display, &guid); if (rv == 0) { - if (auth_result != 0) + if (status != E_SCP_SCREATE_OK) { - g_printf("Connection denied (authentication error)\n"); + char msg[256]; + scp_screate_status_to_str(status, msg, sizeof(msg)); + g_printf("Connection failed; %s\n", msg); + rv = 1; } else { @@ -452,6 +530,7 @@ handle_create_session_response(struct trans *t) guid_to_str(&guid, guid_str)); } } + scp_msg_in_reset(t); // Done with this message } return rv; @@ -475,7 +554,12 @@ main(int argc, char **argv) log_start_from_param(logging); log_config_free(logging); - if (!parse_program_args(argc, argv, &sp, &sesman_ini)) + if (argc == 2 && g_strcmp(argv[1], "--help") == 0) + { + usage(); + rv = 0; + } + else if (!parse_program_args(argc, argv, &sp, &sesman_ini)) { usage(); } @@ -484,20 +568,44 @@ main(int argc, char **argv) LOG(LOG_LEVEL_ERROR, "error reading config file %s : %s", sesman_ini, g_get_strerror()); } - else if (!(t = scp_connect(cfg->listen_port, NULL))) + else if (!(t = scp_connect(cfg->listen_port, "xrdp-sesrun", NULL))) { LOG(LOG_LEVEL_ERROR, "connect error - %s", g_get_strerror()); } else { - rv = send_create_session_request(t, &sp); - if (rv != 0) + int server_closed = 0; + while (!server_closed) { - LOG(LOG_LEVEL_ERROR, "Error sending create session to sesman"); + rv = send_login_request(t, &sp); + if (rv != 0) + { + LOG(LOG_LEVEL_ERROR, "Error sending login request to sesman"); + break; + } + + rv = handle_login_response(t, &server_closed); + if (rv == 0) + { + break; /* Successful authentication */ + } + if (!server_closed) + { + const char *p = getpass("Password: "); + if (p == NULL) + { + break; + } + g_snprintf(sp.password, sizeof(sp.password), "%s", p); + } } - else + + if (rv == 0) { - rv = handle_create_session_response(t); + if ((rv = send_create_session_request(t, &sp)) == 0) + { + rv = handle_create_session_response(t); + } } trans_delete(t); }