Merge pull request #2592 from matt335672/restructure_session_start
Restructure session start
This commit is contained in:
commit
3ee8eb9c9e
@ -1343,6 +1343,13 @@ g_sleep(int msecs)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_pipe(int fd[2])
|
||||
{
|
||||
return pipe(fd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_sck_last_error_would_block(int sck)
|
||||
@ -2291,6 +2298,24 @@ mode_t_to_hex(mode_t mode)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Duplicates a file descriptor onto another one using the semantics
|
||||
* of dup2() */
|
||||
/* return boolean */
|
||||
int
|
||||
g_file_duplicate_on(int fd, int target_fd)
|
||||
{
|
||||
int rv = (dup2(fd, target_fd) >= 0);
|
||||
|
||||
if (rv < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't clone file %d as file %d [%s]",
|
||||
fd, target_fd, g_get_strerror());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns error */
|
||||
int
|
||||
@ -2998,9 +3023,11 @@ g_set_allusercontext(int uid)
|
||||
#endif
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32
|
||||
returns pid of process that exits or zero if signal occurred */
|
||||
returns pid of process that exits or zero if signal occurred
|
||||
an exit_status struct can optionally be passed in to get the
|
||||
exit status of the child */
|
||||
int
|
||||
g_waitchild(void)
|
||||
g_waitchild(struct exit_status *e)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return 0;
|
||||
@ -3008,15 +3035,36 @@ g_waitchild(void)
|
||||
int wstat;
|
||||
int rv;
|
||||
|
||||
struct exit_status dummy;
|
||||
|
||||
if (e == NULL)
|
||||
{
|
||||
e = &dummy; // Set this, then throw it away
|
||||
}
|
||||
|
||||
e->reason = E_XR_UNEXPECTED;
|
||||
e->val = 0;
|
||||
|
||||
rv = waitpid(0, &wstat, WNOHANG);
|
||||
|
||||
if (rv == -1)
|
||||
{
|
||||
if (errno == EINTR) /* signal occurred */
|
||||
if (errno == EINTR)
|
||||
{
|
||||
/* This shouldn't happen as signal handlers use SA_RESTART */
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
else if (WIFEXITED(wstat))
|
||||
{
|
||||
e->reason = E_XR_STATUS_CODE;
|
||||
e->val = WEXITSTATUS(wstat);
|
||||
}
|
||||
else if (WIFSIGNALED(wstat))
|
||||
{
|
||||
e->reason = E_XR_SIGNAL;
|
||||
e->val = WTERMSIG(wstat);
|
||||
}
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
@ -3024,7 +3072,10 @@ g_waitchild(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32
|
||||
returns pid of process that exits or <= 0 if no process was found */
|
||||
returns pid of process that exits or <= 0 if no process was found
|
||||
|
||||
Note that signal handlers are established with BSD-style semantics,
|
||||
so this call is NOT interrupted by a signal */
|
||||
int
|
||||
g_waitpid(int pid)
|
||||
{
|
||||
@ -3048,25 +3099,21 @@ g_waitpid(int pid)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32
|
||||
returns exit status code of child process with pid */
|
||||
returns exit status code of child process with pid
|
||||
|
||||
Note that signal handlers are established with BSD-style semantics,
|
||||
so this call is NOT interrupted by a signal */
|
||||
struct exit_status
|
||||
g_waitpid_status(int pid)
|
||||
{
|
||||
struct exit_status exit_status;
|
||||
|
||||
#if defined(_WIN32)
|
||||
exit_status.exit_code = -1;
|
||||
exit_status.signal_no = 0;
|
||||
return exit_status;
|
||||
#else
|
||||
int rv;
|
||||
int status;
|
||||
|
||||
exit_status.exit_code = -1;
|
||||
exit_status.signal_no = 0;
|
||||
struct exit_status exit_status = {.reason = E_XR_UNEXPECTED, .val = 0};
|
||||
|
||||
#if !defined(_WIN32)
|
||||
if (pid > 0)
|
||||
{
|
||||
int rv;
|
||||
int status;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "waiting for pid %d to exit", pid);
|
||||
rv = waitpid(pid, &status, 0);
|
||||
|
||||
@ -3074,11 +3121,13 @@ g_waitpid_status(int pid)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
exit_status.exit_code = WEXITSTATUS(status);
|
||||
exit_status.reason = E_XR_STATUS_CODE;
|
||||
exit_status.val = WEXITSTATUS(status);
|
||||
}
|
||||
if (WIFSIGNALED(status))
|
||||
{
|
||||
exit_status.signal_no = WTERMSIG(status);
|
||||
exit_status.reason = E_XR_SIGNAL;
|
||||
exit_status.val = WTERMSIG(status);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3087,8 +3136,8 @@ g_waitpid_status(int pid)
|
||||
}
|
||||
}
|
||||
|
||||
return exit_status;
|
||||
#endif
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -23,13 +23,17 @@
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
enum exit_reason
|
||||
{
|
||||
E_XR_STATUS_CODE = 0, ///< 'val' contains exit status
|
||||
E_XR_SIGNAL, ///< 'val' contains a signal number
|
||||
E_XR_UNEXPECTED
|
||||
};
|
||||
|
||||
struct exit_status
|
||||
{
|
||||
/* set to -1 when the process exited via a signal */
|
||||
uint8_t exit_code;
|
||||
|
||||
/* set to 0 when the process exited normally */
|
||||
uint8_t signal_no;
|
||||
enum exit_reason reason;
|
||||
int val;
|
||||
};
|
||||
|
||||
struct list;
|
||||
@ -173,6 +177,8 @@ const char *
|
||||
g_sck_get_peer_description(int sck,
|
||||
char *desc, unsigned int bytes);
|
||||
void g_sleep(int msecs);
|
||||
int g_pipe(int fd[2]);
|
||||
|
||||
tintptr g_create_wait_obj(const char *name);
|
||||
tintptr g_create_wait_obj_from_socket(tintptr socket, int write);
|
||||
void g_delete_wait_obj_from_socket(tintptr wait_obj);
|
||||
@ -208,6 +214,7 @@ int g_file_read(int fd, char *ptr, int len);
|
||||
int g_file_write(int fd, const char *ptr, int len);
|
||||
int g_file_seek(int fd, int offset);
|
||||
int g_file_lock(int fd, int start, int len);
|
||||
int g_file_duplicate_on(int fd, int target_fd);
|
||||
int g_chmod_hex(const char *filename, int flags);
|
||||
int g_umask_hex(int flags);
|
||||
int g_chown(const char *name, int uid, int gid);
|
||||
@ -268,7 +275,7 @@ int g_setlogin(const char *name);
|
||||
*/
|
||||
int g_set_allusercontext(int uid);
|
||||
#endif
|
||||
int g_waitchild(void);
|
||||
int g_waitchild(struct exit_status *e);
|
||||
int g_waitpid(int pid);
|
||||
struct exit_status g_waitpid_status(int pid);
|
||||
void g_clearenv(void);
|
||||
|
@ -66,7 +66,8 @@ scp_screate_status_to_str(enum scp_screate_status n,
|
||||
(n == E_SCP_SCREATE_NO_MEMORY) ? "No memory for session" :
|
||||
(n == E_SCP_SCREATE_NOT_LOGGED_IN) ? "Connection is not logged in" :
|
||||
(n == E_SCP_SCREATE_MAX_REACHED) ? "Max session limit reached" :
|
||||
(n == E_SCP_SCREATE_NO_DISPLAY) ? "No X displays are avaiable" :
|
||||
(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_GENERAL_ERROR) ? "General session creation error" :
|
||||
/* Default */ NULL;
|
||||
|
||||
|
@ -95,6 +95,7 @@ enum scp_screate_status
|
||||
E_SCP_SCREATE_NOT_LOGGED_IN, ///< Connection is not logged in
|
||||
E_SCP_SCREATE_MAX_REACHED, ///< Max number of sessions already reached
|
||||
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_GENERAL_ERROR ///< An unspecific error has occurred
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,8 @@ xrdp_sesman_SOURCES = \
|
||||
sesman.h \
|
||||
session.c \
|
||||
session.h \
|
||||
session_list.c \
|
||||
session_list.h \
|
||||
sig.c \
|
||||
sig.h \
|
||||
xauth.c \
|
||||
|
@ -1522,7 +1522,7 @@ child_signal_handler(int sig)
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "child_signal_handler:");
|
||||
do
|
||||
{
|
||||
pid = g_waitchild();
|
||||
pid = g_waitchild(NULL);
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "child_signal_handler: child pid %d", pid);
|
||||
if ((pid == g_exec_pid) && (pid > 0))
|
||||
{
|
||||
|
@ -31,11 +31,14 @@
|
||||
#include "trans.h"
|
||||
#include "os_calls.h"
|
||||
#include "scp.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "scp_process.h"
|
||||
#include "access.h"
|
||||
#include "auth.h"
|
||||
#include "guid.h"
|
||||
#include "os_calls.h"
|
||||
#include "session_list.h"
|
||||
#include "session.h"
|
||||
#include "sesman.h"
|
||||
#include "string_calls.h"
|
||||
@ -154,8 +157,8 @@ authenticate_and_authorize_connection(struct sesman_con *sc,
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
|
||||
username);
|
||||
LOG(LOG_LEVEL_INFO, "Access permitted for user=%s uid=%d",
|
||||
username, uid);
|
||||
sc->auth_info = auth_info;
|
||||
sc->uid = uid;
|
||||
sc->username = dup_username;
|
||||
@ -195,6 +198,82 @@ process_set_peername_request(struct sesman_con *sc)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Allocates a chain item and starts the session
|
||||
*/
|
||||
static enum scp_screate_status
|
||||
allocate_and_start_session(struct auth_info *auth_info,
|
||||
const char *username,
|
||||
const char *ip_addr,
|
||||
const struct session_parameters *params)
|
||||
{
|
||||
int pid = 0;
|
||||
struct session_chain *temp = (struct session_chain *)NULL;
|
||||
enum scp_screate_status status;
|
||||
|
||||
/* check to limit concurrent sessions */
|
||||
if (session_list_get_count() >= (unsigned int)g_cfg->sess.max_sessions)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "max concurrent session limit "
|
||||
"exceeded. login for user %s denied", username);
|
||||
return E_SCP_SCREATE_MAX_REACHED;
|
||||
}
|
||||
|
||||
temp = (struct session_chain *)g_malloc(sizeof(struct session_chain), 0);
|
||||
|
||||
if (temp == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
|
||||
"chain element - user %s", username);
|
||||
return E_SCP_SCREATE_NO_MEMORY;
|
||||
}
|
||||
|
||||
temp->item = (struct session_item *)g_malloc(sizeof(struct session_item), 0);
|
||||
|
||||
if (temp->item == 0)
|
||||
{
|
||||
g_free(temp);
|
||||
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
|
||||
"item - user %s", username);
|
||||
return E_SCP_SCREATE_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = session_start(auth_info, params, &pid);
|
||||
if (status == E_SCP_SCREATE_OK)
|
||||
{
|
||||
if (ip_addr[0] != '\0')
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "++ created session: username %s, ip %s",
|
||||
username, ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "++ created session: username %s", username);
|
||||
}
|
||||
|
||||
temp->item->pid = pid;
|
||||
temp->item->display = params->display;
|
||||
temp->item->width = params->width;
|
||||
temp->item->height = params->height;
|
||||
temp->item->bpp = params->bpp;
|
||||
temp->item->auth_info = auth_info;
|
||||
g_strncpy(temp->item->start_ip_addr, ip_addr,
|
||||
sizeof(temp->item->start_ip_addr) - 1);
|
||||
temp->item->uid = params->uid;
|
||||
temp->item->guid = params->guid;
|
||||
|
||||
temp->item->start_time = g_time1();
|
||||
|
||||
temp->item->type = params->type;
|
||||
temp->item->status = SESMAN_SESSION_STATUS_ACTIVE;
|
||||
|
||||
session_list_add(temp);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
@ -377,16 +456,21 @@ static int
|
||||
process_create_session_request(struct sesman_con *sc)
|
||||
{
|
||||
int rv;
|
||||
struct session_parameters sp;
|
||||
struct guid guid;
|
||||
int display = 0;
|
||||
// Parameters for a new session (if required). Filled in as
|
||||
// we go along.
|
||||
struct session_parameters sp = {0};
|
||||
const char *shellptr;
|
||||
const char *dirptr;
|
||||
enum scp_screate_status status = E_SCP_SCREATE_OK;
|
||||
|
||||
int display = 0;
|
||||
struct guid guid;
|
||||
|
||||
guid_clear(&guid);
|
||||
|
||||
rv = scp_get_create_session_request(sc->t,
|
||||
&sp.type, &sp.width, &sp.height,
|
||||
&sp.bpp, &sp.shell, &sp.directory);
|
||||
&sp.bpp, &shellptr, &dirptr);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
@ -397,63 +481,79 @@ process_create_session_request(struct sesman_con *sc)
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Received request from %s to create a session for user %s",
|
||||
sc->peername, sc->username);
|
||||
"Received request from %s to create a session for user %s"
|
||||
" type=%s"
|
||||
" geometry=%dx%d, bpp=%d, shell=\"%s\", dir=\"%s\"",
|
||||
sc->peername, sc->username,
|
||||
SCP_SESSION_TYPE_TO_STR(sp.type),
|
||||
sp.width, sp.height, sp.bpp, shellptr, dirptr);
|
||||
|
||||
// Copy over the items we got from the login request,
|
||||
// but which we need to describe the session
|
||||
sp.uid = sc->uid;
|
||||
sp.ip_addr = sc->ip_addr; // Guaranteed to be non-NULL
|
||||
|
||||
struct session_item *s_item = session_get_bydata(&sp);
|
||||
struct session_item *s_item =
|
||||
session_list_get_bydata(sc->uid, sp.type, sp.width, sp.height,
|
||||
sp.bpp, sc->ip_addr);
|
||||
if (s_item != 0)
|
||||
{
|
||||
// Found an existing session
|
||||
display = s_item->display;
|
||||
guid = s_item->guid;
|
||||
if (sp.ip_addr[0] != '\0')
|
||||
if (sc->ip_addr[0] != '\0')
|
||||
{
|
||||
LOG( LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d, ip %s",
|
||||
sc->username, display, s_item->pid, sp.ip_addr);
|
||||
sc->username, s_item->display, s_item->pid,
|
||||
sc->ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d",
|
||||
sc->username, display, s_item->pid);
|
||||
sc->username, s_item->display, s_item->pid);
|
||||
}
|
||||
|
||||
session_reconnect(display, sc->uid, sc->auth_info);
|
||||
// Get values for response to SCP client
|
||||
display = s_item->display;
|
||||
guid = s_item->guid;
|
||||
|
||||
session_reconnect(s_item->display, sc->uid, sc->auth_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to create a new session
|
||||
if (sp.ip_addr[0] != '\0')
|
||||
//
|
||||
// Get the rest of the parameters for the session
|
||||
guid = guid_new();
|
||||
display = session_list_get_available_display();
|
||||
|
||||
sp.display = display;
|
||||
sp.uid = sc->uid;
|
||||
sp.guid = guid;
|
||||
// These need to be copied so they are available
|
||||
// when the sub-process closes all the connections
|
||||
g_snprintf(sp.shell, sizeof(sp.shell), "%s", shellptr);
|
||||
g_snprintf(sp.directory, sizeof(sp.directory), "%s", dirptr);
|
||||
|
||||
if (display == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"++ created session: username %s, ip %s",
|
||||
sc->username, sp.ip_addr);
|
||||
status = E_SCP_SCREATE_NO_DISPLAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"++ created session: username %s", sc->username);
|
||||
}
|
||||
// The new session will have a lifetime longer than
|
||||
// the sesman connection, and so needs to own
|
||||
// the auth_info struct.
|
||||
//
|
||||
// Copy the auth_info struct out of the connection and pass
|
||||
// it to the session
|
||||
struct auth_info *auth_info = sc->auth_info;
|
||||
sc->auth_info = NULL;
|
||||
|
||||
// The new session will have a lifetime longer than
|
||||
// the sesman connection, and so needs to own
|
||||
// the auth_info struct.
|
||||
//
|
||||
// Copy the auth_info struct out of the connection and pass
|
||||
// it to the session
|
||||
struct auth_info *auth_info = sc->auth_info;
|
||||
sc->auth_info = NULL;
|
||||
status = session_start(auth_info, &sp, &display, &guid);
|
||||
if (status != E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Close the auth session down as it can't be re-used.
|
||||
auth_end(auth_info);
|
||||
status = allocate_and_start_session(auth_info,
|
||||
sc->username,
|
||||
sc->ip_addr,
|
||||
&sp);
|
||||
if (status != E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Close the auth session down as it can't be re-used.
|
||||
auth_end(auth_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -462,7 +562,8 @@ process_create_session_request(struct sesman_con *sc)
|
||||
* connection, and results in automatic closure */
|
||||
sc->close_requested = 1;
|
||||
|
||||
rv = scp_send_create_session_response(sc->t, status, display, &guid);
|
||||
rv = scp_send_create_session_response(sc->t, status,
|
||||
display, &guid);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -491,8 +592,8 @@ process_list_sessions_request(struct sesman_con *sc)
|
||||
"Received request from %s to list sessions for user %s",
|
||||
sc->peername, sc->username);
|
||||
|
||||
info = session_get_byuid(sc->uid, &cnt,
|
||||
SESMAN_SESSION_STATUS_ALL);
|
||||
info = session_list_get_byuid(sc->uid, &cnt,
|
||||
SESMAN_SESSION_STATUS_ALL);
|
||||
|
||||
for (i = 0; rv == 0 && i < cnt; ++i)
|
||||
{
|
||||
@ -575,4 +676,3 @@ scp_process(struct sesman_con *sc)
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -74,9 +74,9 @@ struct sesman_startup_params
|
||||
|
||||
struct config_sesman *g_cfg;
|
||||
unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 };
|
||||
tintptr g_term_event = 0;
|
||||
tintptr g_sigchld_event = 0;
|
||||
tintptr g_reload_event = 0;
|
||||
static tintptr g_term_event = 0;
|
||||
static tintptr g_sigchld_event = 0;
|
||||
static tintptr g_reload_event = 0;
|
||||
|
||||
static struct trans *g_list_trans;
|
||||
|
||||
@ -322,6 +322,15 @@ sesman_close_all(unsigned int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
sesman_delete_wait_objects(void)
|
||||
{
|
||||
g_delete_wait_obj(g_reload_event);
|
||||
g_delete_wait_obj(g_sigchld_event);
|
||||
g_delete_wait_obj(g_term_event);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
sesman_data_in(struct trans *self)
|
||||
@ -965,9 +974,7 @@ main(int argc, char **argv)
|
||||
g_file_delete(pid_file);
|
||||
}
|
||||
|
||||
g_delete_wait_obj(g_reload_event);
|
||||
g_delete_wait_obj(g_sigchld_event);
|
||||
g_delete_wait_obj(g_term_event);
|
||||
sesman_delete_wait_objects();
|
||||
|
||||
if (!daemon)
|
||||
{
|
||||
|
@ -45,9 +45,6 @@ struct sesman_con
|
||||
/* Globals */
|
||||
extern struct config_sesman *g_cfg;
|
||||
extern unsigned char g_fixedkey[8];
|
||||
extern tintptr g_term_event;
|
||||
extern tintptr g_sigchld_event;
|
||||
extern tintptr g_reload_event;
|
||||
|
||||
/**
|
||||
* Set the peername of a connection
|
||||
@ -58,7 +55,7 @@ extern tintptr g_reload_event;
|
||||
int
|
||||
sesman_set_connection_peername(struct sesman_con *sc, const char *name);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Close all file descriptors used by sesman.
|
||||
*
|
||||
* This is generally used after forking, to make sure the
|
||||
@ -75,6 +72,14 @@ sesman_set_connection_peername(struct sesman_con *sc, const char *name);
|
||||
int
|
||||
sesman_close_all(unsigned int flags);
|
||||
|
||||
/**
|
||||
* Delete sesman wait objects.
|
||||
*
|
||||
* Call after forking so we don't break sesman's wait objects
|
||||
*/
|
||||
void
|
||||
sesman_delete_wait_objects(void);
|
||||
|
||||
/*
|
||||
* Remove the listening transport
|
||||
*
|
||||
|
2044
sesman/session.c
2044
sesman/session.c
File diff suppressed because it is too large
Load Diff
150
sesman/session.h
150
sesman/session.h
@ -34,161 +34,43 @@
|
||||
#include "scp_application_types.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
#define SESMAN_SESSION_STATUS_ACTIVE 0x01
|
||||
#define SESMAN_SESSION_STATUS_IDLE 0x02
|
||||
#define SESMAN_SESSION_STATUS_DISCONNECTED 0x04
|
||||
/* future expansion
|
||||
#define SESMAN_SESSION_STATUS_REMCONTROL 0x08
|
||||
*/
|
||||
#define SESMAN_SESSION_STATUS_ALL 0xFF
|
||||
|
||||
enum session_kill_status
|
||||
{
|
||||
SESMAN_SESSION_KILL_OK = 0,
|
||||
SESMAN_SESSION_KILL_NULLITEM,
|
||||
SESMAN_SESSION_KILL_NOTFOUND
|
||||
};
|
||||
|
||||
struct scp_session_info;
|
||||
|
||||
struct session_item
|
||||
{
|
||||
int uid; /* UID of session */
|
||||
int pid; /* pid of sesman waiting for wm to end */
|
||||
int display;
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
struct auth_info *auth_info;
|
||||
|
||||
/* status info */
|
||||
unsigned char status;
|
||||
enum scp_session_type type;
|
||||
|
||||
/* time data */
|
||||
time_t start_time;
|
||||
// struct session_date disconnect_time; // Currently unused
|
||||
// struct session_date idle_time; // Currently unused
|
||||
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
|
||||
struct guid guid;
|
||||
};
|
||||
|
||||
struct session_chain
|
||||
{
|
||||
struct session_chain *next;
|
||||
struct session_item *item;
|
||||
};
|
||||
|
||||
struct auth_info;
|
||||
|
||||
/**
|
||||
* Information used to start or find a session
|
||||
* Information used to start a session
|
||||
*/
|
||||
struct session_parameters
|
||||
{
|
||||
unsigned int display;
|
||||
int uid;
|
||||
struct guid guid;
|
||||
enum scp_session_type type;
|
||||
unsigned short height;
|
||||
unsigned short width;
|
||||
unsigned char bpp;
|
||||
const char *shell;
|
||||
const char *directory;
|
||||
const char *ip_addr;
|
||||
char shell[INFO_CLIENT_MAX_CB_LEN];
|
||||
char directory[INFO_CLIENT_MAX_CB_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief finds a session matching the supplied parameters
|
||||
* @return session data or 0
|
||||
*
|
||||
*/
|
||||
struct session_item *
|
||||
session_get_bydata(const struct session_parameters *params);
|
||||
#ifndef session_find_item
|
||||
#define session_find_item(a) session_get_bydata(a)
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief starts a session
|
||||
*
|
||||
* @return Connection status.
|
||||
* @param auth_info Authentication info
|
||||
* @param s Session parameters
|
||||
* @param[out] pid PID of sub-process
|
||||
* @return status
|
||||
*
|
||||
* The returned PID is only valid if the status returned is
|
||||
* E_SCP_SCREATE_OK
|
||||
*/
|
||||
enum scp_screate_status
|
||||
session_start(struct auth_info *auth_info,
|
||||
const struct session_parameters *params,
|
||||
int *display,
|
||||
struct guid *guid);
|
||||
const struct session_parameters *s,
|
||||
int *pid);
|
||||
|
||||
int
|
||||
session_reconnect(int display, int uid,
|
||||
struct auth_info *auth_info);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief kills a session
|
||||
* @param pid the pid of the session to be killed
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
enum session_kill_status
|
||||
session_kill(int pid);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief sends sigkill to all sessions
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
void
|
||||
session_sigkill_all(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief retrieves a session's descriptor
|
||||
* @param pid the session pid
|
||||
* @return a pointer to the session descriptor on success, NULL otherwise
|
||||
*
|
||||
*/
|
||||
struct session_item *
|
||||
session_get_bypid(int pid);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief retrieves session descriptions
|
||||
* @param UID the UID for the descriptions
|
||||
* @return A block of session descriptions
|
||||
*
|
||||
* Pass the return result to free_session_info_list() after use
|
||||
*
|
||||
*/
|
||||
struct scp_session_info *
|
||||
session_get_byuid(int uid, unsigned int *cnt, unsigned char flags);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Frees the result of session_get_byuser()
|
||||
* @param sesslist Resuit of session_get_byuser()
|
||||
* @param cnt Number of entries in sess
|
||||
*/
|
||||
void
|
||||
free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief delete socket files
|
||||
* @param display number
|
||||
* @return non-zero value (number of errors) if failed
|
||||
*/
|
||||
int cleanup_sockets(int display);
|
||||
|
||||
/**
|
||||
* Clone a session_parameters structure
|
||||
*
|
||||
* @param sp Parameters to clone
|
||||
* @return Cloned parameters, or NULL if no memory
|
||||
*
|
||||
* The cloned structure can be free'd with a single call to g_free()
|
||||
*/
|
||||
struct session_parameters *
|
||||
clone_session_params(const struct session_parameters *sp);
|
||||
#endif
|
||||
#endif // SESSION_H
|
||||
|
582
sesman/session_list.c
Normal file
582
sesman/session_list.c
Normal file
@ -0,0 +1,582 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2015
|
||||
*
|
||||
* BSD process grouping by:
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland.
|
||||
* Copyright (c) 2000-2001 Markus Friedl.
|
||||
* Copyright (c) 2011-2015 Koichiro Iwao, Kyushu Institute of Technology.
|
||||
*
|
||||
* 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 session_list.c
|
||||
* @brief Session list management code
|
||||
* @author Jay Sorg, Simone Fedele
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "arch.h"
|
||||
#include "session_list.h"
|
||||
|
||||
#include "auth.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "sesman.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_sockets.h"
|
||||
|
||||
static struct session_chain *g_sessions;
|
||||
static int g_session_count;
|
||||
|
||||
/******************************************************************************/
|
||||
unsigned int
|
||||
session_list_get_count(void)
|
||||
{
|
||||
return g_session_count;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
session_list_add(struct session_chain *element)
|
||||
{
|
||||
element->next = g_sessions;
|
||||
g_sessions = element;
|
||||
g_session_count++;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct session_item *
|
||||
session_list_get_bydata(uid_t uid,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned char bpp,
|
||||
const char *ip_addr)
|
||||
{
|
||||
char policy_str[64];
|
||||
struct session_chain *tmp;
|
||||
int policy = g_cfg->sess.policy;
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_DEFAULT) != 0)
|
||||
{
|
||||
/* In the past (i.e. xrdp before v0.9.14), the default
|
||||
* session policy varied by type. If this is needed again
|
||||
* in the future, here is the place to add it */
|
||||
policy = SESMAN_CFG_SESS_POLICY_U | SESMAN_CFG_SESS_POLICY_B;
|
||||
}
|
||||
|
||||
config_output_policy_string(policy, policy_str, sizeof(policy_str));
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: search policy=%s type=%s U=%d B=%d D=(%dx%d) I=%s",
|
||||
__func__,
|
||||
policy_str, SCP_SESSION_TYPE_TO_STR(type),
|
||||
uid, bpp, width, height,
|
||||
ip_addr);
|
||||
|
||||
/* 'Separate' policy never matches */
|
||||
if (policy & SESMAN_CFG_SESS_POLICY_SEPARATE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: No matches possible", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (tmp = g_sessions ; tmp != 0 ; tmp = tmp->next)
|
||||
{
|
||||
struct session_item *item = tmp->item;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: try %p type=%s U=%d B=%d D=(%dx%d) I=%s",
|
||||
__func__,
|
||||
item,
|
||||
SCP_SESSION_TYPE_TO_STR(item->type),
|
||||
item->uid,
|
||||
item->bpp,
|
||||
item->width, item->height,
|
||||
item->start_ip_addr);
|
||||
|
||||
if (item->type != type)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: Type doesn't match", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_U) && (int)uid != item->uid)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: UID doesn't match for 'U' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_B) && item->bpp != bpp)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: bpp doesn't match for 'B' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_D) &&
|
||||
(item->width != width || item->height != height))
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: Dimensions don't match for 'D' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_I) &&
|
||||
g_strcmp(item->start_ip_addr, ip_addr) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: IPs don't match for 'I' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: Got match, display=%d", __func__, item->display);
|
||||
return item;
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: No matches found", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
|
||||
g_sprintf(text, "/tmp/.X11-unix/X%d", display);
|
||||
x_running = g_file_exist(text);
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(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_sprintf(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)
|
||||
{
|
||||
g_sprintf(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_sprintf(text, "62%2.2d", display);
|
||||
x_running = g_tcp_bind(sck, text);
|
||||
g_tcp_close(sck);
|
||||
}
|
||||
}
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, XRDP_CHANSRV_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);
|
||||
g_sprintf(text, CHANSRV_PORT_OUT_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);
|
||||
g_sprintf(text, CHANSRV_PORT_IN_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);
|
||||
g_sprintf(text, CHANSRV_API_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);
|
||||
g_sprintf(text, XRDP_X11RDP_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
|
||||
}
|
||||
|
||||
return x_running;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* called with the main thread
|
||||
returns boolean */
|
||||
static int
|
||||
is_display_in_chain(int display)
|
||||
{
|
||||
struct session_chain *chain;
|
||||
struct session_item *item;
|
||||
|
||||
chain = g_sessions;
|
||||
|
||||
while (chain != 0)
|
||||
{
|
||||
item = chain->item;
|
||||
|
||||
if (item->display == display)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
chain = chain->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_get_available_display(void)
|
||||
{
|
||||
int display;
|
||||
|
||||
display = g_cfg->sess.x11_display_offset;
|
||||
|
||||
while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions)
|
||||
{
|
||||
if (!is_display_in_chain(display))
|
||||
{
|
||||
if (!x_server_running_check_ports(display))
|
||||
{
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
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.x11_display_offset + g_cfg->sess.max_sessions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Convert a UID to a username
|
||||
*
|
||||
* @param uid UID
|
||||
* @param uname pointer to output buffer
|
||||
* @param uname_len Length of output buffer
|
||||
* @return 0 for success.
|
||||
*/
|
||||
static int
|
||||
username_from_uid(int uid, char *uname, int uname_len)
|
||||
{
|
||||
char *ustr;
|
||||
int rv = g_getuser_info_by_uid(uid, &ustr, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
g_snprintf(uname, uname_len, "%s", ustr);
|
||||
g_free(ustr);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_snprintf(uname, uname_len, "<unknown>");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
enum session_kill_status
|
||||
session_list_kill(int pid)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
struct session_chain *prev;
|
||||
|
||||
tmp = g_sessions;
|
||||
prev = 0;
|
||||
|
||||
while (tmp != 0)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session descriptor for "
|
||||
"pid %d is null!", pid);
|
||||
|
||||
if (prev == 0)
|
||||
{
|
||||
/* prev does no exist, so it's the first element - so we set
|
||||
g_sessions */
|
||||
g_sessions = tmp->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
|
||||
return SESMAN_SESSION_KILL_NULLITEM;
|
||||
}
|
||||
|
||||
if (tmp->item->pid == pid)
|
||||
{
|
||||
char username[256];
|
||||
username_from_uid(tmp->item->uid, username, sizeof(username));
|
||||
|
||||
/* deleting the session */
|
||||
if (tmp->item->auth_info != NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Calling auth_end for pid %d from pid %d",
|
||||
pid, g_getpid());
|
||||
auth_end(tmp->item->auth_info);
|
||||
tmp->item->auth_info = NULL;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"++ terminated session: UID %d (%s), display :%d.0, "
|
||||
"session_pid %d, ip %s",
|
||||
tmp->item->uid, username, tmp->item->display,
|
||||
tmp->item->pid, tmp->item->start_ip_addr);
|
||||
g_free(tmp->item);
|
||||
|
||||
if (prev == 0)
|
||||
{
|
||||
/* prev does no exist, so it's the first element - so we set
|
||||
g_sessions */
|
||||
g_sessions = tmp->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
|
||||
g_free(tmp);
|
||||
g_session_count--;
|
||||
return SESMAN_SESSION_KILL_OK;
|
||||
}
|
||||
|
||||
/* go on */
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return SESMAN_SESSION_KILL_NOTFOUND;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
session_list_sigkill_all(void)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
|
||||
tmp = g_sessions;
|
||||
|
||||
while (tmp != 0)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "found null session descriptor!");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_sigterm(tmp->item->pid);
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct session_item *
|
||||
session_list_get_bypid(int pid)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
struct session_item *dummy;
|
||||
|
||||
dummy = g_new0(struct session_item, 1);
|
||||
|
||||
if (0 == dummy)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session_get_bypid: out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = g_sessions;
|
||||
|
||||
while (tmp != 0)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session descriptor for pid %d is null!", pid);
|
||||
g_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tmp->item->pid == pid)
|
||||
{
|
||||
g_memcpy(dummy, tmp->item, sizeof(struct session_item));
|
||||
return dummy;
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct scp_session_info *
|
||||
session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
struct scp_session_info *sess;
|
||||
int count;
|
||||
int index;
|
||||
|
||||
count = 0;
|
||||
|
||||
tmp = g_sessions;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "searching for session by UID: %d", uid);
|
||||
while (tmp != 0)
|
||||
{
|
||||
if (uid == tmp->item->uid)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "session_list_get_byuid: status=%d, flags=%d, "
|
||||
"result=%d", (tmp->item->status), flags,
|
||||
((tmp->item->status) & flags));
|
||||
|
||||
if ((tmp->item->status) & flags)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
(*cnt) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* malloc() an array of disconnected sessions */
|
||||
sess = g_new0(struct scp_session_info, count);
|
||||
|
||||
if (sess == 0)
|
||||
{
|
||||
(*cnt) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = g_sessions;
|
||||
index = 0;
|
||||
|
||||
while (tmp != 0 && index < count)
|
||||
{
|
||||
if (uid == tmp->item->uid)
|
||||
{
|
||||
if ((tmp->item->status) & flags)
|
||||
{
|
||||
(sess[index]).sid = tmp->item->pid;
|
||||
(sess[index]).display = tmp->item->display;
|
||||
(sess[index]).type = tmp->item->type;
|
||||
(sess[index]).height = tmp->item->height;
|
||||
(sess[index]).width = tmp->item->width;
|
||||
(sess[index]).bpp = tmp->item->bpp;
|
||||
(sess[index]).start_time = tmp->item->start_time;
|
||||
(sess[index]).uid = tmp->item->uid;
|
||||
(sess[index]).start_ip_addr = g_strdup(tmp->item->start_ip_addr);
|
||||
|
||||
/* Check for string allocation failures */
|
||||
if ((sess[index]).start_ip_addr == NULL)
|
||||
{
|
||||
free_session_info_list(sess, *cnt);
|
||||
(*cnt) = 0;
|
||||
return 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
(*cnt) = count;
|
||||
return sess;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt)
|
||||
{
|
||||
if (sesslist != NULL && cnt > 0)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0 ; i < cnt ; ++i)
|
||||
{
|
||||
g_free(sesslist[i].start_ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(sesslist);
|
||||
}
|
171
sesman/session_list.h
Normal file
171
sesman/session_list.h
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2013
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file session_list.h
|
||||
* @brief Session list management definitions
|
||||
* @author Jay Sorg, Simone Fedele
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SESSION_LIST_H
|
||||
#define SESSION_LIST_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "guid.h"
|
||||
#include "scp_application_types.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
struct session_parameters;
|
||||
|
||||
#define SESMAN_SESSION_STATUS_ACTIVE 0x01
|
||||
#define SESMAN_SESSION_STATUS_IDLE 0x02
|
||||
#define SESMAN_SESSION_STATUS_DISCONNECTED 0x04
|
||||
/* future expansion
|
||||
#define SESMAN_SESSION_STATUS_REMCONTROL 0x08
|
||||
*/
|
||||
#define SESMAN_SESSION_STATUS_ALL 0xFF
|
||||
|
||||
enum session_kill_status
|
||||
{
|
||||
SESMAN_SESSION_KILL_OK = 0,
|
||||
SESMAN_SESSION_KILL_NULLITEM,
|
||||
SESMAN_SESSION_KILL_NOTFOUND
|
||||
};
|
||||
|
||||
struct scp_session_info;
|
||||
|
||||
/**
|
||||
* Object describing a session
|
||||
*/
|
||||
struct session_item
|
||||
{
|
||||
int uid; /* UID of session */
|
||||
int pid; /* pid of sesman waiting for wm to end */
|
||||
int display;
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
struct auth_info *auth_info;
|
||||
|
||||
/* status info */
|
||||
unsigned char status;
|
||||
enum scp_session_type type;
|
||||
|
||||
/* time data */
|
||||
time_t start_time;
|
||||
// struct session_date disconnect_time; // Currently unused
|
||||
// struct session_date idle_time; // Currently unused
|
||||
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
|
||||
struct guid guid;
|
||||
};
|
||||
|
||||
struct session_chain
|
||||
{
|
||||
struct session_chain *next;
|
||||
struct session_item *item;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of sessions currently active
|
||||
* @return Session count
|
||||
*/
|
||||
unsigned int
|
||||
session_list_get_count(void);
|
||||
|
||||
/**
|
||||
* Adds a new session item to the chain
|
||||
*/
|
||||
void
|
||||
session_list_add(struct session_chain *element);
|
||||
|
||||
/**
|
||||
* Get the next available display
|
||||
*/
|
||||
int
|
||||
session_list_get_available_display(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief finds a session matching the supplied parameters
|
||||
* @return session data or 0
|
||||
*
|
||||
*/
|
||||
struct session_item *
|
||||
session_list_get_bydata(uid_t uid,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned char bpp,
|
||||
const char *ip_addr);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief kills a session
|
||||
* @param pid the pid of the session to be killed
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
enum session_kill_status
|
||||
session_list_kill(int pid);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief sends sigkill to all sessions
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
void
|
||||
session_list_sigkill_all(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief retrieves a session's descriptor
|
||||
* @param pid the session pid
|
||||
* @return a pointer to the session descriptor on success, NULL otherwise
|
||||
*
|
||||
*/
|
||||
struct session_item *
|
||||
session_list_get_bypid(int pid);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief retrieves session descriptions
|
||||
* @param UID the UID for the descriptions
|
||||
* @return A block of session descriptions
|
||||
*
|
||||
* Pass the return result to free_session_info_list() after use
|
||||
*
|
||||
*/
|
||||
struct scp_session_info *
|
||||
session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Frees the result of session_get_byuser()
|
||||
* @param sesslist Resuit of session_get_byuser()
|
||||
* @param cnt Number of entries in sess
|
||||
*/
|
||||
void
|
||||
free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt);
|
||||
|
||||
#endif // SESSION_LIST_H
|
@ -35,7 +35,7 @@
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "sesman.h"
|
||||
#include "session.h"
|
||||
#include "session_list.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
/******************************************************************************/
|
||||
@ -105,13 +105,13 @@ sig_sesman_session_end(void)
|
||||
LOG(LOG_LEVEL_DEBUG, "receiving SIGCHLD");
|
||||
do
|
||||
{
|
||||
pid = g_waitchild();
|
||||
pid = g_waitchild(NULL);
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Process %d has exited", pid);
|
||||
|
||||
session_kill(pid);
|
||||
session_list_kill(pid);
|
||||
}
|
||||
}
|
||||
while (pid > 0);
|
||||
|
166
sesman/xwait.c
166
sesman/xwait.c
@ -2,6 +2,7 @@
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "env.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
@ -9,38 +10,13 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/******************************************************************************/
|
||||
enum xwait_status
|
||||
wait_for_xserver(int display)
|
||||
static void
|
||||
log_waitforx_messages(FILE *dp)
|
||||
{
|
||||
FILE *dp = NULL;
|
||||
enum xwait_status rv = XW_STATUS_MISC_ERROR;
|
||||
int ret;
|
||||
|
||||
char buffer[100];
|
||||
const char exe[] = XRDP_LIBEXEC_PATH "/waitforx";
|
||||
char cmd[sizeof(exe) + 64];
|
||||
|
||||
if (!g_file_exist(exe))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to find %s", exe);
|
||||
return rv;
|
||||
}
|
||||
|
||||
g_snprintf(cmd, sizeof(cmd), "%s -d :%d", exe, display);
|
||||
LOG(LOG_LEVEL_DEBUG, "Waiting for X server to start on display :%d",
|
||||
display);
|
||||
|
||||
dp = popen(cmd, "r");
|
||||
if (dp == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to launch waitforx");
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (fgets(buffer, 100, dp))
|
||||
char buffer[256];
|
||||
while (fgets(buffer, sizeof(buffer), dp))
|
||||
{
|
||||
const char *msg = buffer;
|
||||
enum logLevels level = LOG_LEVEL_ERROR;
|
||||
@ -73,18 +49,136 @@ wait_for_xserver(int display)
|
||||
LOG(level, "waitforx: %s", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = pclose(dp);
|
||||
if (WIFEXITED(ret))
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Contruct the command to run to check the X server
|
||||
*/
|
||||
static struct list *
|
||||
make_xwait_command(int display)
|
||||
{
|
||||
const char exe[] = XRDP_LIBEXEC_PATH "/waitforx";
|
||||
char displaystr[64];
|
||||
|
||||
struct list *cmd = list_create();
|
||||
if (cmd != NULL)
|
||||
{
|
||||
rv = (enum xwait_status)WEXITSTATUS(ret);
|
||||
cmd->auto_free = 1;
|
||||
g_snprintf(displaystr, sizeof(displaystr), ":%d", display);
|
||||
|
||||
if (!list_add_strdup_multi(cmd, exe, "-d", displaystr, NULL))
|
||||
{
|
||||
list_delete(cmd);
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(ret))
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
enum xwait_status
|
||||
wait_for_xserver(uid_t uid,
|
||||
struct list *env_names,
|
||||
struct list *env_values,
|
||||
int display)
|
||||
{
|
||||
enum xwait_status rv = XW_STATUS_MISC_ERROR;
|
||||
int fd[2] = {-1, -1};
|
||||
struct list *cmd = make_xwait_command(display);
|
||||
|
||||
|
||||
// Construct the command to execute to check the display
|
||||
if (cmd == NULL)
|
||||
{
|
||||
int sig = WTERMSIG(ret);
|
||||
LOG(LOG_LEVEL_ERROR, "waitforx failed with unexpected signal %d",
|
||||
sig);
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create xwait command list - no mem");
|
||||
}
|
||||
else if (g_pipe(fd) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create pipe : %s", g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
pid_t pid = g_fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create pipe : %s",
|
||||
g_get_strerror());
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Child process */
|
||||
|
||||
/* Send stdout and stderr up the pipe */
|
||||
g_file_close(fd[0]);
|
||||
g_file_duplicate_on(fd[1], 1);
|
||||
g_file_duplicate_on(fd[1], 2);
|
||||
|
||||
/* Move to the user context... */
|
||||
env_set_user(uid,
|
||||
0,
|
||||
display,
|
||||
env_names,
|
||||
env_values);
|
||||
|
||||
/* ...and run the program */
|
||||
g_execvp_list((const char *)cmd->items[0], cmd);
|
||||
LOG(LOG_LEVEL_ERROR, "Can't run %s - %s",
|
||||
(const char *)cmd->items[0], g_get_strerror());
|
||||
g_exit(rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"Waiting for X server to start on display :%d",
|
||||
display);
|
||||
|
||||
g_file_close(fd[1]);
|
||||
fd[1] = -1;
|
||||
FILE *dp = fdopen(fd[0], "r");
|
||||
if (dp == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to launch waitforx");
|
||||
}
|
||||
else
|
||||
{
|
||||
struct exit_status e;
|
||||
|
||||
fd[0] = -1; // File descriptor closed by fclose()
|
||||
log_waitforx_messages(dp);
|
||||
fclose(dp);
|
||||
e = g_waitpid_status(pid);
|
||||
switch (e.reason)
|
||||
{
|
||||
case E_XR_STATUS_CODE:
|
||||
rv = (enum xwait_status)e.val;
|
||||
break;
|
||||
|
||||
case E_XR_SIGNAL:
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"waitforx failed with unexpected signal %d",
|
||||
e.val);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"waitforx failed with unknown reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fd[0] >= 0)
|
||||
{
|
||||
g_file_close(fd[0]);
|
||||
}
|
||||
|
||||
if (fd[1] >= 0)
|
||||
{
|
||||
g_file_close(fd[1]);
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(cmd);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef XWAIT_H
|
||||
#define XWAIT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
enum xwait_status
|
||||
{
|
||||
XW_STATUS_OK = 0,
|
||||
@ -12,10 +14,16 @@ enum xwait_status
|
||||
/**
|
||||
*
|
||||
* @brief waits for X to start
|
||||
* @param uid User to run program under
|
||||
* @param env_names Environment to set for user (names)
|
||||
* @param env_values Environment to set for user (values)
|
||||
* @param display number
|
||||
* @return status
|
||||
*
|
||||
*/
|
||||
enum xwait_status
|
||||
wait_for_xserver(int display);
|
||||
wait_for_xserver(uid_t uid,
|
||||
struct list *env_names,
|
||||
struct list *env_values,
|
||||
int display);
|
||||
#endif
|
||||
|
@ -89,7 +89,7 @@ xrdp_shutdown(int sig)
|
||||
static void
|
||||
xrdp_child(int sig)
|
||||
{
|
||||
while (g_waitchild() > 0)
|
||||
while (g_waitchild(NULL) > 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user