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.
This commit is contained in:
matt335672 2022-09-08 15:10:37 +01:00
parent fd99653957
commit 851bed680c
4 changed files with 213 additions and 91 deletions

View File

@ -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.

View File

@ -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 <passwd.txt
Create a default session for user \fBuser1\fR with a password from
a file

View File

@ -31,8 +31,6 @@
#include <stdio.h>
#include <unistd.h>
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>: username to connect to sesman [MANDATORY]\n");
fprintf(stderr, "-p=<password>: password to connect to sesman (asked if not given)\n");
fprintf(stderr, "-s=<hostname>: sesman host (default is localhost)\n");
fprintf(stderr, "-i=<port> : sesman port (default 3350)\n");
fprintf(stderr, "-i=<port> : sesman port (can be defaulted)\n");
fprintf(stderr, "-c=<command> : 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) ? "<unknown>" : 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;

View File

@ -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 <geometry> Default:%dx%d\n",
DEFAULT_WIDTH, DEFAULT_HEIGHT);
@ -176,9 +178,11 @@ usage(void)
" -p <password> TESTING ONLY - DO NOT USE IN PRODUCTION\n"
" -F <file-descriptor> Read password from this file descriptor\n"
" -c <sesman_ini> 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);
}