From ab56c2b52a9414210a3edaa1e26551328a5ef2ab Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:46:12 +0100 Subject: [PATCH 1/7] Fix minor comment errors in libipm/scp.h --- libipm/scp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libipm/scp.h b/libipm/scp.h index ff54fd6a73..386493a0d2 100644 --- a/libipm/scp.h +++ b/libipm/scp.h @@ -411,7 +411,7 @@ scp_get_create_session_response(struct trans *trans, struct guid *guid); /** - * Send an E_LIST_SESSIONS_REQUEST (SCP client) + * Send an E_SCP_LIST_SESSIONS_REQUEST (SCP client) * * @param trans SCP transport * @return != 0 for error @@ -422,7 +422,7 @@ int scp_send_list_sessions_request(struct trans *trans); /** - * Send an E_LIST_SESSIONS_RESPONSE (SCP server) + * Send an E_SCP_LIST_SESSIONS_RESPONSE (SCP server) * * @param trans SCP transport * @param status Status of request @@ -436,7 +436,7 @@ scp_send_list_sessions_response( const struct scp_session_info *info); /** - * Parse an incoming E_LIST_SESSIONS_RESPONSE (SCP client) + * Parse an incoming E_SCP_LIST_SESSIONS_RESPONSE (SCP client) * * @param trans SCP transport * @param[out] status Status of request From dd1dc7c630e4737d5fcff7dbc9e9e7f5fe20a401 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:48:08 +0100 Subject: [PATCH 2/7] Use proper define for sesman listen_port size The size of the listen_port for sesman cannot exceed XRDP_SOCKETS_MAXPATH. We should use this value rather than an arbitrary value of 256. --- sesman/libsesman/Makefile.am | 1 + sesman/libsesman/sesman_config.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sesman/libsesman/Makefile.am b/sesman/libsesman/Makefile.am index 7536cfeb44..7ef44455b0 100644 --- a/sesman/libsesman/Makefile.am +++ b/sesman/libsesman/Makefile.am @@ -4,6 +4,7 @@ AM_CPPFLAGS = \ -DXRDP_PAMCONF_PATH=\"${pamconfdir}\" \ -DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \ + -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/libipm \ -I$(top_srcdir)/common # -DXRDP_SBIN_PATH=\"${sbindir}\" \ diff --git a/sesman/libsesman/sesman_config.h b/sesman/libsesman/sesman_config.h index 5f403fa159..aa8d43dcfb 100644 --- a/sesman/libsesman/sesman_config.h +++ b/sesman/libsesman/sesman_config.h @@ -31,6 +31,8 @@ #include "list.h" #include "log.h" +#include "xrdp_sockets.h" + enum SESMAN_CFG_SESS_POLICY_BITS { /* If these two are set, they override everything else */ @@ -182,7 +184,7 @@ struct config_sesman * @var listen_port * @brief Listening port */ - char listen_port[256]; + char listen_port[XRDP_SOCKETS_MAXPATH]; /** * @var enable_user_wm * @brief Flag that enables user specific wm From 4d80cf6d7754fccb25e60277f491a5db0307b268 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:57:15 +0100 Subject: [PATCH 3/7] Move SCP synch calls from sesman tools to library The sesman tools have some private functions to make syncronous calls to sesman over SCP. This commit moves these calls to a new module scp_sync in libipm so that they can be utilised by other parts of xrdp (i.e. chansrv) --- libipm/Makefile.am | 2 + libipm/scp_sync.c | 168 ++++++++++++++++++++++++++++++++++++ libipm/scp_sync.h | 89 +++++++++++++++++++ sesman/tools/Makefile.am | 8 +- sesman/tools/sesadmin.c | 72 +++------------- sesman/tools/sesrun.c | 7 +- sesman/tools/tools_common.c | 71 --------------- sesman/tools/tools_common.h | 48 ----------- 8 files changed, 275 insertions(+), 190 deletions(-) create mode 100644 libipm/scp_sync.c create mode 100644 libipm/scp_sync.h delete mode 100644 sesman/tools/tools_common.c delete mode 100644 sesman/tools/tools_common.h diff --git a/libipm/Makefile.am b/libipm/Makefile.am index a1a6edcdac..8da084bc74 100644 --- a/libipm/Makefile.am +++ b/libipm/Makefile.am @@ -19,6 +19,8 @@ libipm_la_SOURCES = \ ercp.c \ scp.h \ scp.c \ + scp_sync.h \ + scp_sync.c \ scp_application_types.h \ scp_application_types.c diff --git a/libipm/scp_sync.c b/libipm/scp_sync.c new file mode 100644 index 0000000000..8312e9cb3f --- /dev/null +++ b/libipm/scp_sync.c @@ -0,0 +1,168 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2022 + * + * 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 scp_sync.c + * @brief scp definitions (synchronous calls) + * @author Matt Burt + * + */ + +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +//nclude "tools_common.h" +//nclude "trans.h" +#include "os_calls.h" +#include "log.h" +#include "scp.h" +#include "scp_sync.h" + +/*****************************************************************************/ +int +scp_sync_wait_specific(struct trans *t, enum scp_msg_code wait_msgno) +{ + + int rv = 0; + int available = 0; + + while (rv == 0 && !available) + { + if ((rv = scp_msg_in_wait_available(t)) != 0) + { + LOG(LOG_LEVEL_ERROR, "Error waiting on sesman transport"); + } + else + { + enum scp_msg_code reply_msgno = scp_msg_in_get_msgno(t); + + available = 1; + if (reply_msgno != wait_msgno) + { + char buff[64]; + scp_msgno_to_str(reply_msgno, buff, sizeof(buff)); + + LOG(LOG_LEVEL_WARNING, + "Ignoring unexpected message %s", buff); + scp_msg_in_reset(t); + available = 0; + } + } + } + + return rv; +} + +/*****************************************************************************/ +int +scp_sync_uds_login_request(struct trans *t) +{ + int rv = scp_send_uds_login_request(t); + if (rv == 0) + { + if ((rv = scp_sync_wait_specific(t, E_SCP_LOGIN_RESPONSE)) == 0) + { + enum scp_login_status login_result; + int server_closed; + rv = scp_get_login_response(t, &login_result, &server_closed, NULL); + if (rv == 0 && 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; + if (!server_closed) + { + (void)scp_send_close_connection_request(t); + } + } + scp_msg_in_reset(t); // Done with this message + } + + } + return rv; +} + +/*****************************************************************************/ +struct list * +scp_sync_list_sessions_request(struct trans *t) +{ + struct list *sessions = list_create(); + if (sessions == NULL) + { + LOG(LOG_LEVEL_ERROR, "Out of memory for sessions list"); + } + else + { + int end_of_list = 0; + + enum scp_list_sessions_status status; + struct scp_session_info *p; + + int rv = scp_send_list_sessions_request(t); + + sessions->auto_free = 1; + + while (rv == 0 && !end_of_list) + { + rv = scp_sync_wait_specific(t, E_SCP_LIST_SESSIONS_RESPONSE); + if (rv != 0) + { + break; + } + + rv = scp_get_list_sessions_response(t, &status, &p); + if (rv != 0) + { + break; + } + + switch (status) + { + case E_SCP_LS_SESSION_INFO: + if (!list_add_item(sessions, (tintptr)p)) + { + g_free(p); + LOG(LOG_LEVEL_ERROR, "Out of memory for session item"); + rv = 1; + } + break; + + case E_SCP_LS_END_OF_LIST: + end_of_list = 1; + break; + + default: + LOG(LOG_LEVEL_ERROR, + "Unexpected return code %d for session item", status); + rv = 1; + } + scp_msg_in_reset(t); + } + + if (rv != 0) + { + list_delete(sessions); + sessions = NULL; + } + } + + return sessions; +} diff --git a/libipm/scp_sync.h b/libipm/scp_sync.h new file mode 100644 index 0000000000..b99d3b9942 --- /dev/null +++ b/libipm/scp_sync.h @@ -0,0 +1,89 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2022, all xrdp contributors + * + * 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 libipm/scp_sync.h + * @brief scp declarations (synchronous calls) + * @author Simone Fedele/ Matt Burt + * + * This module places a synchronous wrapper on top of some of the + * calls in scp.h. It is intended to be used for simple SCP applications + * which do not need to handle SCP messages along with other messages + * using the xrdp transport mechanism. + * + */ + +#ifndef SCP_SYNC_H +#define SCP_SYNC_H + +#include + +/** + * Waits on a single transport for a specific SCP message to be available for + * parsing + * + * @param trans libipm transport + * @param wait_msgno Message number to wait for + * @return != 0 for error + * + * This is a convenience function, used to implement synchronous calls. + * + * While the call is active, data-in callbacks for the transport are + * disabled. + * + * Unexpected messages are ignored and logged. + * + * Only use this call if you have nothing to do until a message + * arrives on the transport. + * - If you have other transports to service, use + * scp_msg_in_check_available() + * - If you can process any incoming message, use + * scp_msg_in_wait_available() + */ +int +scp_sync_wait_specific(struct trans *t, enum scp_msg_code wait_msgno); + +/** + * Send UDS login request to sesman and wait for answer + * + * @param t SCP transport + * @return 0 for successful login + * + * If non-zero is returned, the scp_connection has been closed (if + * appropriate) and simply remains to be deleted. + */ +int +scp_sync_uds_login_request(struct trans *t); + +/** + * Send list sessions request to sesman and wait for answer(s) + * + * @param t SCP transport + * @return list of sessions + * + * If NULL is returned, the scp_connection has been closed (if + * appropriate) and simply remains to be deleted. + * + * If NULL is not returned, the caller must call list_delete() to + * free it. + */ +struct list * +scp_sync_list_sessions_request(struct trans *t); + +#endif /* SCP_SYNC_H */ diff --git a/sesman/tools/Makefile.am b/sesman/tools/Makefile.am index 73f1a3b96e..ce5171b1e9 100644 --- a/sesman/tools/Makefile.am +++ b/sesman/tools/Makefile.am @@ -17,14 +17,10 @@ noinst_PROGRAMS = \ xrdp-xcon xrdp_sesrun_SOURCES = \ - sesrun.c \ - tools_common.h \ - tools_common.c + sesrun.c xrdp_sesadmin_SOURCES = \ - sesadmin.c \ - tools_common.h \ - tools_common.c + sesadmin.c xrdp_dis_SOURCES = \ dis.c diff --git a/sesman/tools/sesadmin.c b/sesman/tools/sesadmin.c index e41c8fed49..e5c5e58ef5 100644 --- a/sesman/tools/sesadmin.c +++ b/sesman/tools/sesadmin.c @@ -26,11 +26,14 @@ #include "log.h" #include "os_calls.h" #include "string_calls.h" -#include "tools_common.h" + +#include "scp.h" +#include "scp_sync.h" #include #include + char cmnd[257]; char port[257]; @@ -89,25 +92,8 @@ int main(int argc, char **argv) } else { - 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, 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 - } + rv = scp_sync_uds_login_request(t); } if (rv == 0) @@ -169,48 +155,9 @@ print_session(const struct scp_session_info *s) static int cmndList(struct trans *t) { - struct list *sessions = list_create(); - int end_of_list = 0; - - enum scp_list_sessions_status status; - struct scp_session_info *p; - - int rv = scp_send_list_sessions_request(t); - - sessions->auto_free = 1; - - while (rv == 0 && !end_of_list) - { - rv = wait_for_sesman_reply(t, E_SCP_LIST_SESSIONS_RESPONSE); - if (rv != 0) - { - break; - } - - rv = scp_get_list_sessions_response(t, &status, &p); - if (rv != 0) - { - break; - } - - switch (status) - { - case E_SCP_LS_SESSION_INFO: - list_add_item(sessions, (tintptr)p); - break; - - case E_SCP_LS_END_OF_LIST: - end_of_list = 1; - break; - - default: - printf("Unexpected return code %d\n", status); - rv = 1; - } - scp_msg_in_reset(t); - } - - if (rv == 0) + int rv = 1; + struct list *sessions = scp_sync_list_sessions_request(t); + if (sessions != NULL) { if (sessions->count == 0) { @@ -224,9 +171,10 @@ cmndList(struct trans *t) print_session((struct scp_session_info *)sessions->items[i]); } } + (void)scp_send_close_connection_request(t); + list_delete(sessions); } - list_delete(sessions); return rv; } diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index b727da353d..89e20c36dc 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -40,7 +40,8 @@ #include "string_calls.h" #include "guid.h" -#include "tools_common.h" +#include "scp.h" +#include "scp_sync.h" // cppcheck doesn't always set this macro to something in double-quotes #if defined(__cppcheck__) @@ -453,7 +454,7 @@ 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); + int rv = scp_sync_wait_specific(t, E_SCP_LOGIN_RESPONSE); if (rv != 0) { *server_closed = 1; @@ -511,7 +512,7 @@ handle_create_session_response(struct trans *t) int display; struct guid guid; - int rv = wait_for_sesman_reply(t, E_SCP_CREATE_SESSION_RESPONSE); + int rv = scp_sync_wait_specific(t, E_SCP_CREATE_SESSION_RESPONSE); if (rv == 0) { rv = scp_get_create_session_response(t, &status, diff --git a/sesman/tools/tools_common.c b/sesman/tools/tools_common.c deleted file mode 100644 index 674ba69e23..0000000000 --- a/sesman/tools/tools_common.c +++ /dev/null @@ -1,71 +0,0 @@ -/** - * xrdp: A Remote Desktop Protocol server. - * - * Copyright (C) Jay Sorg 2004-2022 - * - * 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 tools_common.c - * @brief Common definitions for the tools utilities - * @author Matt Burt - * - */ - - -#if defined(HAVE_CONFIG_H) -#include "config_ac.h" -#endif - -#include "tools_common.h" -#include "trans.h" -#include "os_calls.h" -#include "scp.h" - - -/*****************************************************************************/ -int -wait_for_sesman_reply(struct trans *t, enum scp_msg_code wait_msgno) -{ - - int rv = 0; - int available = 0; - - while (rv == 0 && !available) - { - if ((rv = scp_msg_in_wait_available(t)) != 0) - { - LOG(LOG_LEVEL_ERROR, "Error waiting on sesman transport"); - } - else - { - enum scp_msg_code reply_msgno = scp_msg_in_get_msgno(t); - - available = 1; - if (reply_msgno != wait_msgno) - { - char buff[64]; - scp_msgno_to_str(reply_msgno, buff, sizeof(buff)); - - LOG(LOG_LEVEL_WARNING, - "Ignoring unexpected message %s", buff); - scp_msg_in_reset(t); - available = 0; - } - } - } - - return rv; -} diff --git a/sesman/tools/tools_common.h b/sesman/tools/tools_common.h deleted file mode 100644 index 2e357965e8..0000000000 --- a/sesman/tools/tools_common.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * xrdp: A Remote Desktop Protocol server. - * - * Copyright (C) Jay Sorg 2004-2022 - * - * 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 tools_common.c - * @brief Common definitions for the tools utilities - * @author Matt Burt - * - */ - -#if !defined(TOOLS_COMMON_H) -#define TOOLS_COMMON_H - -#include "scp.h" - -struct trans; - -/**************************************************************************//** - * Waits for an expected reply from sesman - * - * Any other incoming messages are ignored. - * - * Following this call, the message can be parsed in the usual way. - * - * @param t SCP transport - * @param wait_msgno Code of the message we're waiting for. - * @result 0 for success - */ -int -wait_for_sesman_reply(struct trans *t, enum scp_msg_code wait_msgno); - -#endif /* TOOLS_COMMON_H */ From c0ccb56908d5cb9861821971968156b7f05d1feb Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:03:03 +0100 Subject: [PATCH 4/7] Add calls to SCP to request sockdir creation THe SCP interface is modified so that a program can connect to sesman and ask for the sockdir to be created for the currently authenticated user --- libipm/scp.c | 40 ++++++++++++++++++++++++++++++++ libipm/scp.h | 40 ++++++++++++++++++++++++++++++++ libipm/scp_application_types.h | 18 +++++++++++++++ libipm/scp_sync.c | 42 ++++++++++++++++++++++++++++++++++ libipm/scp_sync.h | 12 ++++++++++ 5 files changed, 152 insertions(+) diff --git a/libipm/scp.c b/libipm/scp.c index c090bc500e..0e96a19205 100644 --- a/libipm/scp.c +++ b/libipm/scp.c @@ -649,6 +649,46 @@ scp_get_list_sessions_response( /*****************************************************************************/ +int +scp_send_create_sockdir_request(struct trans *trans) +{ + return libipm_msg_out_simple_send( + trans, + (int)E_SCP_CREATE_SOCKDIR_REQUEST, + NULL); +} + + +/*****************************************************************************/ + +int +scp_send_create_sockdir_response(struct trans *trans, + enum scp_create_sockdir_status status) +{ + return libipm_msg_out_simple_send( + trans, + (int)E_SCP_CREATE_SOCKDIR_RESPONSE, + "i", status); +} + +/*****************************************************************************/ + +int +scp_get_create_sockdir_response(struct trans *trans, + enum scp_create_sockdir_status *status) +{ + int32_t i_status = 0; + int rv = libipm_msg_in_parse(trans, "i", &i_status); + if (rv == 0) + { + *status = (enum scp_create_sockdir_status)i_status; + } + + return rv; +} + +/*****************************************************************************/ + int scp_send_close_connection_request(struct trans *trans) { diff --git a/libipm/scp.h b/libipm/scp.h index 386493a0d2..1ec51e8285 100644 --- a/libipm/scp.h +++ b/libipm/scp.h @@ -59,6 +59,9 @@ enum scp_msg_code E_SCP_LIST_SESSIONS_REQUEST, E_SCP_LIST_SESSIONS_RESPONSE, + E_SCP_CREATE_SOCKDIR_REQUEST, + E_SCP_CREATE_SOCKDIR_RESPONSE, + E_SCP_CLOSE_CONNECTION_REQUEST // No E_SCP_CLOSE_CONNECTION_RESPONSE }; @@ -456,6 +459,43 @@ scp_get_list_sessions_response( enum scp_list_sessions_status *status, struct scp_session_info **info); +/** + * Send an E_SCP_CREATE_SOCKDIR_REQUEST (SCP client) + * + * @param trans SCP transport + * @return != 0 for error + * + * In some configurations, chansrv is not started by sesman. In this + * instance, it may be necessary for the unprivileged sesman process to + * ask sesman to create the sockets dir so sesman can populate it. + * + * Server replies with E_SCP_CREATE_SOCKDIR_RESPONSE + */ +int +scp_send_create_sockdir_request(struct trans *trans); + +/** + * Send an E_SCP_CREATE_SOCKDIR_RESPONSE (SCP server) + * + * @param trans SCP transport + * @param status Status of request + * @return != 0 for error + */ +int +scp_send_create_sockdir_response(struct trans *trans, + enum scp_create_sockdir_status status); + +/** + * Parse an incoming E_SCP_CREATE_SOCKDIR_RESPONSE (SCP client) + * + * @param trans SCP transport + * @param[out] status Status of request + * @return != 0 for error + */ +int +scp_get_create_sockdir_response(struct trans *trans, + enum scp_create_sockdir_status *status); + /** * Send an E_CLOSE_CONNECTION_REQUEST (SCP client) * diff --git a/libipm/scp_application_types.h b/libipm/scp_application_types.h index 89c7ca8aac..ab6e8e0e40 100644 --- a/libipm/scp_application_types.h +++ b/libipm/scp_application_types.h @@ -136,5 +136,23 @@ enum scp_list_sessions_status E_SCP_LS_NO_MEMORY }; +/** + * Status of a create sockdir message + */ +enum scp_create_sockdir_status +{ + E_SCP_CS_OK = 0, + + /** + * Client hasn't logged in yet + */ + E_SCP_CS_NOT_LOGGED_IN = 100, + + /** + * sesman failed to create the directory + */ + E_SCP_CS_OTHER_ERROR +}; + #endif /* SCP_APPLICATION_TYPES_H */ diff --git a/libipm/scp_sync.c b/libipm/scp_sync.c index 8312e9cb3f..cf565335e0 100644 --- a/libipm/scp_sync.c +++ b/libipm/scp_sync.c @@ -166,3 +166,45 @@ scp_sync_list_sessions_request(struct trans *t) return sessions; } + +/*****************************************************************************/ +int +scp_sync_create_sockdir_request(struct trans *t) +{ + int rv = scp_send_create_sockdir_request(t); + if (rv == 0) + { + rv = scp_sync_wait_specific(t, E_SCP_CREATE_SOCKDIR_RESPONSE); + if (rv == 0) + { + enum scp_create_sockdir_status status; + rv = scp_get_create_sockdir_response(t, &status); + if (rv == 0) + { + switch (status) + { + case E_SCP_CS_OK: + break; + + case E_SCP_CS_NOT_LOGGED_IN: + LOG(LOG_LEVEL_ERROR, "sesman reported not-logged-in"); + rv = 1; + break; + + case E_SCP_CS_OTHER_ERROR: + LOG(LOG_LEVEL_ERROR, + "sesman reported fail on create directory"); + rv = 1; + break; + } + } + scp_msg_in_reset(t); // Done with this message + if (!rv) + { + (void)scp_send_close_connection_request(t); + } + } + + } + return rv; +} diff --git a/libipm/scp_sync.h b/libipm/scp_sync.h index b99d3b9942..9b36ce8512 100644 --- a/libipm/scp_sync.h +++ b/libipm/scp_sync.h @@ -86,4 +86,16 @@ scp_sync_uds_login_request(struct trans *t); struct list * scp_sync_list_sessions_request(struct trans *t); +/** + * Send sockdir creation request to sesman and wait for answer + * + * @param t SCP transport + * @return 0 for successful response from sesman + * + * If non-zero is returned, the scp_connection has been closed (if + * appropriate) and simply remains to be deleted. + */ +int +scp_sync_create_sockdir_request(struct trans *t); + #endif /* SCP_SYNC_H */ From 661885f71d6a0a67aa00740250665b46f960de4c Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:06:34 +0100 Subject: [PATCH 5/7] Add support for SCP create_sockdir message to sesman --- sesman/scp_process.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sesman/scp_process.c b/sesman/scp_process.c index 8105fc6bb9..62960b370d 100644 --- a/sesman/scp_process.c +++ b/sesman/scp_process.c @@ -578,6 +578,32 @@ process_list_sessions_request(struct pre_session_item *psi) /******************************************************************************/ +static int +process_create_sockdir_request(struct pre_session_item *psi) +{ + enum scp_create_sockdir_status status = E_SCP_CS_OTHER_ERROR; + + if (psi->login_state == E_PS_LOGIN_NOT_LOGGED_IN) + { + status = E_SCP_CS_NOT_LOGGED_IN; + } + else + { + LOG(LOG_LEVEL_INFO, + "Received request from %s to create sockdir for user %s", + psi->peername, psi->username); + + if (create_xrdp_socket_path(psi->uid) == 0) + { + status = E_SCP_CS_OK; + } + } + + return scp_send_create_sockdir_response(psi->client_trans, status); +} + +/******************************************************************************/ + static int process_close_connection_request(struct pre_session_item *psi) { @@ -625,6 +651,10 @@ scp_process(struct pre_session_item *psi) rv = process_list_sessions_request(psi); break; + case E_SCP_CREATE_SOCKDIR_REQUEST: + rv = process_create_sockdir_request(psi); + break; + case E_SCP_CLOSE_CONNECTION_REQUEST: rv = process_close_connection_request(psi); break; From c46eece00fc31b5eac2d1177a737518130fd3002 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:08:31 +0100 Subject: [PATCH 6/7] Add support for creating sockdir to chansrv Chansrv now checks for the user sockdir being present. If it isn't, it connects to chansrv and requests it be created. This also needs the sesman port to be added to the chansrv config struct. --- sesman/chansrv/Makefile.am | 3 +- sesman/chansrv/chansrv.c | 58 ++++++++++++++++++++++++++++ sesman/chansrv/chansrv_config.c | 67 ++++++++++++++++++++++++++++++++- sesman/chansrv/chansrv_config.h | 3 ++ 4 files changed, 129 insertions(+), 2 deletions(-) diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 4b0154fac1..70fdde361f 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -10,7 +10,8 @@ AM_CPPFLAGS = \ -DXRDP_PID_PATH=\"${localstatedir}/run\" \ -DXRDP_SOCKET_ROOT_PATH=\"${socketdir}\" \ -I$(top_srcdir)/sesman/libsesman \ - -I$(top_srcdir)/common + -I$(top_srcdir)/common \ + -I$(top_srcdir)/libipm CHANSRV_EXTRA_LIBS = diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 2cd8cf0ae7..e890febcc2 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -45,6 +45,9 @@ #include "xrdp_sockets.h" #include "audin.h" +#include "scp.h" +#include "scp_sync.h" + #include "ms-rdpbcgr.h" #define MAX_PATH 260 @@ -1763,6 +1766,54 @@ run_exec(void) return 0; } +/*****************************************************************************/ +/** + * Make sure XRDP_SOCKET_PATH exists + * + * We can't do anything without XRDP_SOCKET_PATH existing. + * + * Normally this is done by sesman before chansrv starts. If we're running + * standalone however (i.e. with x11vnc) this won't be done. We don't have the + * privilege to create the directory, so we have to ask sesman to do it + * for us. + */ +static int +chansrv_create_xrdp_socket_path(void) +{ + char xrdp_socket_path[XRDP_SOCKETS_MAXPATH]; + int rv = 1; + + /* Use our UID to qualify XRDP_SOCKET_PATH */ + g_snprintf(xrdp_socket_path, sizeof(xrdp_socket_path), + XRDP_SOCKET_PATH, g_getuid()); + + if (g_directory_exist(xrdp_socket_path)) + { + rv = 0; + } + else + { + LOG(LOG_LEVEL_INFO, "%s doesn't exist - asking sesman to create it", + xrdp_socket_path); + + struct trans *t = NULL; + + if (!(t = scp_connect(g_cfg->listen_port, "xrdp-chansrv", g_is_term))) + { + LOG(LOG_LEVEL_ERROR, "Can't connect to sesman"); + } + else if (scp_sync_uds_login_request(t) == 0 && + scp_sync_create_sockdir_request(t) == 0) + { + rv = 0; + (void)scp_send_close_connection_request(t); + } + trans_delete(t); + } + + return rv; +} + /*****************************************************************************/ int main(int argc, char **argv) @@ -1855,6 +1906,13 @@ main(int argc, char **argv) } LOG_DEVEL(LOG_LEVEL_INFO, "main: app started pid %d(0x%8.8x)", pid, pid); + + if (chansrv_create_xrdp_socket_path() != 0) + { + main_cleanup(); + return 1; + } + /* set up signal handler */ g_signal_terminate(term_signal_handler); /* SIGTERM */ g_signal_user_interrupt(term_signal_handler); /* SIGINT */ diff --git a/sesman/chansrv/chansrv_config.c b/sesman/chansrv/chansrv_config.c index 000c8a4c8e..76b134a028 100644 --- a/sesman/chansrv/chansrv_config.c +++ b/sesman/chansrv/chansrv_config.c @@ -73,6 +73,61 @@ log_to_stdout(const enum logLevels lvl, const char *msg, ...) return LOG_STARTUP_OK; } +/***************************************************************************//** + * Reads the config values we need from the [Globals] section + * + * @param logmsg Function to use to log messages + * @param names List of definitions in the section + * @params values List of corresponding values for the names + * @params cfg Pointer to structure we're filling in + * + * @return 0 for success + */ +static int +read_config_globals(log_func_t logmsg, + struct list *names, struct list *values, + struct config_chansrv *cfg) +{ + int error = 0; + int index; + + for (index = 0; index < names->count; ++index) + { + const char *name = (const char *)list_get_item(names, index); + const char *value = (const char *)list_get_item(values, index); + + char unrecognised[256]; + if (g_strcasecmp(name, "ListenPort") == 0) + { + char *listen_port = strdup(value); + if (listen_port == NULL) + { + LOG(LOG_LEVEL_WARNING, + "Can't allocate config memory for ListenPort"); + } + else + { + g_free(cfg->listen_port); + cfg->listen_port = listen_port; + } + } + if (g_strcasecmp(name, "RestrictInboundClipboard") == 0) + { + cfg->restrict_inbound_clipboard = + sesman_clip_restrict_string_to_bitmask( + value, unrecognised, sizeof(unrecognised)); + if (unrecognised[0] != '\0') + { + LOG(LOG_LEVEL_WARNING, + "Unrecognised tokens parsing 'RestrictInboundClipboard' %s", + unrecognised); + } + } + } + + return error; +} + /***************************************************************************//** * Reads the config values we need from the [Security] section * @@ -213,6 +268,7 @@ new_config(void) } else { + cfg->listen_port = NULL; cfg->enable_fuse_mount = DEFAULT_ENABLE_FUSE_MOUNT; cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD; cfg->restrict_inbound_clipboard = DEFAULT_RESTRICT_INBOUND_CLIPBOARD; @@ -258,6 +314,11 @@ config_read(int use_logger, const char *sesman_ini) names->auto_free = 1; values->auto_free = 1; + if (!error && file_read_section(fd, "Globals", names, values) == 0) + { + error = read_config_globals(logmsg, names, values, cfg); + } + if (!error && file_read_section(fd, "Security", names, values) == 0) { error = read_config_security(logmsg, names, values, cfg); @@ -288,9 +349,12 @@ config_read(int use_logger, const char *sesman_ini) void config_dump(struct config_chansrv *config) { + char buf[256]; + g_writeln("Global configuration:"); + g_writeln(" xrdp-sesman ListenPort: %s", + (config->listen_port) ? config->listen_port : ""); - char buf[256]; g_writeln("\nSecurity configuration:"); sesman_clip_restrict_mask_to_string( config->restrict_outbound_clipboard, @@ -319,6 +383,7 @@ config_free(struct config_chansrv *cc) { if (cc != NULL) { + g_free(cc->listen_port); g_free(cc->fuse_mount_name); g_free(cc); } diff --git a/sesman/chansrv/chansrv_config.h b/sesman/chansrv/chansrv_config.h index a7b30bc694..b438a302be 100644 --- a/sesman/chansrv/chansrv_config.h +++ b/sesman/chansrv/chansrv_config.h @@ -23,6 +23,9 @@ struct config_chansrv { + /** sesman listening port */ + char *listen_port; + /** Whether the FUSE mount is enabled or not */ int enable_fuse_mount; From d17d12d078025e1e54f9594bb339512275ef7cc1 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:33:30 +0100 Subject: [PATCH 7/7] Add optional UID to DISPLAY() in chansrvport The code to determine the socket address of chansrv when using a manually started xrdp-chansrv may need some help determining the UID of the session. This commit allows a UID to be optionally specified in the DISPLAY() function, if the code is unable to determine the UID automatically from the connection parameters. If a manual chansrvport is entered, xrdp now logs what it is connecting to, to assist in debugging. --- docs/man/xrdp.ini.5.in | 9 ++++--- xrdp/xrdp.ini.in | 13 ++++++---- xrdp/xrdp_mm.c | 54 +++++++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/docs/man/xrdp.ini.5.in b/docs/man/xrdp.ini.5.in index 28b8fc70b7..7ce76f7d5b 100644 --- a/docs/man/xrdp.ini.5.in +++ b/docs/man/xrdp.ini.5.in @@ -381,14 +381,17 @@ Specifies the session type. The default, \fI0\fR, is Xvnc, and \fI20\fR is Xorg with xorgxrdp modules. .TP -\fBchansrvport\fR=\fBDISPLAY(\fR\fIn\fR\fB)\fR|\fI/path/to/domain-socket\fR +\fBchansrvport\fR=\fBDISPLAY(\fR\fIn\fR\fB)\fR|\fBDISPLAY(\fR\fIn,u\fR\fB)\fR||\fI/path/to/domain-socket\fR Asks xrdp to connect to a manually started \fBxrdp-chansrv\fR instance. This can be useful if you wish to use to use xrdp to connect to a VNC session which has been started other than by \fBxrdp-sesman\fR, as you can then make use of \fBxrdp\-chansrv\fR facilities in the VNC session. -The first form of this setting is recommended, replacing \fIn\fR with the -X11 display number of the session. +Either the first or second form of this setting is recommended. Replace +\fIn\fR with the X11 display number of the session, and (if applicable) +\fIu\fR with the numeric ID of the session. The second form is only +required if \fBxrdp\fR is unable to determine the session uid from the +other values in the connection block. .TP \fBkeycode_set\fR=\fI\fR diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index 53924764cc..e855e7df4a 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -262,10 +262,6 @@ port=-1 ; Disable requested encodings to support buggy VNC servers ; (1 = ExtendedDesktopSize) #disabled_encodings_mask=0 -; Use this to connect to a chansrv instance created outside of sesman -; (e.g. as part of an x11vnc console session). Replace '0' with the -; display number of the session -#chansrvport=DISPLAY(0) ; Generic VNC Proxy ; Tailor this to specific hosts and VNC instances by specifying an ip @@ -280,6 +276,15 @@ password=ask #pamusername=asksame #pampassword=asksame #delay_ms=2000 +; Use one of these to connect to a chansrv instance created outside of sesman +; (e.g. as part of an x11vnc console session). Replace 'n' with the +; display number of the session, and (if applicable) 'u' with the numeric +; UID of the session. +; +; If 'username' or 'pamusername' is set, you probably don't need to use +; the two parameter variant with 'u'. +#chansrvport=DISPLAY(n) +#chansrvport=DISPLAY(n,u) ; Generic RDP proxy using NeutrinoRDP ; Tailor this to specific hosts by specifying an ip and port and setting diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index c3ae935dc8..5d276c3b88 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -3010,28 +3010,60 @@ static int parse_chansrvport(const char *value, char *dest, int dest_size, int uid) { int rv = 0; + int dnum = 0; if (g_strncmp(value, "DISPLAY(", 8) == 0) { const char *p = value + 8; const char *end = p; - /* Check next chars are digits followed by ')' */ + /* Check next chars are digits */ while (isdigit(*end)) { ++end; } - if (end == p || *end != ')') + if (end == p) { - LOG(LOG_LEVEL_WARNING, "Ignoring invalid chansrvport string '%s'", + LOG(LOG_LEVEL_WARNING, + "Ignoring chansrvport string with bad display number '%s'", value); - rv = -1; + return -1; } - else + + dnum = g_atoi(p); + + if (*end == ',') { - g_snprintf(dest, dest_size, XRDP_CHANSRV_STR, uid, g_atoi(p)); + /* User has specified a UID override + * Check next chars are digits */ + p = end + 1; + end = p; + + while (isdigit(*end)) + { + ++end; + } + + if (end == p) + { + LOG(LOG_LEVEL_WARNING, + "Ignoring chansrvport string with bad uid '%s'", + value); + return -1; + } + uid = g_atoi(p); } + + if (*end != ')') + { + LOG(LOG_LEVEL_WARNING, + "Ignoring badly-terminated chansrvport string '%s'", + value); + return -1; + } + + g_snprintf(dest, dest_size, XRDP_CHANSRV_STR, uid, dnum); } else { @@ -3310,13 +3342,14 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) case MMCS_SESSION_LOGIN: { // Finished with the gateway login + // Leave the UID set in case we need it for the chansrvport + // string if (self->use_gw_login) { xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "access control check was successful"); // No reply needed for this one status = scp_send_logout_request(self->sesman_trans); - self->uid = -1; } if (status == 0 && self->use_sesman) @@ -3390,12 +3423,12 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) { char portbuff[XRDP_SOCKETS_MAXPATH]; - xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, - "Connecting to chansrv"); if (self->use_sesman) { g_snprintf(portbuff, sizeof(portbuff), XRDP_CHANSRV_STR, self->uid, self->display); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, + "Connecting to chansrv"); } else { @@ -3404,6 +3437,9 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) parse_chansrvport(cp, portbuff, sizeof(portbuff), self->uid); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, + "Connecting to chansrv on %s", + portbuff); } xrdp_mm_update_allowed_channels(self); xrdp_mm_chansrv_connect(self, portbuff);