From 315b8914c853078d8bb04a7d16e47d19128ca318 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sat, 2 Mar 2019 19:39:52 -0600 Subject: [PATCH] Second batch of initial commits: * Add server/group pamming * Partially fix immediate exit after login Still will not compile due to libraptorsmiface being too new --- common/defines.h | 2 + common/trans.c | 50 ++++++++++++ sesman/chansrv/chansrv.c | 4 +- sesman/scp_v0.c | 12 +++ sesman/scp_v1.c | 9 +++ sesman/session.c | 168 ++++++++++++++++++++++++++++++++++++--- xrdp/xrdp_mm.c | 36 +++++++-- xup/xup.c | 104 ++++++++++++++++++++++++ 8 files changed, 368 insertions(+), 17 deletions(-) diff --git a/common/defines.h b/common/defines.h index d87ddae7..74723f45 100644 --- a/common/defines.h +++ b/common/defines.h @@ -21,6 +21,8 @@ #ifndef DEFINES_H #define DEFINES_H +#define DISABLE_UNIX_DOMAIN_SOCKETS 1 + /* check for debug */ #ifdef XRDP_DEBUG #define DEBUG(args) g_writeln args; diff --git a/common/trans.c b/common/trans.c index 5909e4eb..84fafe43 100644 --- a/common/trans.c +++ b/common/trans.c @@ -512,6 +512,7 @@ trans_force_read(struct trans *self, int size) } /*****************************************************************************/ +#if 0 int trans_force_write_s(struct trans *self, struct stream *out_s) { @@ -571,6 +572,55 @@ trans_force_write_s(struct trans *self, struct stream *out_s) } return 0; } +#else +// DEBUG +/*****************************************************************************/ +int +trans_force_write_s(struct trans* self, struct stream* out_s) +{ + int size; + int total; + int sent; + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + size = (int)(out_s->end - out_s->data); + total = 0; + while (total < size) + { + sent = g_tcp_send(self->sck, out_s->data + total, size - total, 0); + if (sent == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + if (!g_tcp_can_send(self->sck, 10)) + { + /* check for term here */ + } + } + else + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 2; + } + } + else if (sent == 0) + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 3; + } + else + { + total = total + sent; + } + } + return 0; +} +#endif /*****************************************************************************/ int diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 12614f51..3a99cf6c 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -1468,7 +1468,6 @@ channel_thread_loop(void *in_val) g_con_trans = 0; /* use the display number to mark session disconnected in the Raptor session management database */ raptor_sm_set_session_state(g_display_num, SM_STATUS_RUNNING); - exit(0); // RAPTOR session management /* create new listener */ error = setup_listen(); @@ -1678,7 +1677,7 @@ read_ini(void) { name = (char *)list_get_item(names, index); value = (char *)list_get_item(values, index); - +#ifndef DISABLE_UNIX_DOMAIN_SOCKETS if (g_strcasecmp(name, "ListenAddress") == 0) { if (g_strcasecmp(value, "127.0.0.1") == 0) @@ -1686,6 +1685,7 @@ read_ini(void) g_use_unix_socket = 1; } } +#endif } } diff --git a/sesman/scp_v0.c b/sesman/scp_v0.c index cc3712cc..13a1bfc8 100644 --- a/sesman/scp_v0.c +++ b/sesman/scp_v0.c @@ -30,6 +30,8 @@ #include "sesman.h" +#include "libraptorsmiface.h" + extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ @@ -79,6 +81,16 @@ scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) s_item = session_get_bydata(s->username, s->width, s->height, s->bpp, s->type, s->client_ip); + // RAPTOR session management + pid_t serverpid = raptor_sm_get_pid_for_username(s->username); + if (serverpid < 0) { + // Session NOT already running + if (s_item != 0) { + log_message( LOG_LEVEL_INFO, "++ [FIXME] scp claimed there was an active session, but the authoritative RAPTOR database disagrees: username %s", s->username); + } + s_item = 0; + } + if (s_item != 0) { display = s_item->display; diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c index 60f82112..607aeca5 100644 --- a/sesman/scp_v1.c +++ b/sesman/scp_v1.c @@ -33,6 +33,8 @@ //#include "libscp_types.h" #include "libscp.h" +#include "libraptorsmiface.h" + extern struct config_sesman *g_cfg; /* in sesman.c */ static void parseCommonStates(enum SCP_SERVER_STATES_E e, const char *f); @@ -109,6 +111,13 @@ scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) /* list disconnected sessions */ slist = session_get_byuser(s->username, &scount, SESMAN_SESSION_STATUS_DISCONNECTED); + // RAPTOR session management + pid_t serverpid = raptor_sm_get_pid_for_username(s->username); + if (serverpid < 0) { + // Session NOT already running + scount = 0; + } + if (scount == 0) { /* no disconnected sessions - start a new one */ diff --git a/sesman/session.c b/sesman/session.c index 6fa63c3a..7a6173bf 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -42,6 +42,16 @@ #include "xauth.h" #include "xrdp_sockets.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "libraptorsmiface.h" #ifndef PR_SET_NO_NEW_PRIVS @@ -158,6 +168,82 @@ session_get_bydata(const char *name, int width, int height, int bpp, int type, return 0; } +/******************************************************************************/ +/** + * + * @brief checks if there's a server running on a host and port + * @param display the display to check + * @return 0 if the port is closed, 1 if it is open + * + */ +static int +check_port_status(const char* host, const char* port) +{ + char text[256]; + int x_running; + int sck; + + struct sockaddr_in servaddr; + int soc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + g_memset( &servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(atoi(port)); + + struct hostent* hostaddr; + hostaddr = gethostbyname(host); + g_memcpy(&servaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length); + + int res = connect(soc, (struct sockaddr*)&servaddr, sizeof(servaddr)); + + close(soc); + + if (res == -1) + { + // Port is closed, no server there! + return 0; + } + else { + // Port is open + return 1; + } +} + +/******************************************************************************/ +/** + * + * @brief checks if there's a server running on a remote display + * @param display the display to check + * @return 0 if there isn't a display running, nonzero otherwise + * + */ +static int +x_server_running_check_remote_ports(const char* host, int display) +{ + char text[256]; + int x_running; + int sck; + + x_running = 0; + /* check 59xx */ + { + g_sprintf(text, "59%2.2d", display); + x_running += check_port_status(host, text); + } + /* check 60xx */ + { + g_sprintf(text, "60%2.2d", display); + x_running += check_port_status(host, text); + } + /* check 62xx */ + { + g_sprintf(text, "62%2.2d", display); + x_running += check_port_status(host, text); + } + + return x_running; +} + /******************************************************************************/ /** * @@ -330,14 +416,14 @@ wait_for_xserver(int display) int i; /* give X a bit to start */ - /* wait up to 10 secs for x server to start */ + /* wait up to 15 secs for x server to start */ i = 0; - while (!x_server_running(display)) + while (!x_server_running_check_ports(display)) { i++; - if (i > 40) + if (i > 60) { log_message(LOG_LEVEL_ERROR, "X server for display %d startup timeout", @@ -387,6 +473,57 @@ session_start_chansrv(char *username, int display) return chansrv_pid; } +/******************************************************************************/ +static int +wait_for_remote_xserver(const char* host, int display) +{ + int i; + + /* give X a bit to start */ + /* wait up to 15 secs for x server to start */ + i = 0; + //while (!x_server_running(display)) + while (!x_server_running_check_remote_ports(host, display)) + { + i++; + if (i > 60) + { + log_message(LOG_LEVEL_ERROR, + "X server for host %s and display %d startup timeout", + host, display); + break; + } + g_sleep(250); + } + return 0; +} + +/******************************************************************************/ +static const char * +wait_for_remote_hostname(char* username) +{ + int i; + + /* wait up to 5 secs for hostname to appear */ + i = 0; + const char * hostname = raptor_sm_get_hostname_for_username(username, false); + while (strcmp(hostname, "") == 0) + { + g_free(hostname); + hostname = raptor_sm_get_hostname_for_username(username, false); + i++; + if (i > 20) + { + log_message(LOG_LEVEL_ERROR, + "Hostname allocation timeout"); + break; + } + g_sleep(250); + } + + return hostname; +} + /******************************************************************************/ /* called with the main thread */ static int @@ -468,6 +605,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c, if (display == 0) { + log_message(LOG_LEVEL_ALWAYS, "Unable to allocate display for user %s", s->username); g_free(temp->item); g_free(temp); return 0; @@ -543,17 +681,25 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c, } else if (window_manager_pid == 0) { - wait_for_xserver(display); + if (session_was_already_running) { + g_exit(0); + } + char* remote_server = wait_for_remote_hostname(s->username); + wait_for_remote_xserver(remote_server, display); env_set_user(s->username, 0, display, g_cfg->env_names, g_cfg->env_values); - if (session_was_already_running) { - g_exit(0); - } - if (x_server_running(display)) + + if (x_server_running_check_remote_ports(remote_server, display)) { + g_free(remote_server); + + // RAPTOR session management + raptor_sm_run_remote_desktop(s->username, display, "/opt/trinity/bin/starttde"); + g_exit(0); + auth_set_env(data); if (s->directory != 0) { @@ -619,6 +765,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c, } else { + g_free(remote_server); log_message(LOG_LEVEL_ERROR, "another Xserver might " "already be active on display %d - see log", display); } @@ -726,6 +873,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c, /* fire up Xorg */ pid_t serverpid; serverpid = raptor_sm_run_remote_server(s->username, pp1); + log_message(LOG_LEVEL_ALWAYS, "new server pid code was %d during login for user %s", serverpid, s->username); if (serverpid >= 0) { if (!session_was_already_running) { @@ -841,7 +989,9 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c, } else { - wait_for_xserver(display); + char* remote_server = wait_for_remote_hostname(s->username); + wait_for_remote_xserver(remote_server, display); + free(remote_server); chansrv_pid = session_start_chansrv(s->username, display); log_message(LOG_LEVEL_ALWAYS, "waiting for window manager " "(pid %d) to exit", window_manager_pid); diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 1bb7ea15..d62947fa 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -21,6 +21,7 @@ #if defined(HAVE_CONFIG_H) #include #endif +#include #include "xrdp.h" #include "log.h" @@ -494,6 +495,7 @@ static int xrdp_mm_setup_mod2(struct xrdp_mm *self, tui8 *guid) { char text[256]; + char raptortext[256]; const char *name; const char *value; int i; @@ -526,14 +528,24 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self, tui8 *guid) else if (self->code == 10 || self->code == 20) /* X11rdp/Xorg */ { char* rsmip = raptor_sm_get_ip_for_username(self->login_username, true); + if (strcmp(rsmip, "ERROR") == 0) { + g_snprintf(raptortext, 255, "[LICENSE] Instantaneous limit exceeded."); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext); + g_snprintf(raptortext, 255, "[LICENSE] Login for user %s denied.", self->login_username); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext); + g_free(rsmip); + raptor_sm_session_terminated(self->login_username); + return 1; + } int allocdisplay = raptor_sm_get_display_for_username(self->login_username); if ((raptor_sm_sesslimit_reached(self->login_username)) && (allocdisplay < 0)) { - g_snprintf(text, 255, "[LICENSE] Maximum concurrent session"); - xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR, text); - g_snprintf(text, 255, "[LICENSE] limit exceeded for group."); - xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR, text); - g_snprintf(text, 255, "[LICENSE] Login for user %s denied.", self->login_username); - xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR, text); + g_snprintf(raptortext, 255, "[LICENSE] Maximum concurrent session"); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext); + g_snprintf(raptortext, 255, "[LICENSE] limit exceeded for group."); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext); + g_snprintf(raptortext, 255, "[LICENSE] Login for user %s denied.", self->login_username); + xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext); + g_free(rsmip); raptor_sm_session_terminated(self->login_username); return 1; } @@ -542,10 +554,14 @@ xrdp_mm_setup_mod2(struct xrdp_mm *self, tui8 *guid) self->display = allocdisplay; } self->mod->mod_set_param(self->mod, "ip", rsmip); +#ifdef DISABLE_UNIX_DOMAIN_SOCKETS + use_uds = 0; +#else use_uds = 1; if (g_strcmp(rsmip, "127.0.0.1") != 0) { use_uds = 0; } +#endif } g_free(rsmip); @@ -1432,7 +1448,11 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port) self->usechansrv = 1; /* connect channel redir */ +#ifdef DISABLE_UNIX_DOMAIN_SOCKETS + if (0) +#else if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) +#endif { /* unix socket */ self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); @@ -1577,7 +1597,11 @@ xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s) self->wm->dragging = 0; /* connect channel redir */ +#ifdef DISABLE_UNIX_DOMAIN_SOCKETS + if (0) +#else if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) +#endif { g_snprintf(port, 255, XRDP_CHANSRV_STR, display); } diff --git a/xup/xup.c b/xup/xup.c index 91eb0563..a96c362c 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -32,6 +32,98 @@ #define LLOGLN(_level, _args) \ do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************/ +/** ++ * ++ * @brief checks if there's a server running on a host and port ++ * @param display the display to check + * @return 0 if the port is closed, 1 if it is open + * + */ +static int +check_port_status(const char* host, const char* port) +{ + char text[256]; + int x_running; + int sck; + + struct sockaddr_in servaddr; + int soc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + g_memset( &servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(atoi(port)); + + struct hostent* hostaddr; + hostaddr = gethostbyname(host); + g_memcpy(&servaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length); + + int res = connect(soc, (struct sockaddr*)&servaddr, sizeof(servaddr)); + + close(soc); + + if (res == -1) + { + // Port is closed, no server there! + return 0; + } + else { + // Port is open + return 1; + } +} + +/******************************************************************************/ +/** + * + * @brief checks if there's a server running on a remote display + * @param display the display to check + * @return 0 if there isn't a display running, nonzero otherwise + * + */ +static int +x_server_running_check_remote_port(const char* host, const char* port) +{ + int x_running; + int sck; + + x_running = 0; + x_running += check_port_status(host, port); + + return x_running; +} + +/******************************************************************************/ +static int +wait_for_remote_xserver(const char* host, const char* port) +{ + int i; + + /* give X a bit to start */ + /* wait up to 15 secs for x server to start */ + i = 0; + while (!x_server_running_check_remote_port(host, port)) + { + i++; + if (i > 60) + { + break; + } + g_sleep(250); + } + return 0; +} + + static int lib_mod_process_message(struct mod *mod, struct stream *s); @@ -164,6 +256,18 @@ lib_mod_connect(struct mod *mod) return 1; } + char text[256]; + g_snprintf(text, 255, "allocating resources on %s, please wait...\n\r", mod->ip); + mod->server_msg(mod, text, 0); + + // Prevent an immediate RDP exit + wait_for_remote_xserver(mod->ip, mod->port); + + // FIXME CRITICAL + // Prevent an immediate RDP exit + // Why is this still needed even after waiting for the X11rdp server to start!?!? + g_sleep(5000); + if (g_strcmp(mod->ip, "") == 0) { mod->server_msg(mod, "error - no ip set", 0);