Plumb connect_session call into sesman and sesexec

This commit is contained in:
matt335672
2025-06-18 11:31:58 +01:00
parent 602f3b495b
commit 09e4a99bac
6 changed files with 404 additions and 19 deletions
+109 -3
View File
@@ -31,6 +31,7 @@
#include "trans.h" #include "trans.h"
#include "os_calls.h" #include "os_calls.h"
#include "eicp.h" #include "eicp.h"
#include "ercp.h"
#include "scp.h" #include "scp.h"
#include "display_utils.h" #include "display_utils.h"
@@ -301,9 +302,12 @@ logout_scp_list_item(struct scp_list_item *sli)
{ {
if (sli->login_state != E_SLI_LOGIN_NOT_LOGGED_IN) if (sli->login_state != E_SLI_LOGIN_NOT_LOGGED_IN)
{ {
(void)eicp_send_logout_request(sli->sesexec_trans); if (sli->sesexec_trans != NULL)
trans_delete(sli->sesexec_trans); {
sli->sesexec_trans = NULL; (void)eicp_send_logout_request(sli->sesexec_trans);
trans_delete(sli->sesexec_trans);
sli->sesexec_trans = NULL;
}
sli->uid = (uid_t) -1; sli->uid = (uid_t) -1;
g_free(sli->username); g_free(sli->username);
sli->username = NULL; sli->username = NULL;
@@ -469,6 +473,9 @@ process_create_session_request(struct scp_list_item *sli)
if (s_item != NULL) if (s_item != NULL)
{ {
// Found an existing session // Found an existing session
LOG(LOG_LEVEL_INFO,
"A suitable session on display :%d is already active",
s_item->display);
display = s_item->display; display = s_item->display;
guid = s_item->guid; guid = s_item->guid;
} }
@@ -476,15 +483,22 @@ process_create_session_request(struct scp_list_item *sli)
else if (g_cfg->sess.max_sessions > 0 && else if (g_cfg->sess.max_sessions > 0 &&
session_list_get_count() >= g_cfg->sess.max_sessions) session_list_get_count() >= g_cfg->sess.max_sessions)
{ {
LOG(LOG_LEVEL_ERROR,
"The maximum number of sessions has been reached");
status = E_SCP_SCREATE_MAX_REACHED; status = E_SCP_SCREATE_MAX_REACHED;
} }
else if ((display = get_free_display()) < 0) else if ((display = get_free_display()) < 0)
{ {
LOG(LOG_LEVEL_ERROR,
"No free display can be found for a new session");
status = E_SCP_SCREATE_NO_DISPLAY; status = E_SCP_SCREATE_NO_DISPLAY;
} }
// Create a socket dir for this user // Create a socket dir for this user
else if (create_xrdp_socket_path(sli->uid) != 0) else if (create_xrdp_socket_path(sli->uid) != 0)
{ {
LOG(LOG_LEVEL_ERROR,
"Can't create a socket directory for UID %d",
(int)sli->uid);
status = E_SCP_SCREATE_GENERAL_ERROR; status = E_SCP_SCREATE_GENERAL_ERROR;
} }
// Create a sesexec process if we don't have one (UDS login) // Create a sesexec process if we don't have one (UDS login)
@@ -511,6 +525,8 @@ process_create_session_request(struct scp_list_item *sli)
else else
{ {
// Pass the session create request to sesexec // Pass the session create request to sesexec
LOG(LOG_LEVEL_INFO,
"Passing session creation request to sesexec");
int eicp_stat; int eicp_stat;
eicp_stat = eicp_send_create_session_request( eicp_stat = eicp_send_create_session_request(
sli->sesexec_trans, sli->sesexec_trans,
@@ -554,6 +570,86 @@ process_create_session_request(struct scp_list_item *sli)
/******************************************************************************/ /******************************************************************************/
static int
process_connect_session_request(struct scp_list_item *sli)
{
int rv;
/* Client parameters describing new session */
struct guid guid;
unsigned int flags;
enum scp_sconnect_status status = E_SCP_SCONNECT_OK;
rv = scp_get_connect_session_request(sli->client_trans, &guid, &flags);
if (rv == 0)
{
if (sli->login_state == E_SLI_LOGIN_NOT_LOGGED_IN)
{
status = E_SCP_SCONNECT_NOT_LOGGED_IN;
}
else
{
struct session_item *s_item = session_list_get_byguid(&guid);
if (s_item == NULL)
{
LOG(LOG_LEVEL_ERROR,
"User %s tried to connect to non-existent session",
sli->username);
status = E_SCP_SCONNECT_NO_SUCH_GUID;
}
else if (s_item->uid != sli->uid)
{
LOG(LOG_LEVEL_ERROR,
"User %s (UID %d) denied access to session for UID %d",
sli->username, sli->uid, s_item->uid);
status = E_SCP_SCONNECT_NO_SUCH_GUID;
}
else
{
// Don't log the GUID
LOG(LOG_LEVEL_INFO,
"Forwarding request from %s to connect to a session",
sli->username);
// Pass the session create request to sesexec
int ercp_stat;
ercp_stat = ercp_send_connect_session_request(
s_item->sesexec_trans,
sli->client_trans->sck,
flags);
if (ercp_stat != 0)
{
// The sesexec transport is broken. That's dealt with
// elsewhere.
LOG(LOG_LEVEL_ERROR,
"Can't ask sesexec to connect to a session");
status = E_SCP_SCONNECT_GENERAL_ERROR;
}
else
{
status = E_SCP_SCONNECT_OK;
}
}
}
// Send anything other than a successful connection request
// back to the client
if (status != E_SCP_SCONNECT_OK)
{
rv = scp_send_connect_session_response(sli->client_trans,
status, -1, -1);
}
}
// This call is always the last thing on the SCP connection.
logout_scp_list_item(sli); // Remove any sesexec process used for auth
sli->dispatcher_action = E_SLD_TERMINATE_SCP_CONN;
return rv;
}
/******************************************************************************/
static int static int
process_list_sessions_request(struct scp_list_item *sli) process_list_sessions_request(struct scp_list_item *sli)
{ {
@@ -639,6 +735,12 @@ process_close_connection_request(struct scp_list_item *sli)
LOG(LOG_LEVEL_INFO, "Received request to close connection from %s", LOG(LOG_LEVEL_INFO, "Received request to close connection from %s",
sli->peername); sli->peername);
/* Make sure we're logged out */
if (sli->login_state != E_SLI_LOGIN_NOT_LOGGED_IN)
{
logout_scp_list_item(sli);
}
/* Expecting no more client messages. Close the connection /* Expecting no more client messages. Close the connection
* after returning from this callback */ * after returning from this callback */
sli->dispatcher_action = E_SLD_TERMINATE_SCP_CONN; sli->dispatcher_action = E_SLD_TERMINATE_SCP_CONN;
@@ -674,6 +776,10 @@ scp_process(struct scp_list_item *sli)
rv = process_create_session_request(sli); rv = process_create_session_request(sli);
break; break;
case E_SCP_CONNECT_SESSION_REQUEST:
rv = process_connect_session_request(sli);
break;
case E_SCP_LIST_SESSIONS_REQUEST: case E_SCP_LIST_SESSIONS_REQUEST:
rv = process_list_sessions_request(sli); rv = process_list_sessions_request(sli);
break; break;
+97 -6
View File
@@ -30,7 +30,10 @@
#include "arch.h" #include "arch.h"
#include "login_info.h"
#include "scp.h"
#include "sesexec.h" #include "sesexec.h"
#include "os_calls.h"
#include "session.h" #include "session.h"
#include "trans.h" #include "trans.h"
@@ -38,11 +41,99 @@
#include "ercp_server.h" #include "ercp_server.h"
/******************************************************************************/ /******************************************************************************/
static int static enum scp_sconnect_status
handle_session_reconnect_event(struct trans *self) get_session_fds(struct session_data *sd, unsigned int scp_flags,
int *display_fd, int *chan_fd)
{ {
session_reconnect(g_login_info, g_session_data); enum scp_sconnect_status result = E_SCP_SCONNECT_OK;
return 0;
if ((*display_fd = session_get_display_server_fd(g_login_info, sd)) < 0)
{
result = E_SCP_SCONNECT_SERVER_FAIL;
}
else if ((scp_flags & E_SCP_SCONNECT_FLAG_NEED_CHANSRV) == 0)
{
// Don't need to try to connect to chansrv
*chan_fd = -1;
}
else
{
// If this fails, it's inconvenient, but not a show-stopper
*chan_fd = session_get_chansrv_fd(g_login_info, sd);
}
return result;
}
/******************************************************************************/
static int
handle_connect_session_request(struct trans *self)
{
int scp_fd = -1;
unsigned int scp_flags;
int rv = ercp_get_connect_session_request(self, &scp_fd, &scp_flags);
if (rv == 0)
{
struct trans *scp_trans;
if ((scp_trans = scp_init_trans_from_fd(scp_fd,
TRANS_TYPE_SERVER,
sesexec_is_term)) == NULL)
{
LOG(LOG_LEVEL_ERROR, "Can't create SCP trans");
rv = 1;
}
else
{
scp_fd = -1; // Don't close this twice!
// Now we've got a transport we can send data back to
// the SCP client
enum scp_sconnect_status scp_status;
int display_fd = -1;
int chan_fd = -1;
scp_status = get_session_fds(g_session_data, scp_flags,
&display_fd, &chan_fd);
rv = scp_send_connect_session_response(scp_trans, scp_status,
display_fd, chan_fd);
if (rv == 0 && scp_status == E_SCP_SCONNECT_OK)
{
// Don't run the reconnect script on the first connect
if (session_increment_connect_count(g_session_data) == 0)
{
LOG(LOG_LEVEL_INFO, "User %s has connected to a session",
g_login_info->username);
}
else
{
LOG(LOG_LEVEL_INFO, "User %s has reconnected to a session",
g_login_info->username);
session_run_reconnect_script(g_login_info, g_session_data);
}
}
// Regardless of the result of the send, we must close all
// our copies of file descriptors.
if (display_fd >= 0)
{
g_file_close(display_fd);
}
if (chan_fd >= 0)
{
g_file_close(chan_fd);
}
trans_delete(scp_trans);
}
}
if (scp_fd >= 0)
{
g_file_close(scp_fd);
}
return rv;
} }
/******************************************************************************/ /******************************************************************************/
@@ -54,8 +145,8 @@ ercp_server(struct trans *self)
switch ((msgno = ercp_msg_in_get_msgno(self))) switch ((msgno = ercp_msg_in_get_msgno(self)))
{ {
case E_ERCP_SESSION_RECONNECT_EVENT: case E_ERCP_CONNECT_SESSION_REQUEST:
rv = handle_session_reconnect_event(self); rv = handle_connect_session_request(self);
break; break;
default: default:
+136 -8
View File
@@ -33,6 +33,7 @@
#include "config_ac.h" #include "config_ac.h"
#endif #endif
#include <stdio.h>
#include <errno.h> #include <errno.h>
#include "arch.h" #include "arch.h"
@@ -49,6 +50,7 @@
#include "sesexec.h" #include "sesexec.h"
#include "sessionrecord.h" #include "sessionrecord.h"
#include "string_calls.h" #include "string_calls.h"
#include "trans.h"
#include "xauth.h" #include "xauth.h"
#include "xwait.h" #include "xwait.h"
#include "xrdp_sockets.h" #include "xrdp_sockets.h"
@@ -59,6 +61,7 @@ struct session_data
pid_t win_mgr; ///< PID of window manager pid_t win_mgr; ///< PID of window manager
pid_t chansrv; //< PID of chansrv pid_t chansrv; //< PID of chansrv
time_t start_time; time_t start_time;
unsigned int connect_count;
struct session_parameters params; struct session_parameters params;
// Flexible array member used to store strings in params and ip_addr; // Flexible array member used to store strings in params and ip_addr;
#ifdef __cplusplus #ifdef __cplusplus
@@ -95,6 +98,7 @@ session_data_new(const struct session_parameters *sp)
sd->x_server = -1; sd->x_server = -1;
sd->chansrv = -1; sd->chansrv = -1;
sd->start_time = 0; sd->start_time = 0;
sd->connect_count = 0;
/* Copy all the non-string session parameters... */ /* Copy all the non-string session parameters... */
sd->params = *sp; sd->params = *sp;
@@ -184,7 +188,7 @@ dumpItemsToString(struct list *self, char *outstr, int len)
/******************************************************************************/ /******************************************************************************/
static void static void
start_chansrv(struct login_info *login_info, start_chansrv(const struct login_info *login_info,
const struct session_parameters *s) const struct session_parameters *s)
{ {
struct list *chansrv_params = list_create(); struct list *chansrv_params = list_create();
@@ -222,7 +226,7 @@ start_chansrv(struct login_info *login_info,
/******************************************************************************/ /******************************************************************************/
static void static void
start_window_manager(struct login_info *login_info, start_window_manager(const struct login_info *login_info,
const struct session_parameters *s) const struct session_parameters *s)
{ {
char text[256]; char text[256];
@@ -471,7 +475,7 @@ prepare_xvnc_xserver_params(const struct session_parameters *s,
/******************************************************************************/ /******************************************************************************/
/* Either execs the X server, or returns */ /* Either execs the X server, or returns */
static void static void
start_x_server(struct login_info *login_info, start_x_server(const struct login_info *login_info,
const struct session_parameters *s) const struct session_parameters *s)
{ {
char authfile[256]; /* The filename for storing xauth information */ char authfile[256]; /* The filename for storing xauth information */
@@ -575,8 +579,8 @@ start_x_server(struct login_info *login_info,
* Simple helper process to fork a child and log errors */ * Simple helper process to fork a child and log errors */
static int static int
fork_child( fork_child(
void (*runproc)(struct login_info *, const struct session_parameters *), void (*runproc)(const struct login_info *, const struct session_parameters *),
struct login_info *login_info, const struct login_info *login_info,
const struct session_parameters *s, const struct session_parameters *s,
pid_t group_pid) pid_t group_pid)
{ {
@@ -1065,6 +1069,20 @@ session_get_start_time(const struct session_data *sd)
return (sd == NULL) ? 0 : sd->start_time; return (sd == NULL) ? 0 : sd->start_time;
} }
/******************************************************************************/
unsigned int
session_get_connect_count(const struct session_data *sd)
{
return (sd == NULL) ? 0 : sd->connect_count;
}
/******************************************************************************/
unsigned int
session_increment_connect_count(struct session_data *sd)
{
return (sd == NULL) ? 0 : sd->connect_count++;
}
/******************************************************************************/ /******************************************************************************/
const struct session_parameters * const struct session_parameters *
session_get_parameters(const struct session_data *sd) session_get_parameters(const struct session_data *sd)
@@ -1110,7 +1128,7 @@ session_send_term(struct session_data *sd, int wait_for_all)
/******************************************************************************/ /******************************************************************************/
static void static void
start_reconnect_script(struct login_info *login_info, start_reconnect_script(const struct login_info *login_info,
const struct session_parameters *s) const struct session_parameters *s)
{ {
env_set_user(login_info->uid, 0, s->display, env_set_user(login_info->uid, 0, s->display,
@@ -1143,8 +1161,8 @@ start_reconnect_script(struct login_info *login_info,
/******************************************************************************/ /******************************************************************************/
void void
session_reconnect(struct login_info *login_info, session_run_reconnect_script(const struct login_info *login_info,
struct session_data *sd) const struct session_data *sd)
{ {
if (fork_child(start_reconnect_script, if (fork_child(start_reconnect_script,
login_info, &sd->params, sd->x_server) < 0) login_info, &sd->params, sd->x_server) < 0)
@@ -1152,3 +1170,113 @@ session_reconnect(struct login_info *login_info,
LOG(LOG_LEVEL_ERROR, "Failed to fork for session reconnection script"); LOG(LOG_LEVEL_ERROR, "Failed to fork for session reconnection script");
} }
} }
/******************************************************************************/
int
session_get_display_server_fd(const struct login_info *login_info,
const struct session_data *sd)
{
char portname[XRDP_SOCKETS_MAXPATH];
const char *localhost = "localhost"; // Ignored for TRANS_MODE_UNIX
int socket_mode;
int rv = -1;
if (sd->x_server <= 0)
{
LOG(LOG_LEVEL_ERROR,
"Request to connect to display server :%u"
" which has exited", sd->params.display);
}
else
{
switch (sd->params.type)
{
case SCP_SESSION_TYPE_XVNC:
socket_mode = TRANS_MODE_TCP;
snprintf(portname, sizeof(portname), "%u",
5900 + sd->params.display);
break;
case SCP_SESSION_TYPE_XVNC_UDS:
case SCP_SESSION_TYPE_XORG:
socket_mode = TRANS_MODE_UNIX;
snprintf(portname, sizeof(portname), XRDP_X11RDP_STR,
login_info->uid, (int)sd->params.display);
break;
default:
LOG(LOG_LEVEL_ERROR, "Unsupported session type %d for connect",
sd->params.type);
portname[0] = '\0';
}
if (portname[0] != '\0')
{
// Use the transport library to get the fd
struct trans *t = trans_create(socket_mode, 8 * 8192, 8192);
if (t == NULL)
{
LOG(LOG_LEVEL_ERROR, "Out of memory creating transport");
}
else if (trans_connect(t, localhost, portname, 3000) != 0)
{
LOG(LOG_LEVEL_ERROR, "Can't connect to display server :%u [%s]",
sd->params.display,
g_get_strerror());
}
else
{
rv = t->sck;
t->sck = -1;
}
trans_delete(t);
}
}
return rv;
}
/******************************************************************************/
int
session_get_chansrv_fd(const struct login_info *login_info,
const struct session_data *sd)
{
char portname[XRDP_SOCKETS_MAXPATH];
int rv = -1;
if (sd->chansrv <= 0)
{
LOG(LOG_LEVEL_ERROR,
"Request to connect to chansrv :%u"
" which has exited", sd->params.display);
}
else
{
snprintf(portname, sizeof(portname),
XRDP_CHANSRV_STR, login_info->uid, (int)sd->params.display);
// Use the transport library to get the fd
struct trans *t = trans_create(TRANS_MODE_UNIX, 8192, 8192);
if (t == NULL)
{
LOG(LOG_LEVEL_ERROR, "Out of memory creating transport");
}
else if (trans_connect(t, NULL, portname, 10 * 1000) != 0)
{
LOG(LOG_LEVEL_ERROR, "Can't connect to chansrv :%u [%s]",
sd->params.display,
g_get_strerror());
}
else
{
rv = t->sck;
t->sck = -1;
}
trans_delete(t);
}
return rv;
}
+32 -2
View File
@@ -108,6 +108,22 @@ session_active(const struct session_data *sd);
time_t time_t
session_get_start_time(const struct session_data *sd); session_get_start_time(const struct session_data *sd);
/**
* Returns the connect count for an active session
* @param sd session_data for this session
* @return connect count
*/
unsigned int
session_get_connect_count(const struct session_data *sd);
/**
* Increment the connect count for an active session
* @param sd session_data for this session
* @return Pre-increment value of the connect count
*/
unsigned int
session_increment_connect_count(struct session_data *sd);
/** /**
* Returns the parameters used to start the session * Returns the parameters used to start the session
* *
@@ -145,7 +161,21 @@ session_data_free(struct session_data *session_data);
* Runs the reconnect script for the session * Runs the reconnect script for the session
*/ */
void void
session_reconnect(struct login_info *login_info, session_run_reconnect_script(const struct login_info *login_info,
struct session_data *sd); const struct session_data *sd);
/**
* Connects a file descriptor to the display server
*/
int
session_get_display_server_fd(const struct login_info *login_info,
const struct session_data *sd);
/**
* Connects a file descriptor to chansrv
*/
int
session_get_chansrv_fd(const struct login_info *login_info,
const struct session_data *sd);
#endif // SESSION_H #endif // SESSION_H
+19
View File
@@ -361,6 +361,25 @@ session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags)
return sess; return sess;
} }
/******************************************************************************/
struct session_item *
session_list_get_byguid(const struct guid *guid)
{
int i;
for (i = 0 ; i < g_session_list->count ; ++i)
{
struct session_item *si;
si = (struct session_item *)list_get_item(g_session_list, i);
if (SESSION_IN_USE(si) && GUID_ARE_EQUAL(guid, &si->guid))
{
return si;
}
}
return NULL;
}
/******************************************************************************/ /******************************************************************************/
void void
free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt) free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt)
+11
View File
@@ -153,6 +153,17 @@ session_list_get_bydata(uid_t uid,
struct scp_session_info * struct scp_session_info *
session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags); session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags);
/**
* @brief retrieves a session by GUID
* @param guid GUID of session
* @return Pointer to session, or NULL.
*
* The caller is responsible for checking the client has
* permissions to access the session.
*/
struct session_item *
session_list_get_byguid(const struct guid *guid);
/** /**
* *
* @brief Frees the result of session_get_byuser() * @brief Frees the result of session_get_byuser()