Rework the start session method in SCP
The start session method is reworked to pass a response back to the client. If the method was successful, a session list entry is created. This is different to the provious behaviour, where we created the session list entry unconditionally. This new arrangement means that we need a different way to avoid a race condition where two users may try to create a session at the same time, and end up with the same display. We do this by keeping track of newly allocated displays as part of the SCP connections. When we allocate a display, the SCP connection displays are also taken into account.
This commit is contained in:
+57
-6
@@ -44,6 +44,7 @@ msgno_to_str(unsigned short n)
|
||||
(n == E_EICP_LOGOUT_REQUEST) ? "EICP_LOGOUT_REQUEST" :
|
||||
|
||||
(n == E_EICP_CREATE_SESSION_REQUEST) ? "EICP_CREATE_SESSION_REQUEST" :
|
||||
(n == E_EICP_CREATE_SESSION_RESPONSE) ? "EICP_CREATE_SESSION_RESPONSE" :
|
||||
|
||||
NULL;
|
||||
}
|
||||
@@ -244,6 +245,23 @@ eicp_get_sys_login_response(struct trans *trans,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_send_uds_login_request(struct trans *trans,
|
||||
int scp_fd)
|
||||
{
|
||||
return libipm_msg_out_simple_send(
|
||||
trans, (int)E_EICP_UDS_LOGIN_REQUEST, "h", scp_fd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_get_uds_login_request(struct trans *trans,
|
||||
int *scp_fd)
|
||||
{
|
||||
return libipm_msg_in_parse( trans, "h", scp_fd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_send_logout_request(struct trans *trans)
|
||||
@@ -255,7 +273,6 @@ eicp_send_logout_request(struct trans *trans)
|
||||
|
||||
int
|
||||
eicp_send_create_session_request(struct trans *trans,
|
||||
int scp_fd,
|
||||
unsigned int display,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
@@ -267,8 +284,7 @@ eicp_send_create_session_request(struct trans *trans,
|
||||
return libipm_msg_out_simple_send(
|
||||
trans,
|
||||
(int)E_EICP_CREATE_SESSION_REQUEST,
|
||||
"huyqqyss",
|
||||
scp_fd,
|
||||
"uyqqyss",
|
||||
display,
|
||||
type,
|
||||
width,
|
||||
@@ -282,7 +298,6 @@ eicp_send_create_session_request(struct trans *trans,
|
||||
|
||||
int
|
||||
eicp_get_create_session_request(struct trans *trans,
|
||||
int *scp_fd,
|
||||
unsigned int *display,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *width,
|
||||
@@ -300,8 +315,7 @@ eicp_get_create_session_request(struct trans *trans,
|
||||
|
||||
int rv = libipm_msg_in_parse(
|
||||
trans,
|
||||
"huyqqyss",
|
||||
scp_fd,
|
||||
"uyqqyss",
|
||||
&i_display,
|
||||
&i_type,
|
||||
&i_width,
|
||||
@@ -322,3 +336,40 @@ eicp_get_create_session_request(struct trans *trans,
|
||||
|
||||
return rv;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_send_create_session_response(struct trans *trans,
|
||||
enum scp_screate_status status,
|
||||
const struct guid *guid)
|
||||
{
|
||||
struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
||||
return libipm_msg_out_simple_send(
|
||||
trans, (int)E_EICP_CREATE_SESSION_RESPONSE,
|
||||
"iB", status, &guid_descriptor);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_get_create_session_response(struct trans *trans,
|
||||
enum scp_screate_status *status,
|
||||
struct guid *guid)
|
||||
{
|
||||
/* Intermediate values */
|
||||
int32_t i_status;
|
||||
|
||||
const struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
||||
int rv = libipm_msg_in_parse(
|
||||
trans,
|
||||
"iB",
|
||||
&i_status,
|
||||
&guid_descriptor);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
*status = (enum scp_screate_status)i_status;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
+78
-14
@@ -45,11 +45,14 @@ enum eicp_msg_code
|
||||
E_EICP_SYS_LOGIN_REQUEST,
|
||||
E_EICP_SYS_LOGIN_RESPONSE,
|
||||
|
||||
E_EICP_UDS_LOGIN_REQUEST,
|
||||
// No E_EIC_UDS_LOGIN response
|
||||
|
||||
E_EICP_LOGOUT_REQUEST,
|
||||
// No E_EICP_LOGOUT_RESPONSE
|
||||
|
||||
E_EICP_CREATE_SESSION_REQUEST
|
||||
// No E_EICP_CREATE_SESSION_RESPONSE
|
||||
E_EICP_CREATE_SESSION_REQUEST,
|
||||
E_EICP_CREATE_SESSION_RESPONSE
|
||||
};
|
||||
|
||||
/* Common facilities */
|
||||
@@ -204,7 +207,7 @@ eicp_send_sys_login_response(struct trans *trans,
|
||||
int scp_fd);
|
||||
|
||||
/**
|
||||
* Parses an incoming E_EICP_SYS_LOGIN_RESPONSE (sesexec)
|
||||
* Parses an incoming E_EICP_SYS_LOGIN_RESPONSE (sesman)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] is_logged_in true if the SCP client is logged in
|
||||
@@ -221,6 +224,37 @@ eicp_get_sys_login_response(struct trans *trans,
|
||||
uid_t *uid,
|
||||
int *scp_fd);
|
||||
|
||||
/**
|
||||
* Send an E_EICP_UDS_LOGIN_REQUEST (sesman)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param scp_fd File descriptor attached to the client
|
||||
* @return != 0 for error
|
||||
*
|
||||
* This call is needed if the sesexec process is created after
|
||||
* the UID is known already. It generates no response. It is expected to
|
||||
* succeed, as sesman is expected to have already vetted the caller.
|
||||
*
|
||||
* The file descriptor is closed immediately after it is used by the
|
||||
* recipient.
|
||||
*/
|
||||
int
|
||||
eicp_send_uds_login_request(struct trans *trans,
|
||||
int scp_fd);
|
||||
|
||||
|
||||
/**
|
||||
* Get a E_EICP_UDS_LOGIN_REQUEST (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] scp_fd File descriptor attached to the client
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_get_uds_login_request(struct trans *trans,
|
||||
int *scp_fd);
|
||||
|
||||
|
||||
/**
|
||||
* Send an E_EICP_LOGOUT_REQUEST (sesexec)
|
||||
*
|
||||
@@ -238,7 +272,6 @@ eicp_send_logout_request(struct trans *trans);
|
||||
* Send an E_EICP_CREATE_SESSION_REQUEST (sesman)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param scp_fd SCP file descriptor from sesman client
|
||||
* @param display X display number to use
|
||||
* @param type Session type
|
||||
* @param width Initial session width
|
||||
@@ -248,20 +281,17 @@ eicp_send_logout_request(struct trans *trans);
|
||||
* @param directory Directory to run the program in. May be ""
|
||||
* @return != 0 for error
|
||||
*
|
||||
* The UID for the session comes from one of two places:-
|
||||
* - The UID for a sys login request is used if one has successfully
|
||||
* been executed.
|
||||
* - If no sys login request is used, the UID is taken from the scp_fd
|
||||
* The UID for the session must have been set by a previous call.
|
||||
*
|
||||
* Following a successful request, the session creation can be
|
||||
* considered to be underway. The result of this operation is
|
||||
* conveyed back to the caller as an ERCP event. The caller must use
|
||||
* ercp_trans_from_eicp_trans() on 'trans' to convert the transport to
|
||||
* an ERCP transport to receive this (and other) session run-time events.
|
||||
* conveyed back to the caller as one or more ERCP messages. The caller
|
||||
* must use ercp_trans_from_eicp_trans() on 'trans' to convert the
|
||||
* transport to an ERCP transport to receive this (and other) session
|
||||
* run-time events.
|
||||
*/
|
||||
int
|
||||
eicp_send_create_session_request(struct trans *trans,
|
||||
int scp_fd,
|
||||
unsigned int display,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
@@ -275,7 +305,6 @@ eicp_send_create_session_request(struct trans *trans,
|
||||
* Parse an incoming E_EICP_CREATE_SESSION_REQUEST (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] scp_fd SCP file descriptor from sesman client
|
||||
* @param[out] display X display number to use
|
||||
* @param[out] type Session type
|
||||
* @param[out] width Initial session width
|
||||
@@ -290,7 +319,6 @@ eicp_send_create_session_request(struct trans *trans,
|
||||
*/
|
||||
int
|
||||
eicp_get_create_session_request(struct trans *trans,
|
||||
int *scp_fd,
|
||||
unsigned int *display,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *width,
|
||||
@@ -299,4 +327,40 @@ eicp_get_create_session_request(struct trans *trans,
|
||||
const char **shell,
|
||||
const char **directory);
|
||||
|
||||
/**
|
||||
* Send an E_EICP_CREATE_SESSION_RESPONSE
|
||||
*
|
||||
* Direction : sesexec -> sesman
|
||||
*
|
||||
* This event is in response to an E_EICP_CREATE_SESSION_REQUEST
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param status Status of creation request
|
||||
* @param guid GUID of session
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_send_create_session_response(struct trans *trans,
|
||||
enum scp_screate_status status,
|
||||
const struct guid *guid);
|
||||
|
||||
|
||||
/**
|
||||
* Parse an E_EICP_CREATE_SESSION_RESPONSE
|
||||
*
|
||||
* Direction : sesexec -> sesman
|
||||
*
|
||||
* This event is in response to an E_EICP_CREATE_SESSION_REQUEST
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] status Status of creation request
|
||||
* @param[out] guid GUID of session
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_get_create_session_response(struct trans *trans,
|
||||
enum scp_screate_status *status,
|
||||
struct guid *guid);
|
||||
|
||||
|
||||
#endif /* EICP_H */
|
||||
|
||||
@@ -40,6 +40,8 @@ msgno_to_str(unsigned short n)
|
||||
return
|
||||
(n == E_ERCP_SESSION_ANNOUNCE_EVENT) ? "ERCP_SESSION_ANNOUNCE_EVENT" :
|
||||
(n == E_ERCP_SESSION_FINISHED_EVENT) ? "ERCP_SESSION_FINISHED_EVENT" :
|
||||
|
||||
(n == E_ERCP_SESSION_RECONNECT_EVENT) ? "ERCP_SESSION_RECONNECT_EVENT" :
|
||||
NULL;
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -44,10 +44,10 @@ struct guid;
|
||||
/* Message codes */
|
||||
enum ercp_msg_code
|
||||
{
|
||||
E_ERCP_SESSION_ANNOUNCE_EVENT,
|
||||
E_ERCP_SESSION_FINISHED_EVENT,
|
||||
E_ERCP_SESSION_ANNOUNCE_EVENT, // sesexec -> sesman
|
||||
E_ERCP_SESSION_FINISHED_EVENT, // sesexec -> sesman
|
||||
|
||||
E_ERCP_SESSION_RECONNECT_EVENT
|
||||
E_ERCP_SESSION_RECONNECT_EVENT // sesman -> sesexec
|
||||
};
|
||||
|
||||
/* Common facilities */
|
||||
@@ -225,8 +225,6 @@ ercp_get_session_announce_event(struct trans *trans,
|
||||
int
|
||||
ercp_send_session_finished_event(struct trans *trans);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send an E_ERCP_SESSION_RECONNECT_EVENT
|
||||
*
|
||||
|
||||
@@ -69,6 +69,7 @@ scp_screate_status_to_str(enum scp_screate_status n,
|
||||
(n == E_SCP_SCREATE_NO_DISPLAY) ? "No X displays are available" :
|
||||
(n == E_SCP_SCREATE_X_SERVER_FAIL) ? "X server could not be started" :
|
||||
(n == E_SCP_SCREATE_SESSION_FAIL) ? "Session failed immediately" :
|
||||
(n == E_SCP_SCREATE_IN_PROGRESS) ? "Session creation is already in progress" :
|
||||
(n == E_SCP_SCREATE_GENERAL_ERROR) ? "General session creation error" :
|
||||
/* Default */ NULL;
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ enum scp_screate_status
|
||||
E_SCP_SCREATE_NO_DISPLAY, ///< No X server display number is available
|
||||
E_SCP_SCREATE_X_SERVER_FAIL, ///< X server could not be started
|
||||
E_SCP_SCREATE_SESSION_FAIL, ///< The session failed quickly
|
||||
E_SCP_SCREATE_IN_PROGRESS, ///< A create session request is in progress
|
||||
E_SCP_SCREATE_GENERAL_ERROR ///< An unspecific error has occurred
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ sbin_PROGRAMS = \
|
||||
xrdp-sesman
|
||||
|
||||
xrdp_sesman_SOURCES = \
|
||||
display_utils.c \
|
||||
display_utils.h \
|
||||
eicp_process.c \
|
||||
eicp_process.h \
|
||||
ercp_process.c \
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2025
|
||||
*
|
||||
* 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 display_utils.c
|
||||
* @brief Definition of utility calls related to display handling
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "display_utils.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "sesman.h"
|
||||
#include "sesman_config.h"
|
||||
#include "set_int.h"
|
||||
#include "xrdp_sockets.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* @brief checks if there's a server running on a display
|
||||
* @param display the display to check
|
||||
* @return 0 if there isn't a display running, nonzero otherwise
|
||||
*
|
||||
*/
|
||||
static int
|
||||
x_server_running_check_ports(int display)
|
||||
{
|
||||
char text[256];
|
||||
int x_running;
|
||||
int sck;
|
||||
|
||||
(void)snprintf(text, sizeof(text), X11_UNIX_SOCKET_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
(void)snprintf(text, sizeof(text), "/tmp/.X%d-lock", display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running) /* check 59xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
(void)snprintf(text, sizeof(text), "59%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (!x_running) /* check 60xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
(void)snprintf(text, sizeof(text), "60%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (!x_running) /* check 62xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
(void)snprintf(text, sizeof(text), "62%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
|
||||
}
|
||||
|
||||
return x_running;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
display_utils_get_free_display(const struct set_int *alloc_displays)
|
||||
{
|
||||
int display;
|
||||
|
||||
for (display = g_cfg->sess.x11_display_offset;
|
||||
(unsigned int)display <= g_cfg->sess.max_display_number;
|
||||
++display)
|
||||
{
|
||||
// Have we already allocated this one?
|
||||
if (!set_int_contains(alloc_displays, display))
|
||||
{
|
||||
if (!x_server_running_check_ports(display))
|
||||
{
|
||||
return display;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"X server -- no display in range (%d to %d) is available",
|
||||
g_cfg->sess.x11_display_offset,
|
||||
g_cfg->sess.max_display_number);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2025
|
||||
*
|
||||
* 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 display_utils.h
|
||||
* @brief Declaration of utility calls related to display handling
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DISPLAY_UTILS_H
|
||||
#define DISPLAY_UTILS_H
|
||||
|
||||
struct set_int;
|
||||
|
||||
/**
|
||||
* @brief Gets a free display number
|
||||
*
|
||||
* @param Displays already allocated (or being allocated) by sesman
|
||||
* @return next available display, or -1 if none.
|
||||
*/
|
||||
int
|
||||
display_utils_get_free_display(const struct set_int *alloc_displays);
|
||||
|
||||
#endif // DISPLAY_UTILS_H
|
||||
@@ -32,12 +32,15 @@
|
||||
|
||||
#include "eicp.h"
|
||||
#include "eicp_process.h"
|
||||
#include "ercp.h"
|
||||
#include "os_calls.h"
|
||||
#include "scp_list.h"
|
||||
#include "session_list.h"
|
||||
#include "scp.h"
|
||||
#include "sesman.h"
|
||||
#include "sesman_access.h"
|
||||
#include "sesman_config.h"
|
||||
#include "guid.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -92,6 +95,61 @@ process_sys_login_response(struct scp_list_item *sli)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
process_create_session_response(struct scp_list_item *sli)
|
||||
{
|
||||
struct session_item *s_item;
|
||||
int display = -1;
|
||||
struct guid guid;
|
||||
enum scp_screate_status status;
|
||||
|
||||
int rv = eicp_get_create_session_response(sli->sesexec_trans,
|
||||
&status, &guid);
|
||||
if (rv == 0)
|
||||
{
|
||||
// Create an entry on the session list for the new session
|
||||
if (status == E_SCP_SCREATE_OK &&
|
||||
(s_item = session_list_new()) == NULL)
|
||||
{
|
||||
status = E_SCP_SCREATE_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (status == E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Further comms from sesexec comes over the ERCP
|
||||
// protocol
|
||||
ercp_trans_from_eicp_trans(sli->sesexec_trans,
|
||||
sesman_ercp_data_in,
|
||||
(void *)s_item);
|
||||
|
||||
// Move the new ERCP transport over to the session list item,
|
||||
// and initialise enough data so that a connection request
|
||||
// can be serviced.
|
||||
s_item->sesexec_trans = sli->sesexec_trans;
|
||||
s_item->sesexec_pid = sli->sesexec_pid;
|
||||
s_item->guid = guid;
|
||||
s_item->uid = sli->uid;
|
||||
s_item->display = sli->session_display;
|
||||
display = s_item->display;
|
||||
|
||||
// We don't use the sesexec process again
|
||||
sli->sesexec_trans = NULL;
|
||||
sli->sesexec_pid = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
guid_clear(&guid);
|
||||
display = -1;
|
||||
}
|
||||
rv = scp_send_create_session_response(sli->client_trans, status,
|
||||
display, &guid);
|
||||
sli->create_session_in_progress = 0;
|
||||
sli->session_display = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
/******************************************************************************/
|
||||
int
|
||||
eicp_process(struct scp_list_item *sli)
|
||||
@@ -105,6 +163,10 @@ eicp_process(struct scp_list_item *sli)
|
||||
rv = process_sys_login_response(sli);
|
||||
break;
|
||||
|
||||
case E_EICP_CREATE_SESSION_RESPONSE:
|
||||
rv = process_create_session_response(sli);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
|
||||
+22
-1
@@ -33,6 +33,7 @@
|
||||
#include "list.h"
|
||||
#include "os_calls.h"
|
||||
#include "scp_list.h"
|
||||
#include "set_int.h"
|
||||
#include "trans.h"
|
||||
|
||||
#define SCP_LIST_ITEM_IN_USE(sli) \
|
||||
@@ -125,7 +126,7 @@ scp_list_item_new(void)
|
||||
{
|
||||
g_snprintf(result->peername, sizeof(result->peername), "unknown");
|
||||
result->uid = (uid_t) -1;
|
||||
|
||||
result->session_display = -1;
|
||||
if (!list_add_item(g_scp_list, (tintptr)result))
|
||||
{
|
||||
g_free(result);
|
||||
@@ -259,3 +260,23 @@ scp_list_check_wait_objs(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
scp_list_get_create_session_displays(struct set_int *alloc_displays)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < g_scp_list->count; ++i)
|
||||
{
|
||||
struct scp_list_item *sli;
|
||||
|
||||
sli = (struct scp_list_item *)list_get_item(g_scp_list, i);
|
||||
|
||||
if (SCP_LIST_ITEM_IN_USE(sli) &&
|
||||
sli->create_session_in_progress &&
|
||||
sli->session_display >= 0)
|
||||
{
|
||||
set_int_add(alloc_displays, sli->session_display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
struct set_int;
|
||||
|
||||
/**
|
||||
* Type describing the login state of an SCP list item
|
||||
*/
|
||||
@@ -83,6 +85,8 @@ struct scp_list_item
|
||||
char *username; ///< Username from UID (at time of logon)
|
||||
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
|
||||
int is_admin;
|
||||
int create_session_in_progress; ///< Already handling a create_session
|
||||
unsigned int session_display; ///< Display allocated for create_session
|
||||
};
|
||||
|
||||
|
||||
@@ -151,4 +155,12 @@ scp_list_get_wait_objs(tbus robjs[], int *robjs_count);
|
||||
int
|
||||
scp_list_check_wait_objs(void);
|
||||
|
||||
/**
|
||||
* @brief Get all create-session displays
|
||||
*
|
||||
* Adds displays allocated to create-session operations to a set
|
||||
*/
|
||||
void
|
||||
scp_list_get_create_session_displays(struct set_int *alloc_displays);
|
||||
|
||||
#endif // SCP_LIST_H
|
||||
|
||||
+69
-59
@@ -31,15 +31,16 @@
|
||||
#include "trans.h"
|
||||
#include "os_calls.h"
|
||||
#include "eicp.h"
|
||||
#include "ercp.h"
|
||||
#include "scp.h"
|
||||
|
||||
#include "display_utils.h"
|
||||
#include "scp_process.h"
|
||||
#include "sesman.h"
|
||||
#include "sesman_access.h"
|
||||
#include "sesman_auth.h"
|
||||
#include "sesman_config.h"
|
||||
#include "os_calls.h"
|
||||
#include "set_int.h"
|
||||
#include "scp_list.h"
|
||||
#include "session_list.h"
|
||||
#include "sesexec_control.h"
|
||||
@@ -389,13 +390,45 @@ create_xrdp_socket_path(uid_t uid)
|
||||
#undef RWX_PERMS
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Gets a free display number
|
||||
*
|
||||
* We can't use displays either allocated to sessions, or being used to
|
||||
* create sessions
|
||||
*/
|
||||
static int
|
||||
get_free_display(void)
|
||||
{
|
||||
int result = -1;
|
||||
struct set_int *alloc_displays;
|
||||
|
||||
alloc_displays = set_int_init(g_cfg->sess.x11_display_offset,
|
||||
g_cfg->sess.max_display_number);
|
||||
|
||||
if (alloc_displays != NULL)
|
||||
{
|
||||
// Get all the displays either allocated to sessions, or
|
||||
// potentially assigned to sessions on the SCP list
|
||||
session_list_get_session_displays(alloc_displays);
|
||||
scp_list_get_create_session_displays(alloc_displays);
|
||||
|
||||
// Find a free display, taking the allocated ones into account
|
||||
result = display_utils_get_free_display(alloc_displays);
|
||||
|
||||
set_int_delete(alloc_displays);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_create_session_request(struct scp_list_item *sli)
|
||||
{
|
||||
int rv;
|
||||
/* Client parameters describing new session*/
|
||||
/* Client parameters describing new session */
|
||||
enum scp_session_type type;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
@@ -404,8 +437,9 @@ process_create_session_request(struct scp_list_item *sli)
|
||||
const char *directory;
|
||||
|
||||
struct guid guid;
|
||||
int display = 0;
|
||||
int display = -1;
|
||||
struct session_item *s_item = NULL;
|
||||
int start_sesexec = (sli->sesexec_trans == NULL);
|
||||
int send_client_reply = 1;
|
||||
|
||||
enum scp_screate_status status = E_SCP_SCREATE_OK;
|
||||
@@ -420,6 +454,10 @@ process_create_session_request(struct scp_list_item *sli)
|
||||
{
|
||||
status = E_SCP_SCREATE_NOT_LOGGED_IN;
|
||||
}
|
||||
else if (sli->create_session_in_progress)
|
||||
{
|
||||
status = E_SCP_SCREATE_IN_PROGRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
@@ -433,29 +471,6 @@ process_create_session_request(struct scp_list_item *sli)
|
||||
// Found an existing session
|
||||
display = s_item->display;
|
||||
guid = s_item->guid;
|
||||
|
||||
// Tell the existing session to run the reconnect script.
|
||||
// We ignore errors at this level, as any comms errors
|
||||
// will be picked up in the main loop
|
||||
(void)ercp_send_session_reconnect_event(s_item->sesexec_trans);
|
||||
|
||||
if (sli->start_ip_addr[0] != '\0')
|
||||
{
|
||||
LOG( LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d, ip %s",
|
||||
sli->username, display,
|
||||
s_item->sesexec_pid, sli->start_ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d",
|
||||
sli->username, display, s_item->sesexec_pid);
|
||||
}
|
||||
|
||||
// If we created an authentication process for this SCP
|
||||
// connection, close it gracefully
|
||||
logout_scp_list_item(sli);
|
||||
}
|
||||
// Need to create a new session
|
||||
else if (g_cfg->sess.max_sessions > 0 &&
|
||||
@@ -463,34 +478,42 @@ process_create_session_request(struct scp_list_item *sli)
|
||||
{
|
||||
status = E_SCP_SCREATE_MAX_REACHED;
|
||||
}
|
||||
else if ((display = session_list_get_available_display()) < 0)
|
||||
else if ((display = get_free_display()) < 0)
|
||||
{
|
||||
status = E_SCP_SCREATE_NO_DISPLAY;
|
||||
}
|
||||
// Create an entry on the session list for the new session
|
||||
else if ((s_item = session_list_new()) == NULL)
|
||||
{
|
||||
status = E_SCP_SCREATE_NO_MEMORY;
|
||||
}
|
||||
// Create a socket dir for this user
|
||||
else if (create_xrdp_socket_path(sli->uid) != 0)
|
||||
{
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
// Create a sesexec process if we don't have one (UDS login)
|
||||
else if (sli->sesexec_trans == NULL && sesexec_start(sli) != 0)
|
||||
else if (start_sesexec && sesexec_start(sli) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't start sesexec to manage session");
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
else if (start_sesexec &&
|
||||
eicp_send_uds_login_request(
|
||||
sli->sesexec_trans, sli->client_trans->sck) != 0)
|
||||
{
|
||||
// Because we started sesexec late, we needed to log it in.
|
||||
// That hasn't gone too well.
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't set UID for sesexec process");
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
|
||||
// Looks like sesexec is broken...
|
||||
trans_delete(sli->sesexec_trans);
|
||||
sli->sesexec_trans = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass the session create request to sesexec
|
||||
int eicp_stat;
|
||||
eicp_stat = eicp_send_create_session_request(
|
||||
sli->sesexec_trans,
|
||||
sli->client_trans->sck,
|
||||
display,
|
||||
type, width, height,
|
||||
bpp, shell, directory);
|
||||
@@ -498,42 +521,29 @@ process_create_session_request(struct scp_list_item *sli)
|
||||
if (eicp_stat != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't ask sesexec to authenticate user");
|
||||
"Can't ask sesexec to create a session");
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
// Looks like sesexec is broken...
|
||||
trans_delete(sli->sesexec_trans);
|
||||
sli->sesexec_trans = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've handed over responsibility for the
|
||||
// SCP communication
|
||||
// We're not sending a reply yet
|
||||
send_client_reply = 0;
|
||||
|
||||
// Further comms from sesexec comes over the ERCP
|
||||
// protocol
|
||||
ercp_trans_from_eicp_trans(sli->sesexec_trans,
|
||||
sesman_ercp_data_in,
|
||||
(void *)s_item);
|
||||
|
||||
// Move the transport over to the session list item
|
||||
s_item->sesexec_trans = sli->sesexec_trans;
|
||||
s_item->sesexec_pid = sli->sesexec_pid;
|
||||
sli->sesexec_trans = NULL;
|
||||
sli->sesexec_pid = 0;
|
||||
|
||||
// Add the display to the session item so we don't try
|
||||
// to allocate it to another session
|
||||
s_item->display = display;
|
||||
sli->create_session_in_progress = 1;
|
||||
sli->session_display = display; // Reserve display
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Currently a create session request is the last thing on a
|
||||
// connection, and results in automatic closure
|
||||
//
|
||||
// We may have passed the client_trans over to sesexec. If so,
|
||||
// we can't send a reply here.
|
||||
sli->dispatcher_action = E_SLD_TERMINATE_SCP_CONN;
|
||||
if (send_client_reply)
|
||||
{
|
||||
if (status != E_SCP_SCREATE_OK)
|
||||
{
|
||||
display = -1;
|
||||
guid_clear(&guid);
|
||||
}
|
||||
rv = scp_send_create_session_response(sli->client_trans,
|
||||
status, display, &guid);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,13 @@ handle_sys_login_request(struct trans *self)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_login_info != NULL)
|
||||
{
|
||||
// Shouldn't get here. Prevent a memory leak.
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Asked to sys login when a login has already been made");
|
||||
login_info_free(g_login_info);
|
||||
}
|
||||
g_login_info = login_info_sys_login_user(scp_trans, username,
|
||||
password, ip_addr);
|
||||
|
||||
@@ -84,6 +91,46 @@ handle_sys_login_request(struct trans *self)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_uds_login_request(struct trans *self)
|
||||
{
|
||||
int scp_fd;
|
||||
|
||||
int rv = eicp_get_uds_login_request(self, &scp_fd);
|
||||
if (rv == 0)
|
||||
{
|
||||
struct trans *scp_trans;
|
||||
scp_trans = scp_init_trans_from_fd(scp_fd, TRANS_TYPE_SERVER,
|
||||
sesexec_is_term);
|
||||
if (scp_trans == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create SCP trans");
|
||||
g_file_close(scp_fd);
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_login_info != NULL)
|
||||
{
|
||||
// Shouldn't get here. Prevent a memory leak.
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Asked to UDS login when a login has already been made");
|
||||
login_info_free(g_login_info);
|
||||
}
|
||||
// The following call logs errors, but these are not
|
||||
// returned to the caller, as the call is expected to succeed.
|
||||
if ((g_login_info = login_info_uds_login_user(scp_trans)) == NULL)
|
||||
{
|
||||
rv = 1;
|
||||
}
|
||||
trans_delete(scp_trans);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_logout_request(struct trans *self)
|
||||
@@ -97,56 +144,40 @@ handle_logout_request(struct trans *self)
|
||||
static int
|
||||
handle_create_session_request(struct trans *self)
|
||||
{
|
||||
int scp_fd;
|
||||
struct session_parameters sp = {0};
|
||||
int status;
|
||||
|
||||
status = eicp_get_create_session_request(
|
||||
self, &scp_fd, &sp.display,
|
||||
self, &sp.display,
|
||||
&sp.type, &sp.width, &sp.height,
|
||||
&sp.bpp, &sp.shell, &sp.directory);
|
||||
if (status == 0)
|
||||
{
|
||||
// Need to talk to the SCP client
|
||||
struct trans *scp_trans;
|
||||
scp_trans = scp_init_trans_from_fd(scp_fd, TRANS_TYPE_SERVER,
|
||||
sesexec_is_term);
|
||||
if (scp_trans == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create SCP trans");
|
||||
g_file_close(scp_fd);
|
||||
status = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum scp_screate_status scp_status = E_SCP_SCREATE_OK;
|
||||
|
||||
// Use the UID from the SCP connection if the user hasn't
|
||||
// explicitly logged in
|
||||
if (g_login_info == NULL &&
|
||||
(g_login_info = login_info_uds_login_user(scp_trans)) == NULL)
|
||||
// Must be logged in to start a session
|
||||
if (g_login_info == NULL)
|
||||
{
|
||||
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
scp_status = E_SCP_SCREATE_NOT_LOGGED_IN;
|
||||
}
|
||||
|
||||
if (scp_status == E_SCP_SCREATE_OK)
|
||||
else
|
||||
{
|
||||
// Try to create the session
|
||||
sp.guid = guid_new();
|
||||
scp_status = session_start(g_login_info, &sp, &g_session_data);
|
||||
}
|
||||
|
||||
// Return the creation status to sesman.
|
||||
status = eicp_send_create_session_response(self, scp_status, &sp.guid);
|
||||
if (status == 0 && scp_status == E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Further comms to sesman is sent over the ERCP protocol
|
||||
ercp_trans_from_eicp_trans(self,
|
||||
sesexec_ercp_data_in,
|
||||
(void *)self);
|
||||
|
||||
if (scp_status != E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Tell sesman the session hasn't started
|
||||
(void)ercp_send_session_finished_event(self);
|
||||
}
|
||||
else if ((status = ercp_send_session_announce_event(
|
||||
// Announce the session to sesman
|
||||
if ((status = ercp_send_session_announce_event(
|
||||
self,
|
||||
sp.display,
|
||||
g_login_info->uid,
|
||||
@@ -171,24 +202,15 @@ handle_create_session_request(struct trans *self)
|
||||
// new one
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"sesman appears to have failed - stopping session");
|
||||
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
else if ((status = sesexec_discover_enable()) != 0)
|
||||
{
|
||||
// Equally regrettable - we can't make the session
|
||||
// discoverable, so we'll stop it. We can tell sesman
|
||||
// about this one however.
|
||||
// discoverable, so we'll stop it.
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"unable to make session discoverable"
|
||||
" - stopping session");
|
||||
(void)ercp_send_session_finished_event(self);
|
||||
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
// Return the status to the SCP client.
|
||||
(void)scp_send_create_session_response(scp_trans, scp_status,
|
||||
sp.display, &sp.guid);
|
||||
trans_delete(scp_trans);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +235,10 @@ eicp_server(struct trans *self)
|
||||
rv = handle_sys_login_request(self);
|
||||
break;
|
||||
|
||||
case E_EICP_UDS_LOGIN_REQUEST:
|
||||
rv = handle_uds_login_request(self);
|
||||
break;
|
||||
|
||||
case E_EICP_LOGOUT_REQUEST:
|
||||
rv = handle_logout_request(self);
|
||||
break;
|
||||
|
||||
@@ -1086,6 +1086,8 @@ session_send_term(struct session_data *sd, int wait_for_all)
|
||||
g_sigterm(sd->win_mgr);
|
||||
}
|
||||
|
||||
if (wait_for_all)
|
||||
{
|
||||
while (session_active(sd))
|
||||
{
|
||||
/* Don't check SIGTERM - we shouldn't be here long */
|
||||
@@ -1103,6 +1105,7 @@ session_send_term(struct session_data *sd, int wait_for_all)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
+15
-168
@@ -42,6 +42,7 @@
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "sesman.h"
|
||||
#include "set_int.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_sockets.h"
|
||||
|
||||
@@ -56,20 +57,19 @@ static struct list *g_session_list = NULL;
|
||||
int
|
||||
session_list_init(void)
|
||||
{
|
||||
int rv = 1;
|
||||
int rv = 0;
|
||||
if (g_session_list == NULL)
|
||||
{
|
||||
g_session_list = list_create_sized(g_cfg->sess.max_sessions);
|
||||
}
|
||||
|
||||
if (g_session_list == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't allocate session list");
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_session_list->auto_free = 0;
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -119,7 +119,7 @@ session_list_cleanup(void)
|
||||
unsigned int
|
||||
session_list_get_count(void)
|
||||
{
|
||||
return g_session_list->count;
|
||||
return (g_session_list == NULL) ? 0 : g_session_list->count;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -159,175 +159,22 @@ session_list_new(void)
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* @brief checks if there's a server running on a display
|
||||
* @param display the display to check
|
||||
* @return 0 if there isn't a display running, nonzero otherwise
|
||||
*
|
||||
*/
|
||||
static int
|
||||
x_server_running_check_ports(int display)
|
||||
void
|
||||
session_list_get_session_displays(struct set_int *alloc_displays)
|
||||
{
|
||||
char text[256];
|
||||
int x_running;
|
||||
int sck;
|
||||
int count = (g_session_list == NULL) ? 0 : g_session_list->count;
|
||||
|
||||
g_snprintf(text, sizeof(text), X11_UNIX_SOCKET_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
int i = 0;
|
||||
for (i = 0 ; i < count ; ++i)
|
||||
{
|
||||
struct session_item *si;
|
||||
si = (struct session_item *)list_get_item(g_session_list, i);
|
||||
|
||||
if (!x_running)
|
||||
if (SESSION_IN_USE(si))
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_snprintf(text, sizeof(text), "/tmp/.X%d-lock", display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running) /* check 59xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_snprintf(text, sizeof(text), "59%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
set_int_add(alloc_displays, si->display);
|
||||
}
|
||||
}
|
||||
|
||||
if (!x_running) /* check 60xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_snprintf(text, sizeof(text), "60%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (!x_running) /* check 62xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_snprintf(text, sizeof(text), "62%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
|
||||
}
|
||||
|
||||
return x_running;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Helper function for get_sorted_display_list():qsort() */
|
||||
static int
|
||||
icmp(const void *v1, const void *v2)
|
||||
{
|
||||
// Pointers point to unsigned ints
|
||||
unsigned int i1 = *(unsigned int *)v1;
|
||||
unsigned int i2 = *(unsigned int *)v2;
|
||||
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Get a sorted array of all the displays allocated to sessions
|
||||
* @param[out] cnt Count of displays in list
|
||||
* @return Allocated array of displays or NULL for no memory
|
||||
*
|
||||
* Result must always be freed, even if cnt == 0
|
||||
*/
|
||||
|
||||
static unsigned int *
|
||||
get_sorted_session_displays(unsigned int *cnt)
|
||||
{
|
||||
unsigned int *displays;
|
||||
|
||||
*cnt = 0;
|
||||
displays = g_new(unsigned int, session_list_get_count() + 1);
|
||||
if (displays == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't allocate memory for display list");
|
||||
}
|
||||
else if (g_session_list != NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < g_session_list->count ; ++i)
|
||||
{
|
||||
const struct session_item *si;
|
||||
si = (const struct session_item *)list_get_item(g_session_list, i);
|
||||
if (SESSION_IN_USE(si) && si->display >= 0)
|
||||
{
|
||||
displays[(*cnt)++] = si->display;
|
||||
}
|
||||
}
|
||||
qsort(displays, *cnt, sizeof(displays[0]), icmp);
|
||||
}
|
||||
|
||||
return displays;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_get_available_display(void)
|
||||
{
|
||||
int rv = -1;
|
||||
unsigned int max_alloc = 0;
|
||||
|
||||
// Find all displays already allocated. We do this to prevent
|
||||
// unnecessary file system accesses, and also to prevent us allocating
|
||||
// the same display number to two callers who call in quick
|
||||
// succession i.e. if the first caller has not created its X server
|
||||
// by the time we service the second request
|
||||
unsigned int *allocated_displays = get_sorted_session_displays(&max_alloc);
|
||||
if (allocated_displays != NULL)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int display;
|
||||
|
||||
for (display = g_cfg->sess.x11_display_offset;
|
||||
display <= g_cfg->sess.max_display_number;
|
||||
++display)
|
||||
{
|
||||
// Have we already allocated this one?
|
||||
while (i < max_alloc && display > allocated_displays[i])
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < max_alloc && display == allocated_displays[i])
|
||||
{
|
||||
continue; // Already allocated
|
||||
}
|
||||
|
||||
if (!x_server_running_check_ports(display))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(allocated_displays);
|
||||
|
||||
if (display > g_cfg->sess.max_display_number)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"X server -- no display in range (%d to %d) is available",
|
||||
g_cfg->sess.x11_display_offset,
|
||||
g_cfg->sess.max_display_number);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = display;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "scp_application_types.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
struct set_int;
|
||||
|
||||
enum session_state
|
||||
{
|
||||
/**
|
||||
@@ -116,13 +118,12 @@ struct session_item *
|
||||
session_list_new(void);
|
||||
|
||||
/**
|
||||
* Get the next available display
|
||||
* @brief Get all session displays
|
||||
*
|
||||
* The display isn't reserved until the caller has allocated a new session
|
||||
* (with session_list_new()) and put the new display in it.
|
||||
* Adds displays allocated to sessions to a set
|
||||
*/
|
||||
int
|
||||
session_list_get_available_display(void);
|
||||
void
|
||||
session_list_get_session_displays(struct set_int *alloc_displays);
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user