From 8e291846d5c2dcbcb8fadb0f372bb51a5bf54061 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 29 Mar 2023 15:26:38 +0100 Subject: [PATCH] Create pre-session list This is made from the old sesman_con structure. It describes a connection to sesman which is not yet running a session. --- sesman/Makefile.am | 2 + sesman/pre_session_list.c | 261 ++++++++++++++++++++++++++++++++++++++ sesman/pre_session_list.h | 148 +++++++++++++++++++++ 3 files changed, 411 insertions(+) create mode 100644 sesman/pre_session_list.c create mode 100644 sesman/pre_session_list.h diff --git a/sesman/Makefile.am b/sesman/Makefile.am index 83101983..a2d64f00 100644 --- a/sesman/Makefile.am +++ b/sesman/Makefile.am @@ -20,6 +20,8 @@ xrdp_sesman_SOURCES = \ env.h \ lock_uds.c \ lock_uds.h \ + pre_session_list.c \ + pre_session_list.h \ scp_process.c \ scp_process.h \ sesman.c \ diff --git a/sesman/pre_session_list.c b/sesman/pre_session_list.c new file mode 100644 index 00000000..ebc15af6 --- /dev/null +++ b/sesman/pre_session_list.c @@ -0,0 +1,261 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2015 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file pre_session_list.h + * @brief List of pre-session connections to sesman (definitions) + * + * @author Matt Burt + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + + +#include "arch.h" +#include "list.h" +#include "os_calls.h" +#include "pre_session_list.h" +#include "trans.h" + +#define PRE_SESSION_IN_USE(si) \ + ( \ + (si) != NULL && \ + ( \ + ((si)->client_trans != NULL && (si)->client_trans->status == TRANS_STATUS_UP) || \ + ((si)->sesexec_trans != NULL && (si)->sesexec_trans->status == TRANS_STATUS_UP) \ + ) \ + ) + +static struct list *g_pre_session_list = NULL; + +/** + * Deletes a pre_session_item, freeing resources + * + * After this call, the passed-in pointer is invalid and must not be + * referenced. + * + * Any auth_info struct found in the sesman_con is also deallocated. + * + * @param sc struct to de-allocate + */ +static void +free_pre_session_item(struct pre_session_item *psi) +{ + if (psi != NULL) + { + trans_delete(psi->client_trans); + trans_delete(psi->sesexec_trans); + g_free(psi->username); + g_free(psi); + } +} + +/******************************************************************************/ +int +pre_session_list_init(unsigned int list_size) +{ + int rv = 1; + if (g_pre_session_list == NULL) + { + g_pre_session_list = list_create_sized(list_size); + } + + if (g_pre_session_list == NULL) + { + LOG(LOG_LEVEL_ERROR, "Can't allocate pre-session list"); + } + else + { + g_pre_session_list->auto_free = 0; + rv = 0; + } + + return rv; +} + +/******************************************************************************/ +void +pre_session_list_cleanup(void) +{ + if (g_pre_session_list != NULL) + { + int i; + for (i = 0 ; i < g_pre_session_list->count ; ++i) + { + struct pre_session_item *p; + p = (struct pre_session_item *)list_get_item(g_pre_session_list, i); + free_pre_session_item(p); + } + list_delete(g_pre_session_list); + g_pre_session_list = NULL; + } +} + +/******************************************************************************/ +unsigned int +pre_session_list_get_count(void) +{ + return g_pre_session_list->count; +} + +/******************************************************************************/ +struct pre_session_item * +pre_session_list_new(void) +{ + struct pre_session_item *result = g_new0(struct pre_session_item, 1); + if (result != NULL) + { + g_snprintf(result->peername, sizeof(result->peername), "unknown"); + result->uid = (uid_t) -1; + + if (!list_add_item(g_pre_session_list, (tintptr)result)) + { + g_free(result); + result = NULL; + } + } + + return result; +} + +/*****************************************************************************/ +int +pre_session_list_set_peername(struct pre_session_item *psi, const char *name) +{ + int rv = 1; + + if (psi != NULL && name != NULL) + { + g_snprintf(psi->peername, sizeof(psi->peername), "%s", name); + rv = 0; + } + + return rv; +} + +/******************************************************************************/ +int +pre_session_list_get_wait_objs(tbus robjs[], int *robjs_count) +{ + int i = 0; + + while (i < g_pre_session_list->count) + { + struct pre_session_item *psi; + psi = (struct pre_session_item *)list_get_item(g_pre_session_list, i); + int psi_in_use = 0; + + if (psi != NULL) + { + if (psi->client_trans != NULL && + psi->client_trans->status == TRANS_STATUS_UP) + { + robjs[(*robjs_count)++] = psi->client_trans->sck; + psi_in_use = 1; + } + + if (psi->sesexec_trans != NULL && + psi->sesexec_trans->status == TRANS_STATUS_UP) + { + robjs[(*robjs_count)++] = psi->sesexec_trans->sck; + psi_in_use = 1; + } + } + + if (psi_in_use) + { + ++i; + } + else + { + free_pre_session_item(psi); + list_remove_item(g_pre_session_list, i); + } + } + + return 0; +} + +/******************************************************************************/ +int +pre_session_list_check_wait_objs(void) +{ + int i = 0; + + while (i < g_pre_session_list->count) + { + struct pre_session_item *psi; + enum pre_session_dispatcher_action action; + + psi = (struct pre_session_item *)list_get_item(g_pre_session_list, i); + action = E_PSD_TERMINATE_PRE_SESSION; + + if (PRE_SESSION_IN_USE(psi)) + { + if (psi->client_trans != NULL && + psi->client_trans->status == TRANS_STATUS_UP) + { + if (trans_check_wait_objs(psi->client_trans) != 0) + { + LOG(LOG_LEVEL_ERROR, "pre_session_list_check_wait_objs: " + "trans_check_wait_objs(1) failed, removing trans"); + psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION; + } + } + + if (psi->sesexec_trans != NULL && + psi->sesexec_trans->status == TRANS_STATUS_UP) + { + if (trans_check_wait_objs(psi->sesexec_trans) != 0) + { + LOG(LOG_LEVEL_ERROR, "pre_session_list_check_wait_objs: " + "trans_check_wait_objs(2) failed, removing trans"); + psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION; + } + } + + /* Get any action, and reset the requested one */ + action = psi->dispatcher_action; + psi->dispatcher_action = E_PSD_NONE; + } + + switch (action) + { + case E_PSD_NONE: + /* On to the next item on the list */ + ++i; + break; + + case E_PSD_REMOVE_CLIENT_TRANS: + trans_delete(psi->client_trans); + psi->client_trans = NULL; + /* On to the next item on the list */ + ++i; + break; + case E_PSD_TERMINATE_PRE_SESSION: + free_pre_session_item(psi); + list_remove_item(g_pre_session_list, i); + break; + } + } + + return 0; +} diff --git a/sesman/pre_session_list.h b/sesman/pre_session_list.h new file mode 100644 index 00000000..5f217731 --- /dev/null +++ b/sesman/pre_session_list.h @@ -0,0 +1,148 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * @file pre_session_list.h + * @brief List of pre-session connections to sesman (declarations) + * + * Items on this list are moved to the session list once they have + * authenticated and a session is started. + * + * @author Matt Burt + * + */ + +#ifndef PRE_SESSION_LIST_H +#define PRE_SESSION_LIST_H + +#include + +#include "xrdp_constants.h" + +/** + * Type describing the login state of a pre-session item + */ +enum ps_login_state +{ + E_PS_LOGIN_NOT_LOGGED_IN = 0, + E_PS_LOGIN_SYS, + E_PS_LOGIN_UDS +}; + +/** + * Action we require the dispatcher to do for us + * + * We can't do some things in an SCP or EICP callback, so we have to + * ask the dispatcher to do them. For example, we can't delete the + * client_trans as the callback stack won't be expecting this. + */ +enum pre_session_dispatcher_action +{ + E_PSD_NONE = 0, + E_PSD_REMOVE_CLIENT_TRANS, + E_PSD_TERMINATE_PRE_SESSION +}; + +/** + * Type for managing sesman connections from SCP clients (xrdp, etc) + * and any sesexec processes we've created for them. + */ +struct pre_session_item +{ + struct trans *client_trans; ///< SCP link to sesman client + struct trans *sesexec_trans; ///< ECP link to sesexec + pid_t sesexec_pid; ///< PID of sesexec (if sesexec is active) + char peername[15 + 1]; ///< Name of peer, if known, for logging + enum ps_login_state login_state; ///< Login state + /** + * Any action which a callback requires the dispatcher to + * do out of scope of the callback */ + enum pre_session_dispatcher_action dispatcher_action; + uid_t uid; ///< User + char *username; ///< Username from UID (at time of logon) + char start_ip_addr[MAX_PEER_ADDRSTRLEN]; +}; + + +/** + * Initialise the module + * @param list_size Number of pre-session items allowed + * @return 0 for success + * + * Errors are logged + */ +int +pre_session_list_init(unsigned int list_size); + +/** + * Clean up the module on program exit + */ +void +pre_session_list_cleanup(void); + +/** + * Returns the number of items on the pre-session list + * @return Item count + */ +unsigned int +pre_session_list_get_count(void); + +/** + * Allocates a new pre-session item on the list + * + * @return pointer to new pre-session object or NULL for no memory + * + * After allocating the session, you must initialise the sesexec_trans field + * with a valid transport. + * + * The session is removed by pre_session_list_get_wait_objs() or + * pre_session_check_wait_objs() when the client + * transport goes down (or wasn't allocated in the first place). + */ +struct pre_session_item * +pre_session_list_new(void); + +/** + * Set the peername of a pre-session + * + * @param psi pre-session-item + * @param name Name to set + * @result 0 for success + */ +int +pre_session_list_set_peername(struct pre_session_item *psi, const char *name); + +/** + * @brief Get the wait objs for the pre-session list module + * @param @robjs Objects array to update + * @param robjs_count Elements in robjs (by reference) + * @return 0 for success + */ +int +pre_session_list_get_wait_objs(tbus robjs[], int *robjs_count); + + +/** + * @brief Check the wait objs for the pre-session list module + * @return 0 for success + */ +int +pre_session_list_check_wait_objs(void); + +#endif // PRE_SESSION_LIST_H