Merge pull request #2644 from matt335672/split_session_driver
Split sesman into sesman and sesexec
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ NEWS
|
||||
*.o
|
||||
README
|
||||
sesman/chansrv/xrdp-chansrv
|
||||
sesman/sessvc/xrdp-sessvc
|
||||
sesman/sesexec/xrdp-sesexec
|
||||
sesman/tools/xrdp-authtest
|
||||
sesman/tools/xrdp-dis
|
||||
sesman/tools/xrdp-sesadmin
|
||||
|
||||
+36
-10
@@ -133,7 +133,7 @@ g_rm_temp_dir(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_mk_socket_path(const char *app_name)
|
||||
g_mk_socket_path(void)
|
||||
{
|
||||
if (!g_directory_exist(XRDP_SOCKET_PATH))
|
||||
{
|
||||
@@ -176,8 +176,6 @@ g_init(const char *app_name)
|
||||
/* use en_US.UTF-8 instead if not available */
|
||||
setlocale(LC_CTYPE, "en_US.UTF-8");
|
||||
}
|
||||
|
||||
g_mk_socket_path(app_name);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -2160,6 +2158,13 @@ g_file_close(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_file_is_open(int fd)
|
||||
{
|
||||
return (fcntl(fd, F_GETFD) >= 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* read from file, returns the number of bytes read or -1 on error */
|
||||
int
|
||||
@@ -2549,6 +2554,14 @@ g_directory_exist(const char *dirname)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns boolean, non zero if the file exists and is a readable executable */
|
||||
int
|
||||
g_executable_exist(const char *exename)
|
||||
{
|
||||
return access(exename, R_OK | X_OK) == 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns boolean */
|
||||
int
|
||||
@@ -2866,7 +2879,6 @@ g_execlp3(const char *a1, const char *a2, const char *a3)
|
||||
"returned errno: %d, description: %s",
|
||||
a1, args_str, g_get_errno(), g_get_strerror());
|
||||
|
||||
g_mk_socket_path(0);
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
@@ -2976,11 +2988,7 @@ g_fork(void)
|
||||
|
||||
rv = fork();
|
||||
|
||||
if (rv == 0) /* child */
|
||||
{
|
||||
g_mk_socket_path(0);
|
||||
}
|
||||
else if (rv == -1) /* error */
|
||||
if (rv == -1) /* error */
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Process fork failed with errno: %d, description: %s",
|
||||
@@ -3143,7 +3151,7 @@ g_waitchild(struct exit_status *e)
|
||||
e->reason = E_XR_UNEXPECTED;
|
||||
e->val = 0;
|
||||
|
||||
rv = waitpid(0, &wstat, WNOHANG);
|
||||
rv = waitpid(-1, &wstat, WNOHANG);
|
||||
|
||||
if (rv == -1)
|
||||
{
|
||||
@@ -3238,6 +3246,24 @@ g_waitpid_status(int pid)
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_setpgid(int pid, int pgid)
|
||||
{
|
||||
int rv = setpgid(pid, pgid);
|
||||
if (rv < 0)
|
||||
{
|
||||
if (pid == 0)
|
||||
{
|
||||
pid = getpid();
|
||||
}
|
||||
LOG(LOG_LEVEL_ERROR, "Can't set process group ID of %d to %d [%s]",
|
||||
pid, pgid, g_get_strerror());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32 */
|
||||
void
|
||||
|
||||
+17
-1
@@ -53,7 +53,7 @@ struct list;
|
||||
#define g_close_wait_obj g_delete_wait_obj
|
||||
|
||||
int g_rm_temp_dir(void);
|
||||
int g_mk_socket_path(const char *app_name);
|
||||
int g_mk_socket_path(void);
|
||||
void g_init(const char *app_name);
|
||||
void g_deinit(void);
|
||||
void g_printf(const char *format, ...) printflike(1, 2);
|
||||
@@ -210,6 +210,12 @@ int g_file_open(const char *file_name);
|
||||
int g_file_open_ex(const char *file_name, int aread, int awrite,
|
||||
int acreate, int atrunc);
|
||||
int g_file_close(int fd);
|
||||
/**
|
||||
* Returns 1 if a file is open (i.e. the file descriptor is valid)
|
||||
* @param fd File descriptor
|
||||
* @return 1 for file open, 0 for not open
|
||||
*/
|
||||
int g_file_is_open(int fd);
|
||||
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);
|
||||
@@ -236,6 +242,7 @@ int g_set_current_dir(const char *dirname);
|
||||
int g_file_exist(const char *filename);
|
||||
int g_file_readable(const char *filename);
|
||||
int g_directory_exist(const char *dirname);
|
||||
int g_executable_exist(const char *dirname);
|
||||
int g_create_dir(const char *dirname);
|
||||
int g_create_path(const char *path);
|
||||
int g_remove_dir(const char *dirname);
|
||||
@@ -290,6 +297,15 @@ int g_set_allusercontext(int uid);
|
||||
int g_waitchild(struct exit_status *e);
|
||||
int g_waitpid(int pid);
|
||||
struct exit_status g_waitpid_status(int pid);
|
||||
/*
|
||||
* Sets the process group ID of the indicated process to the specified value.
|
||||
* (POSIX.1)
|
||||
*
|
||||
* Errors are logged.
|
||||
*
|
||||
* May do nothing if process groups are not supported
|
||||
*/
|
||||
int g_setpgid(int pid, int pgid);
|
||||
void g_clearenv(void);
|
||||
int g_setenv(const char *name, const char *value, int rewrite);
|
||||
char *g_getenv(const char *name);
|
||||
|
||||
@@ -588,6 +588,7 @@ AC_CONFIG_FILES([
|
||||
sesman/libsesman/Makefile
|
||||
sesman/chansrv/Makefile
|
||||
sesman/Makefile
|
||||
sesman/sesexec/Makefile
|
||||
sesman/tools/Makefile
|
||||
tests/Makefile
|
||||
tests/common/Makefile
|
||||
|
||||
@@ -155,6 +155,13 @@ defaults to \fI10\fR.
|
||||
Sets the maximum number of simultaneous sessions. If not set or set to
|
||||
\fI0\fR, unlimited session are allowed.
|
||||
|
||||
.TP
|
||||
\fBMaxDisplayNumber\fR=\fInumber\fR
|
||||
Sets the maximum number which can be assigned to an X11 $DISPLAY. The
|
||||
default is compatible with IANA TCP port allocations. If you are not
|
||||
allowing TCP connections to your X servers you may safely increase this
|
||||
number.
|
||||
|
||||
.TP
|
||||
\fBKillDisconnected\fR=\fI[true|false]\fR
|
||||
If set to \fB1\fR, \fBtrue\fR or \fByes\fR, every session will be killed
|
||||
|
||||
@@ -13,6 +13,10 @@ libipm_la_SOURCES = \
|
||||
libipm_recv.c \
|
||||
libipm_facilities.h \
|
||||
libipm_private.h \
|
||||
eicp.h \
|
||||
eicp.c \
|
||||
ercp.h \
|
||||
ercp.c \
|
||||
scp.h \
|
||||
scp.c \
|
||||
scp_application_types.h \
|
||||
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2022, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file libipm/eicp.c
|
||||
* @brief EICP definitions
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "eicp.h"
|
||||
#include "libipm.h"
|
||||
#include "guid.h"
|
||||
#include "os_calls.h"
|
||||
#include "trans.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
static const char *
|
||||
msgno_to_str(unsigned short n)
|
||||
{
|
||||
return
|
||||
(n == E_EICP_SYS_LOGIN_REQUEST) ? "EICP_SYS_LOGIN_REQUEST" :
|
||||
(n == E_EICP_SYS_LOGIN_RESPONSE) ? "EICP_SYS_LOGIN_RESPONSE" :
|
||||
|
||||
(n == E_EICP_LOGOUT_REQUEST) ? "EICP_LOGOUT_REQUEST" :
|
||||
|
||||
(n == E_EICP_CREATE_SESSION_REQUEST) ? "EICP_CREATE_SESSION_REQUEST" :
|
||||
|
||||
NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
const char *
|
||||
eicp_msgno_to_str(enum eicp_msg_code n, char *buff, unsigned int buff_size)
|
||||
{
|
||||
const char *str = msgno_to_str((unsigned short)n);
|
||||
|
||||
if (str == NULL)
|
||||
{
|
||||
g_snprintf(buff, buff_size, "[code #%d]", (int)n);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_snprintf(buff, buff_size, "%s", str);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_init_trans(struct trans *trans)
|
||||
{
|
||||
return libipm_init_trans(trans, LIBIPM_FAC_EICP, msgno_to_str);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
struct trans *
|
||||
eicp_init_trans_from_fd(int fd, int trans_type, int (*term_func)(void))
|
||||
{
|
||||
struct trans *result;
|
||||
if ((result = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create ECP transport [%s]",
|
||||
g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
result->sck = fd;
|
||||
result->type1 = trans_type;
|
||||
result->status = TRANS_STATUS_UP;
|
||||
result->is_term = term_func;
|
||||
|
||||
// Make sure child processes don't inherit our FD
|
||||
(void)g_file_set_cloexec(result->sck, 1);
|
||||
|
||||
if (eicp_init_trans(result) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "eicp_init_trans() call failed");
|
||||
trans_delete(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_msg_in_check_available(struct trans *trans, int *available)
|
||||
{
|
||||
return libipm_msg_in_check_available(trans, available);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_msg_in_wait_available(struct trans *trans)
|
||||
{
|
||||
return libipm_msg_in_wait_available(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum eicp_msg_code
|
||||
eicp_msg_in_get_msgno(const struct trans *trans)
|
||||
{
|
||||
return (enum eicp_msg_code)libipm_msg_in_get_msgno(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
eicp_msg_in_reset(struct trans *trans)
|
||||
{
|
||||
libipm_msg_in_reset(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_send_sys_login_request(struct trans *trans,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *ip_addr,
|
||||
int scp_fd)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = libipm_msg_out_simple_send(
|
||||
trans,
|
||||
(int)E_EICP_SYS_LOGIN_REQUEST,
|
||||
"sssh",
|
||||
username,
|
||||
password,
|
||||
ip_addr,
|
||||
scp_fd);
|
||||
|
||||
/* Wipe the output buffer to remove the password */
|
||||
libipm_msg_out_erase(trans);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_get_sys_login_request(struct trans *trans,
|
||||
const char **username,
|
||||
const char **password,
|
||||
const char **ip_addr,
|
||||
int *scp_fd)
|
||||
{
|
||||
/* Make sure the buffer is cleared after processing this message */
|
||||
libipm_set_flags(trans, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
|
||||
|
||||
return libipm_msg_in_parse( trans, "sssh",
|
||||
username, password, ip_addr, scp_fd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_send_sys_login_response(struct trans *trans,
|
||||
int is_logged_in,
|
||||
uid_t uid,
|
||||
int scp_fd)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (is_logged_in)
|
||||
{
|
||||
rv = libipm_msg_out_simple_send(
|
||||
trans,
|
||||
(int)E_EICP_SYS_LOGIN_RESPONSE,
|
||||
"bih",
|
||||
1,
|
||||
uid,
|
||||
scp_fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = libipm_msg_out_simple_send(
|
||||
trans, (int)E_EICP_SYS_LOGIN_RESPONSE, "b", 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_get_sys_login_response(struct trans *trans,
|
||||
int *is_logged_in,
|
||||
uid_t *uid,
|
||||
int *scp_fd)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if ((rv = libipm_msg_in_parse(trans, "b", is_logged_in)) == 0)
|
||||
{
|
||||
if (*is_logged_in)
|
||||
{
|
||||
int32_t i_uid;
|
||||
|
||||
rv = libipm_msg_in_parse(
|
||||
trans,
|
||||
"ih",
|
||||
&i_uid,
|
||||
scp_fd);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
*uid = (uid_t)i_uid;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*uid = (uid_t) -1;
|
||||
*scp_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
eicp_send_logout_request(struct trans *trans)
|
||||
{
|
||||
return libipm_msg_out_simple_send(trans, (int)E_EICP_LOGOUT_REQUEST, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_send_create_session_request(struct trans *trans,
|
||||
int scp_fd,
|
||||
unsigned int display,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned char bpp,
|
||||
const char *shell,
|
||||
const char *directory)
|
||||
{
|
||||
return libipm_msg_out_simple_send(
|
||||
trans,
|
||||
(int)E_EICP_CREATE_SESSION_REQUEST,
|
||||
"huyqqyss",
|
||||
scp_fd,
|
||||
display,
|
||||
type,
|
||||
width,
|
||||
height,
|
||||
bpp,
|
||||
shell,
|
||||
directory);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
eicp_get_create_session_request(struct trans *trans,
|
||||
int *scp_fd,
|
||||
unsigned int *display,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *width,
|
||||
unsigned short *height,
|
||||
unsigned char *bpp,
|
||||
const char **shell,
|
||||
const char **directory)
|
||||
{
|
||||
/* Intermediate values */
|
||||
uint32_t i_display;
|
||||
uint8_t i_type;
|
||||
uint16_t i_width;
|
||||
uint16_t i_height;
|
||||
uint8_t i_bpp;
|
||||
|
||||
int rv = libipm_msg_in_parse(
|
||||
trans,
|
||||
"huyqqyss",
|
||||
scp_fd,
|
||||
&i_display,
|
||||
&i_type,
|
||||
&i_width,
|
||||
&i_height,
|
||||
&i_bpp,
|
||||
shell,
|
||||
directory);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
*display = i_display;
|
||||
*type = (enum scp_session_type)i_type;
|
||||
*width = i_width;
|
||||
*height = i_height;
|
||||
/* bpp is fixed for Xorg session types */
|
||||
*bpp = (*type == SCP_SESSION_TYPE_XORG) ? 24 : i_bpp;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2022, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file libipm/eicp.h
|
||||
* @brief EICP declarations
|
||||
* @author Matt Burt
|
||||
*
|
||||
* Functions in this file use the following naming conventions:-
|
||||
*
|
||||
* E_EICP_{msg}_REQUEST is sent by eicp_send_{msg}_request()
|
||||
* E_EICP_{msg}_REQUEST is parsed by eicp_get_{msg}_request()
|
||||
* E_EICP_{msg}_RESPONSE is sent by eicp_send_{msg}_response()
|
||||
* E_EICP_{msg}_RESPONSE is parsed by eicp_get_{msg}_response()
|
||||
*/
|
||||
|
||||
#ifndef EICP_H
|
||||
#define EICP_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "scp_application_types.h"
|
||||
|
||||
struct trans;
|
||||
struct guid;
|
||||
|
||||
/* Message codes */
|
||||
enum eicp_msg_code
|
||||
{
|
||||
E_EICP_SYS_LOGIN_REQUEST,
|
||||
E_EICP_SYS_LOGIN_RESPONSE,
|
||||
|
||||
E_EICP_LOGOUT_REQUEST,
|
||||
// No E_EICP_LOGOUT_RESPONSE
|
||||
|
||||
E_EICP_CREATE_SESSION_REQUEST
|
||||
// No E_EICP_CREATE_SESSION_RESPONSE
|
||||
};
|
||||
|
||||
/* Common facilities */
|
||||
|
||||
/**
|
||||
* Convert a message code to a string for output
|
||||
* @param n Message code
|
||||
* @param buff to contain string
|
||||
* @param buff_size length of buff
|
||||
* @return buff is returned for convenience.
|
||||
*/
|
||||
const char *
|
||||
eicp_msgno_to_str(enum eicp_msg_code n, char *buff, unsigned int buff_size);
|
||||
|
||||
/* Connection management facilities */
|
||||
|
||||
/**
|
||||
* Converts a standard trans connected to an EICP endpoint to an EICP transport
|
||||
*
|
||||
* @param trans connected endpoint
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_init_trans(struct trans *trans);
|
||||
|
||||
/**
|
||||
* Creates an EICP transport from a file descriptor
|
||||
*
|
||||
* @param fd file descriptor
|
||||
* @param trans_type TRANS_TYPE_SERVER or TRANS_TYPE_CLIENT
|
||||
* @param term_func Function to poll during connection for program
|
||||
* termination, or NULL for none.
|
||||
* @return SCP transport, or NULL
|
||||
*/
|
||||
struct trans *
|
||||
eicp_init_trans_from_fd(int fd, int trans_type, int (*term_func)(void));
|
||||
|
||||
|
||||
/**
|
||||
* Checks an EICP transport to see if a complete message is
|
||||
* available for parsing
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] available != 0 if a complete message is available
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_msg_in_check_available(struct trans *trans, int *available);
|
||||
|
||||
/**
|
||||
* Waits on a single transport for an EICP message to be available for
|
||||
* parsing
|
||||
*
|
||||
* @param trans libipm transport
|
||||
* @return != 0 for error
|
||||
*
|
||||
* While the call is active, data-in callbacks for the transport are
|
||||
* disabled.
|
||||
*
|
||||
* Only use this call if you have nothing to do until a message
|
||||
* arrives on the transport. If you have other transports to service, use
|
||||
* eicp_msg_in_check_available()
|
||||
*/
|
||||
int
|
||||
eicp_msg_in_wait_available(struct trans *trans);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the EICP message number of an incoming message
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @return message in the buffer
|
||||
*
|
||||
* The results of calling this routine before eicp_msg_in_check_available()
|
||||
* states a message is available are undefined.
|
||||
*/
|
||||
enum eicp_msg_code
|
||||
eicp_msg_in_get_msgno(const struct trans *trans);
|
||||
|
||||
/**
|
||||
* Resets an EICP message buffer ready to receive the next message
|
||||
*
|
||||
* @param trans libipm transport
|
||||
*/
|
||||
void
|
||||
eicp_msg_in_reset(struct trans *trans);
|
||||
|
||||
/* -------------------- Connect messages-------------------- */
|
||||
|
||||
/**
|
||||
* Send an E_EICP_SYS_LOGIN_REQUEST
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param username Username
|
||||
* @param password Password
|
||||
* @param ip_addr IP address for the client (or "" if not known)
|
||||
* @param scp_fd SCP file descriptor from sesman client
|
||||
* @return != 0 for error
|
||||
*
|
||||
* sesexec replies (eventually) with E_EICP_SYS_LOGIN_RESPONSE
|
||||
*
|
||||
* Once this message has been sent, sesman can close its own SCP transport
|
||||
* down, as sesexec is responsible for client communication. When sesexec
|
||||
* responds, sesman can recreate the SCP transport if necessary.
|
||||
*
|
||||
* While E_EICP_SYS_LOGIN_REQUEST is being processed, sesman must assume
|
||||
* sesexec will be unresponsive to other EICP messages (although a
|
||||
* SIGTERM should be effective).
|
||||
*/
|
||||
int
|
||||
eicp_send_sys_login_request(struct trans *trans,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *ip_addr,
|
||||
int scp_fd);
|
||||
|
||||
/**
|
||||
* Parse an incoming E_EICP_SYS_LOGIN_REQUEST message (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] username Username
|
||||
* @param[out] password Password
|
||||
* @param[out] ip_addr IP address for the client (or "" if not known)
|
||||
* @param [out] scp_fd SCP file descriptor from sesman client
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
eicp_get_sys_login_request(struct trans *trans,
|
||||
const char **username,
|
||||
const char **password,
|
||||
const char **ip_addr,
|
||||
int *scp_fd);
|
||||
|
||||
/**
|
||||
* Send an E_EICP_SYS_LOGIN_RESPONSE (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param is_logged_in true if the SCP client is logged in
|
||||
* @param uid UID of connected user
|
||||
* @param scp_fd File descriptor of sesman client
|
||||
* @return != 0 for error
|
||||
*
|
||||
* The uid and scp_fd are ignored unless is_logged_in is true.
|
||||
*
|
||||
* If is_logged_in is false, it is assumed that sesexec has properly
|
||||
* closed the connection to the SCP client.
|
||||
*/
|
||||
int
|
||||
eicp_send_sys_login_response(struct trans *trans,
|
||||
int is_logged_in,
|
||||
uid_t uid,
|
||||
int scp_fd);
|
||||
|
||||
/**
|
||||
* Parses an incoming E_EICP_SYS_LOGIN_RESPONSE (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] is_logged_in true if the SCP client is logged in
|
||||
* @param[out] uid UID of connected user
|
||||
* @param[out] scp_fd File descriptor of sesman client
|
||||
* @return != 0 for error
|
||||
*
|
||||
* The uid and client_fd are returned as (uid_t)-1 and -1 respectively
|
||||
* unless is_logged_in is true
|
||||
*/
|
||||
int
|
||||
eicp_get_sys_login_response(struct trans *trans,
|
||||
int *is_logged_in,
|
||||
uid_t *uid,
|
||||
int *scp_fd);
|
||||
|
||||
/**
|
||||
* Send an E_EICP_LOGOUT_REQUEST (sesexec)
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @return != 0 for error
|
||||
*
|
||||
* The sesexec process will exit normally
|
||||
*/
|
||||
int
|
||||
eicp_send_logout_request(struct trans *trans);
|
||||
|
||||
/* -------------------- Session messages-------------------- */
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param height Initial session height
|
||||
* @param bpp Session bits-per-pixel (ignored for Xorg sessions)
|
||||
* @param shell User program to run. May be ""
|
||||
* @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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
int
|
||||
eicp_send_create_session_request(struct trans *trans,
|
||||
int scp_fd,
|
||||
unsigned int display,
|
||||
enum scp_session_type type,
|
||||
unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned char bpp,
|
||||
const char *shell,
|
||||
const char *directory);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param[out] height Initial session height
|
||||
* @param[out] bpp Session bits-per-pixel (ignored for Xorg sessions)
|
||||
* @param[out] shell User program to run. May be ""
|
||||
* @param[out] directory Directory to run the program in. May be ""
|
||||
* @return != 0 for error
|
||||
*
|
||||
* Returned string pointers are valid until scp_msg_in_reset() is
|
||||
* called for the transport
|
||||
*/
|
||||
int
|
||||
eicp_get_create_session_request(struct trans *trans,
|
||||
int *scp_fd,
|
||||
unsigned int *display,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *width,
|
||||
unsigned short *height,
|
||||
unsigned char *bpp,
|
||||
const char **shell,
|
||||
const char **directory);
|
||||
|
||||
#endif /* EICP_H */
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2022, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file libipm/ercp.c
|
||||
* @brief ERCP definitions
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "ercp.h"
|
||||
#include "libipm.h"
|
||||
#include "guid.h"
|
||||
#include "os_calls.h"
|
||||
#include "trans.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
static const char *
|
||||
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" :
|
||||
NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
const char *
|
||||
ercp_msgno_to_str(enum ercp_msg_code n, char *buff, unsigned int buff_size)
|
||||
{
|
||||
const char *str = msgno_to_str((unsigned short)n);
|
||||
|
||||
if (str == NULL)
|
||||
{
|
||||
g_snprintf(buff, buff_size, "[code #%d]", (int)n);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_snprintf(buff, buff_size, "%s", str);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
ercp_init_trans(struct trans *trans)
|
||||
{
|
||||
return libipm_init_trans(trans, LIBIPM_FAC_ERCP, msgno_to_str);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void
|
||||
ercp_trans_from_eicp_trans(struct trans *trans,
|
||||
ttrans_data_in callback_func,
|
||||
void *callback_data)
|
||||
{
|
||||
libipm_change_facility(trans, LIBIPM_FAC_EICP, LIBIPM_FAC_ERCP);
|
||||
trans->trans_data_in = callback_func;
|
||||
trans->callback_data = callback_data;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_msg_in_check_available(struct trans *trans, int *available)
|
||||
{
|
||||
return libipm_msg_in_check_available(trans, available);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_msg_in_wait_available(struct trans *trans)
|
||||
{
|
||||
return libipm_msg_in_wait_available(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum ercp_msg_code
|
||||
ercp_msg_in_get_msgno(const struct trans *trans)
|
||||
{
|
||||
return (enum ercp_msg_code)libipm_msg_in_get_msgno(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
ercp_msg_in_reset(struct trans *trans)
|
||||
{
|
||||
libipm_msg_in_reset(trans);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_send_session_announce_event(struct trans *trans,
|
||||
unsigned int display,
|
||||
uid_t uid,
|
||||
enum scp_session_type type,
|
||||
unsigned short start_width,
|
||||
unsigned short start_height,
|
||||
unsigned char bpp,
|
||||
const struct guid *guid,
|
||||
const char *start_ip_addr,
|
||||
time_t start_time)
|
||||
{
|
||||
struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
||||
|
||||
return libipm_msg_out_simple_send(
|
||||
trans,
|
||||
(int)E_ERCP_SESSION_ANNOUNCE_EVENT,
|
||||
"uiyqqyBsx",
|
||||
display,
|
||||
uid,
|
||||
type,
|
||||
start_width,
|
||||
start_height,
|
||||
bpp,
|
||||
&guid_descriptor,
|
||||
start_ip_addr,
|
||||
start_time);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_get_session_announce_event(struct trans *trans,
|
||||
unsigned int *display,
|
||||
uid_t *uid,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *start_width,
|
||||
unsigned short *start_height,
|
||||
unsigned char *bpp,
|
||||
struct guid *guid,
|
||||
const char **start_ip_addr,
|
||||
time_t *start_time)
|
||||
{
|
||||
/* Intermediate values */
|
||||
uint32_t i_display;
|
||||
int32_t i_uid;
|
||||
uint8_t i_type;
|
||||
uint16_t i_width;
|
||||
uint16_t i_height;
|
||||
uint8_t i_bpp;
|
||||
int64_t i_start_time;
|
||||
|
||||
const struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
||||
|
||||
int rv = libipm_msg_in_parse(
|
||||
trans,
|
||||
"uiyqqyBsx",
|
||||
&i_display,
|
||||
&i_uid,
|
||||
&i_type,
|
||||
&i_width,
|
||||
&i_height,
|
||||
&i_bpp,
|
||||
&guid_descriptor,
|
||||
start_ip_addr,
|
||||
&i_start_time);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
if (display != NULL)
|
||||
{
|
||||
*display = i_display;
|
||||
}
|
||||
*uid = (uid_t)i_uid;
|
||||
*type = (enum scp_session_type)i_type;
|
||||
*start_width = i_width;
|
||||
*start_height = i_height;
|
||||
*bpp = i_bpp;
|
||||
*start_time = (time_t)i_start_time;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_send_session_finished_event(struct trans *trans)
|
||||
{
|
||||
return libipm_msg_out_simple_send(
|
||||
trans, (int)E_ERCP_SESSION_FINISHED_EVENT, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
ercp_send_session_reconnect_event(struct trans *trans)
|
||||
{
|
||||
return libipm_msg_out_simple_send(
|
||||
trans, (int)E_ERCP_SESSION_RECONNECT_EVENT, NULL);
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2022, all xrdp contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file libipm/ercp.h
|
||||
* @brief ERCP declarations
|
||||
* @author Matt Burt
|
||||
*
|
||||
* Functions in this file use the following naming conventions:-
|
||||
*
|
||||
* E_ERCP_{msg}_REQUEST is sent by ercp_send_{msg}_request()
|
||||
* E_ERCP_{msg}_REQUEST is parsed by ercp_get_{msg}_request()
|
||||
* E_ERCP_{msg}_RESPONSE is sent by ercp_send_{msg}_response()
|
||||
* E_ERCP_{msg}_RESPONSE is parsed by ercp_get_{msg}_response()
|
||||
* E_ERCP_{msg}_EVENT is sent by ercp_send_{msg}_event()
|
||||
* E_ERCP_{msg}_EVENT is parsed by ercp_get_{msg}_event()
|
||||
*/
|
||||
|
||||
#ifndef ERCP_H
|
||||
#define ERCP_H
|
||||
|
||||
#include "arch.h"
|
||||
#include "scp_application_types.h"
|
||||
#include "trans.h"
|
||||
|
||||
struct guid;
|
||||
|
||||
/* Message codes */
|
||||
enum ercp_msg_code
|
||||
{
|
||||
E_ERCP_SESSION_ANNOUNCE_EVENT,
|
||||
E_ERCP_SESSION_FINISHED_EVENT,
|
||||
|
||||
E_ERCP_SESSION_RECONNECT_EVENT
|
||||
};
|
||||
|
||||
/* Common facilities */
|
||||
|
||||
/**
|
||||
* Convert a message code to a string for output
|
||||
* @param n Message code
|
||||
* @param buff to contain string
|
||||
* @param buff_size length of buff
|
||||
* @return buff is returned for convenience.
|
||||
*/
|
||||
const char *
|
||||
ercp_msgno_to_str(enum ercp_msg_code n, char *buff, unsigned int buff_size);
|
||||
|
||||
/* Connection management facilities */
|
||||
|
||||
/**
|
||||
* Converts a standard trans connected to an ERCP endpoint to an ERCP transport
|
||||
*
|
||||
* @param trans connected endpoint
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_init_trans(struct trans *trans);
|
||||
|
||||
/**
|
||||
* Converts an EICP transport to an ERCP transport.
|
||||
*
|
||||
* This is done following successful transmission or receipt of an
|
||||
* E_EICP_CREATE_SESSION_REQUEST.
|
||||
*
|
||||
* @param trans connected endpoint
|
||||
* @param callback_func New callback function for ERCP messages.
|
||||
* @param callback_data New argument for callback function
|
||||
*/
|
||||
void
|
||||
ercp_trans_from_eicp_trans(struct trans *trans,
|
||||
ttrans_data_in callback_func,
|
||||
void *callback_data);
|
||||
|
||||
|
||||
/**
|
||||
* Checks an ERCP transport to see if a complete message is
|
||||
* available for parsing
|
||||
*
|
||||
* @param trans ERCP transport
|
||||
* @param[out] available != 0 if a complete message is available
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_msg_in_check_available(struct trans *trans, int *available);
|
||||
|
||||
/**
|
||||
* Waits on a single transport for an ERCP message to be available for
|
||||
* parsing
|
||||
*
|
||||
* @param trans libipm transport
|
||||
* @return != 0 for error
|
||||
*
|
||||
* While the call is active, data-in callbacks for the transport are
|
||||
* disabled.
|
||||
*
|
||||
* Only use this call if you have nothing to do until a message
|
||||
* arrives on the transport. If you have other transports to service, use
|
||||
* ercp_msg_in_check_available()
|
||||
*/
|
||||
int
|
||||
ercp_msg_in_wait_available(struct trans *trans);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the ERCP message number of an incoming message
|
||||
*
|
||||
* @param trans ERCP transport
|
||||
* @return message in the buffer
|
||||
*
|
||||
* The results of calling this routine before ercp_msg_in_check_available()
|
||||
* states a message is available are undefined.
|
||||
*/
|
||||
enum ercp_msg_code
|
||||
ercp_msg_in_get_msgno(const struct trans *trans);
|
||||
|
||||
/**
|
||||
* Resets an ERCP message buffer ready to receive the next message
|
||||
*
|
||||
* @param trans libipm transport
|
||||
*/
|
||||
void
|
||||
ercp_msg_in_reset(struct trans *trans);
|
||||
|
||||
/* -------------------- Session event messages-------------------- */
|
||||
/**
|
||||
* Send an E_ERCP_SESSION_ANNOUNCE_EVENT
|
||||
*
|
||||
* Direction : sesexec -> sesman
|
||||
*
|
||||
* This event contains all the information known about a session
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param display Display used by session
|
||||
* @param uid UID of user logged in to session
|
||||
* @param type Session type
|
||||
* @param start_width Starting width of seenio
|
||||
* @param start_height Starting height of session
|
||||
* @param bpp Bits-per-pixel for session
|
||||
* @param guid Session GUID
|
||||
* @param start_ip_addr Starting IP address of client
|
||||
* @param start_time Session start time
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_send_session_announce_event(struct trans *trans,
|
||||
unsigned int display,
|
||||
uid_t uid,
|
||||
enum scp_session_type type,
|
||||
unsigned short start_width,
|
||||
unsigned short start_height,
|
||||
unsigned char bpp,
|
||||
const struct guid *guid,
|
||||
const char *start_ip_addr,
|
||||
time_t start_time);
|
||||
|
||||
|
||||
/**
|
||||
* Parse an incoming E_ERCP_SESSION_ANNOUNCE_EVENT
|
||||
*
|
||||
* This event contains all the information known about a session
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @param[out] display Display used by session.
|
||||
* Pointer can be NULL if this is already known.
|
||||
* @param[out] uid UID of user logged in to session
|
||||
* @param[out] type Session type
|
||||
* @param[out] start_width Starting width of seenio
|
||||
* @param[out] start_height Starting height of session
|
||||
* @param[out] bpp Bits-per-pixel for session
|
||||
* @param[out] guid Session GUID
|
||||
* @param[out] start_ip_addr Starting IP address of client
|
||||
* @param[out] start_time Session start time
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_get_session_announce_event(struct trans *trans,
|
||||
unsigned int *display,
|
||||
uid_t *uid,
|
||||
enum scp_session_type *type,
|
||||
unsigned short *start_width,
|
||||
unsigned short *start_height,
|
||||
unsigned char *bpp,
|
||||
struct guid *guid,
|
||||
const char **start_ip_addr,
|
||||
time_t *start_time);
|
||||
|
||||
|
||||
/**
|
||||
* Send an E_ERCP_SESSION_FINISHED_EVENT
|
||||
*
|
||||
* Direction : sesexec -> sesman
|
||||
*
|
||||
* This event simply states the attached session has finished and can be
|
||||
* removed from any data structures held by sesman
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_send_session_finished_event(struct trans *trans);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send an E_ERCP_SESSION_RECONNECT_EVENT
|
||||
*
|
||||
* Direction : sesman -> sesexec
|
||||
*
|
||||
* This event tells sesexec that a reconnection is about to occur, and
|
||||
* sesexec should run the reconnect script.
|
||||
*
|
||||
* @param trans EICP transport
|
||||
* @return != 0 for error
|
||||
*/
|
||||
int
|
||||
ercp_send_session_reconnect_event(struct trans *trans);
|
||||
|
||||
|
||||
#endif /* ERCP_H */
|
||||
@@ -216,3 +216,25 @@ libipm_clear_flags(struct trans *trans, unsigned int flags)
|
||||
priv->flags &= ~flags;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
libipm_change_facility(struct trans *trans,
|
||||
enum libipm_facility old_facility,
|
||||
enum libipm_facility new_facility)
|
||||
{
|
||||
struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
|
||||
|
||||
if (priv != NULL)
|
||||
{
|
||||
if (priv->facility != old_facility)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Not changing libipm facility - bad value");
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->facility = new_facility;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,26 @@ libipm_set_flags(struct trans *trans, unsigned int flags);
|
||||
void
|
||||
libipm_clear_flags(struct trans *trans, unsigned int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Change the facility number for the transport
|
||||
* @param trans libipm transport
|
||||
* @param old_facility old transport facility
|
||||
* @param new_facility new transport facility
|
||||
*
|
||||
* This call is required if a libipm transport changes a facility number.
|
||||
* This can be used to implement switches from one functional server state to
|
||||
* another.
|
||||
*
|
||||
* The caller must be aware of the previous facility to change the facility.
|
||||
* In the event of a mismatch, a message is logged and no action is taken.
|
||||
*/
|
||||
void
|
||||
libipm_change_facility(struct trans *trans,
|
||||
enum libipm_facility old_facility,
|
||||
enum libipm_facility new_facility);
|
||||
|
||||
|
||||
/**
|
||||
* Initialise an output message
|
||||
*
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
enum libipm_facility
|
||||
{
|
||||
LIBIPM_FAC_SCP = 1, /**< SCP - Sesman Control Protocol */
|
||||
LIBIPM_FAC_EICP, /**< EICP - Executive Initialization Control Protocol */
|
||||
LIBIPM_FAC_ERCP, /**< ERCP - Executive Run-time Control Protocol */
|
||||
|
||||
LIBIPM_FAC_TEST = 65535 /**< Used for unit testing */
|
||||
};
|
||||
|
||||
|
||||
@@ -195,7 +195,38 @@ scp_init_trans(struct trans *trans)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
struct trans *
|
||||
scp_init_trans_from_fd(int fd, int trans_type, int (*term_func)(void))
|
||||
{
|
||||
struct trans *result;
|
||||
if ((result = trans_create(TRANS_MODE_UNIX, 128, 128)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create SCP transport [%s]",
|
||||
g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
result->sck = fd;
|
||||
result->type1 = trans_type;
|
||||
result->status = TRANS_STATUS_UP;
|
||||
result->is_term = term_func;
|
||||
|
||||
// Make sure child processes don't inherit our FD
|
||||
(void)g_file_set_cloexec(result->sck, 1);
|
||||
|
||||
if (scp_init_trans(result) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "scp_init_trans() call failed");
|
||||
trans_delete(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
scp_msg_in_check_available(struct trans *trans, int *available)
|
||||
{
|
||||
|
||||
+17
-1
@@ -125,7 +125,7 @@ scp_connect(const char *port,
|
||||
* Converts a standard trans connected to an SCP endpoint to an SCP transport
|
||||
*
|
||||
* If you are running on a client, you may wish to use
|
||||
* scp_send_set_peername_request() after the commnect to inform the
|
||||
* scp_send_set_peername_request() after the connect to inform the
|
||||
* server who you are.
|
||||
*
|
||||
* @param trans connected endpoint
|
||||
@@ -134,6 +134,22 @@ scp_connect(const char *port,
|
||||
int
|
||||
scp_init_trans(struct trans *trans);
|
||||
|
||||
/**
|
||||
* Creates an SCP transport from a file descriptor
|
||||
*
|
||||
* If you are running on a client, you may wish to use
|
||||
* scp_send_set_peername_request() after the connect to inform the
|
||||
* server who you are.
|
||||
*
|
||||
* @param fd file descriptor
|
||||
* @param trans_type TRANS_TYPE_SERVER or TRANS_TYPE_CLIENT
|
||||
* @param term_func Function to poll during connection for program
|
||||
* termination, or NULL for none.
|
||||
* @return SCP transport, or NULL
|
||||
*/
|
||||
struct trans *
|
||||
scp_init_trans_from_fd(int fd, int trans_type, int (*term_func)(void));
|
||||
|
||||
/**
|
||||
* Checks an SCP transport to see if a complete message is
|
||||
* available for parsing
|
||||
|
||||
+10
-9
@@ -16,24 +16,24 @@ sbin_PROGRAMS = \
|
||||
xrdp-sesman
|
||||
|
||||
xrdp_sesman_SOURCES = \
|
||||
env.c \
|
||||
env.h \
|
||||
eicp_process.c \
|
||||
eicp_process.h \
|
||||
ercp_process.c \
|
||||
ercp_process.h \
|
||||
lock_uds.c \
|
||||
lock_uds.h \
|
||||
pre_session_list.c \
|
||||
pre_session_list.h \
|
||||
scp_process.c \
|
||||
scp_process.h \
|
||||
sesman.c \
|
||||
sesman.h \
|
||||
session.c \
|
||||
session.h \
|
||||
sesexec_control.c \
|
||||
sesexec_control.h \
|
||||
session_list.c \
|
||||
session_list.h \
|
||||
sig.c \
|
||||
sig.h \
|
||||
xauth.c \
|
||||
xauth.h \
|
||||
xwait.c \
|
||||
xwait.h
|
||||
sig.h
|
||||
|
||||
xrdp_sesman_LDADD = \
|
||||
$(top_builddir)/sesman/libsesman/libsesman.la \
|
||||
@@ -62,5 +62,6 @@ dist_sesmansysconf_SCRIPTS = \
|
||||
|
||||
SUBDIRS = \
|
||||
libsesman \
|
||||
sesexec \
|
||||
tools \
|
||||
chansrv
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 eicp_process.c
|
||||
* @brief eicp (executive initialisation control protocol) handler function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "trans.h"
|
||||
|
||||
#include "eicp.h"
|
||||
#include "eicp_process.h"
|
||||
#include "os_calls.h"
|
||||
#include "pre_session_list.h"
|
||||
#include "scp.h"
|
||||
#include "sesman.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_sys_login_response(struct pre_session_item *psi)
|
||||
{
|
||||
int rv;
|
||||
int is_logged_in;
|
||||
uid_t uid;
|
||||
int scp_fd;
|
||||
|
||||
rv = eicp_get_sys_login_response(psi->sesexec_trans, &is_logged_in,
|
||||
&uid, &scp_fd);
|
||||
if (rv == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Received sys login status for %s : %s",
|
||||
psi->username,
|
||||
(is_logged_in) ? "logged in" : "not logged in");
|
||||
|
||||
if (!is_logged_in)
|
||||
{
|
||||
// This shouldn't happen. Close the connection to the
|
||||
// client immediately.
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We've been handed back the client connection */
|
||||
psi->client_trans = scp_init_trans_from_fd(scp_fd,
|
||||
TRANS_TYPE_SERVER,
|
||||
sesman_is_term);
|
||||
if (psi->client_trans == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't re-create client connection");
|
||||
g_file_close(scp_fd);
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
psi->client_trans->trans_data_in = sesman_scp_data_in;
|
||||
psi->client_trans->callback_data = (void *)psi;
|
||||
psi->login_state = E_PS_LOGIN_SYS;
|
||||
psi->uid = uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
eicp_process(struct pre_session_item *psi)
|
||||
{
|
||||
enum eicp_msg_code msgno;
|
||||
int rv = 0;
|
||||
|
||||
switch ((msgno = eicp_msg_in_get_msgno(psi->sesexec_trans)))
|
||||
{
|
||||
case E_EICP_SYS_LOGIN_RESPONSE:
|
||||
rv = process_sys_login_response(psi);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
eicp_msgno_to_str(msgno, buff, sizeof(buff));
|
||||
LOG(LOG_LEVEL_ERROR, "Ignored EICP message %s", buff);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 eicp_process.h
|
||||
* @brief eicp (executive initialisation control protocol) handler function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EICP_PROCESS_H
|
||||
#define EICP_PROCESS_H
|
||||
|
||||
struct pre_session_item;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Processes an EICP message
|
||||
* @param sc the sesman connection
|
||||
*
|
||||
*/
|
||||
int
|
||||
eicp_process(struct pre_session_item *psi);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 ercp_process.c
|
||||
* @brief ERCP (executive run-time control protocol) handler function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "trans.h"
|
||||
|
||||
#include "ercp.h"
|
||||
#include "ercp_process.h"
|
||||
#include "session_list.h"
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
process_session_announce_event(struct session_item *si)
|
||||
{
|
||||
int rv;
|
||||
const char *start_ip_addr;
|
||||
|
||||
rv = ercp_get_session_announce_event(si->sesexec_trans,
|
||||
NULL,
|
||||
&si->uid,
|
||||
&si->type,
|
||||
&si->start_width,
|
||||
&si->start_height,
|
||||
&si->bpp,
|
||||
&si->guid,
|
||||
&start_ip_addr,
|
||||
&si->start_time);
|
||||
if (rv == 0)
|
||||
{
|
||||
snprintf(si->start_ip_addr, sizeof(si->start_ip_addr),
|
||||
"%s", start_ip_addr);
|
||||
si->state = E_SESSION_RUNNING;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void
|
||||
process_session_finished_event(struct session_item *si)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Session on display %d has finished.",
|
||||
si->display);
|
||||
// Setting the transport down will remove this connection from the list
|
||||
si->sesexec_trans->status = TRANS_STATUS_DOWN;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
ercp_process(struct session_item *si)
|
||||
{
|
||||
enum ercp_msg_code msgno;
|
||||
int rv = 0;
|
||||
|
||||
switch ((msgno = ercp_msg_in_get_msgno(si->sesexec_trans)))
|
||||
{
|
||||
case E_ERCP_SESSION_ANNOUNCE_EVENT:
|
||||
rv = process_session_announce_event(si);
|
||||
break;
|
||||
|
||||
case E_ERCP_SESSION_FINISHED_EVENT:
|
||||
process_session_finished_event(si);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
ercp_msgno_to_str(msgno, buff, sizeof(buff));
|
||||
LOG(LOG_LEVEL_ERROR, "Ignored EICP message %s", buff);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 ercp_process.h
|
||||
* @brief ERCP (executive run-time control protocol) handler function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ERCP_PROCESS_H
|
||||
#define ERCP_PROCESS_H
|
||||
|
||||
struct session_item;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Processes an ERCP message
|
||||
* @param sc the sesman connection
|
||||
*
|
||||
*/
|
||||
int
|
||||
ercp_process(struct session_item *si);
|
||||
|
||||
#endif // ERCP_PROCESS_H
|
||||
@@ -53,6 +53,7 @@ auth_userpass(const char *user, const char *pass,
|
||||
*
|
||||
* @param uid User ID
|
||||
* @param[out] Error code for the operation. E_SCP_LOGIN_OK on success.
|
||||
* Can be NULL if this information isn't required.
|
||||
* @return auth handle on success, NULL on failure
|
||||
*
|
||||
*/
|
||||
@@ -66,20 +67,12 @@ auth_uds(const char *user, enum scp_login_status *errorcode);
|
||||
* @param display_num Display number
|
||||
* @return 0 on success, 1 on failure
|
||||
*
|
||||
* The resources allocated when the session is started are de-allocated
|
||||
* by auth_end() - there is no separate way to do this.
|
||||
*/
|
||||
int
|
||||
auth_start_session(struct auth_info *auth_info, int display_num);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Stops a session previously started with auth_start_session()
|
||||
* @param auth_info. Auth handle created by auth_userpass
|
||||
* @return 0 on success, 1 on failure
|
||||
*
|
||||
*/
|
||||
int
|
||||
auth_stop_session(struct auth_info *auth_info);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Deallocates an auth handle and releases all resources
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
#define SESMAN_CFG_SESS_IDLE_LIMIT "IdleTimeLimit"
|
||||
#define SESMAN_CFG_SESS_DISC_LIMIT "DisconnectedTimeLimit"
|
||||
#define SESMAN_CFG_SESS_X11DISPLAYOFFSET "X11DisplayOffset"
|
||||
#define SESMAN_CFG_SESS_MAX_DISPLAY "MaxDisplayNumber"
|
||||
|
||||
#define SESMAN_CFG_SESS_POLICY_S "Policy"
|
||||
#define SESMAN_CFG_SESS_POLICY_DFLT_S "Default"
|
||||
@@ -410,6 +411,8 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n,
|
||||
|
||||
/* setting defaults */
|
||||
se->x11_display_offset = 10;
|
||||
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml`
|
||||
se->max_display_number = 63;
|
||||
se->max_sessions = 0;
|
||||
se->max_idle_time = 0;
|
||||
se->max_disc_time = 0;
|
||||
@@ -425,12 +428,29 @@ config_read_sessions(int file, struct config_sessions *se, struct list *param_n,
|
||||
|
||||
if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_X11DISPLAYOFFSET))
|
||||
{
|
||||
se->x11_display_offset = g_atoi(value);
|
||||
int x11off = g_atoi(value);
|
||||
if (x11off >= 0)
|
||||
{
|
||||
se->x11_display_offset = x11off;
|
||||
}
|
||||
}
|
||||
|
||||
else if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_MAX_DISPLAY))
|
||||
{
|
||||
int mdn = g_atoi(value);
|
||||
if (mdn > 0)
|
||||
{
|
||||
se->max_display_number = mdn;
|
||||
}
|
||||
}
|
||||
|
||||
else if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_MAX))
|
||||
{
|
||||
se->max_sessions = g_atoi(value);
|
||||
int sm = g_atoi(value);
|
||||
if (sm >= 0)
|
||||
{
|
||||
se->max_sessions = sm;
|
||||
}
|
||||
}
|
||||
|
||||
else if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC))
|
||||
|
||||
@@ -43,6 +43,11 @@ enum SESMAN_CFG_SESS_POLICY_BITS
|
||||
SESMAN_CFG_SESS_POLICY_I = (1 << 5)
|
||||
};
|
||||
|
||||
/**
|
||||
* Name of default sesman.ini file
|
||||
*/
|
||||
#define DEFAULT_SESMAN_INI XRDP_CFG_PATH "/sesman.ini"
|
||||
|
||||
/**
|
||||
*
|
||||
* @struct config_security
|
||||
@@ -112,12 +117,17 @@ struct config_sessions
|
||||
* @var x11_display_offset
|
||||
* @brief X11 TCP port offset. default value: 10
|
||||
*/
|
||||
int x11_display_offset;
|
||||
unsigned int x11_display_offset;
|
||||
/**
|
||||
* @var max_display_number
|
||||
* @brief Highest X11 display number considered for allocation
|
||||
*/
|
||||
unsigned int max_display_number;
|
||||
/**
|
||||
* @var max_sessions
|
||||
* @brief maximum number of allowed sessions. 0 for unlimited
|
||||
*/
|
||||
int max_sessions;
|
||||
unsigned int max_sessions;
|
||||
/**
|
||||
* @var max_idle_time
|
||||
* @brief maximum idle time for each session
|
||||
|
||||
@@ -180,14 +180,6 @@ auth_start_session(struct auth_info *auth_info, int display_num)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns error */
|
||||
int
|
||||
auth_stop_session(struct auth_info *auth_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
auth_end(struct auth_info *auth_info)
|
||||
|
||||
@@ -229,14 +229,6 @@ auth_start_session(struct auth_info *auth_info, int display_num)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns error */
|
||||
int
|
||||
auth_stop_session(struct auth_info *auth_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
auth_set_env(struct auth_info *auth_info)
|
||||
|
||||
@@ -438,7 +438,7 @@ auth_start_session(struct auth_info *auth_info, int display_num)
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns error */
|
||||
int
|
||||
static int
|
||||
auth_stop_session(struct auth_info *auth_info)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
@@ -248,7 +248,7 @@ auth_start_session(struct auth_info *auth_info, int display_num)
|
||||
|
||||
/******************************************************************************/
|
||||
/* returns error */
|
||||
int
|
||||
static int
|
||||
auth_stop_session(struct auth_info *auth_info)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2015
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file pre_session_list.h
|
||||
* @brief List of pre-session connections to sesman (definitions)
|
||||
*
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "arch.h"
|
||||
#include "list.h"
|
||||
#include "os_calls.h"
|
||||
#include "pre_session_list.h"
|
||||
#include "trans.h"
|
||||
|
||||
#define PRE_SESSION_IN_USE(si) \
|
||||
( \
|
||||
(si) != NULL && \
|
||||
( \
|
||||
((si)->client_trans != NULL && (si)->client_trans->status == TRANS_STATUS_UP) || \
|
||||
((si)->sesexec_trans != NULL && (si)->sesexec_trans->status == TRANS_STATUS_UP) \
|
||||
) \
|
||||
)
|
||||
|
||||
static struct list *g_pre_session_list = NULL;
|
||||
|
||||
/**
|
||||
* Deletes a pre_session_item, freeing resources
|
||||
*
|
||||
* After this call, the passed-in pointer is invalid and must not be
|
||||
* referenced.
|
||||
*
|
||||
* Any auth_info struct found in the sesman_con is also deallocated.
|
||||
*
|
||||
* @param sc struct to de-allocate
|
||||
*/
|
||||
static void
|
||||
free_pre_session_item(struct pre_session_item *psi)
|
||||
{
|
||||
if (psi != NULL)
|
||||
{
|
||||
trans_delete(psi->client_trans);
|
||||
trans_delete(psi->sesexec_trans);
|
||||
g_free(psi->username);
|
||||
g_free(psi);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
pre_session_list_init(unsigned int list_size)
|
||||
{
|
||||
int rv = 1;
|
||||
if (g_pre_session_list == NULL)
|
||||
{
|
||||
g_pre_session_list = list_create_sized(list_size);
|
||||
}
|
||||
|
||||
if (g_pre_session_list == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't allocate pre-session list");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pre_session_list->auto_free = 0;
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
pre_session_list_cleanup(void)
|
||||
{
|
||||
if (g_pre_session_list != NULL)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < g_pre_session_list->count ; ++i)
|
||||
{
|
||||
struct pre_session_item *p;
|
||||
p = (struct pre_session_item *)list_get_item(g_pre_session_list, i);
|
||||
free_pre_session_item(p);
|
||||
}
|
||||
list_delete(g_pre_session_list);
|
||||
g_pre_session_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
unsigned int
|
||||
pre_session_list_get_count(void)
|
||||
{
|
||||
return g_pre_session_list->count;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct pre_session_item *
|
||||
pre_session_list_new(void)
|
||||
{
|
||||
struct pre_session_item *result = g_new0(struct pre_session_item, 1);
|
||||
if (result != NULL)
|
||||
{
|
||||
g_snprintf(result->peername, sizeof(result->peername), "unknown");
|
||||
result->uid = (uid_t) -1;
|
||||
|
||||
if (!list_add_item(g_pre_session_list, (tintptr)result))
|
||||
{
|
||||
g_free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
pre_session_list_set_peername(struct pre_session_item *psi, const char *name)
|
||||
{
|
||||
int rv = 1;
|
||||
|
||||
if (psi != NULL && name != NULL)
|
||||
{
|
||||
g_snprintf(psi->peername, sizeof(psi->peername), "%s", name);
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
pre_session_list_get_wait_objs(tbus robjs[], int *robjs_count)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < g_pre_session_list->count)
|
||||
{
|
||||
struct pre_session_item *psi;
|
||||
psi = (struct pre_session_item *)list_get_item(g_pre_session_list, i);
|
||||
int psi_in_use = 0;
|
||||
|
||||
if (psi != NULL)
|
||||
{
|
||||
if (psi->client_trans != NULL &&
|
||||
psi->client_trans->status == TRANS_STATUS_UP)
|
||||
{
|
||||
robjs[(*robjs_count)++] = psi->client_trans->sck;
|
||||
psi_in_use = 1;
|
||||
}
|
||||
|
||||
if (psi->sesexec_trans != NULL &&
|
||||
psi->sesexec_trans->status == TRANS_STATUS_UP)
|
||||
{
|
||||
robjs[(*robjs_count)++] = psi->sesexec_trans->sck;
|
||||
psi_in_use = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (psi_in_use)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
free_pre_session_item(psi);
|
||||
list_remove_item(g_pre_session_list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
pre_session_list_check_wait_objs(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < g_pre_session_list->count)
|
||||
{
|
||||
struct pre_session_item *psi;
|
||||
enum pre_session_dispatcher_action action;
|
||||
|
||||
psi = (struct pre_session_item *)list_get_item(g_pre_session_list, i);
|
||||
action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
|
||||
if (PRE_SESSION_IN_USE(psi))
|
||||
{
|
||||
if (psi->client_trans != NULL &&
|
||||
psi->client_trans->status == TRANS_STATUS_UP)
|
||||
{
|
||||
if (trans_check_wait_objs(psi->client_trans) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "pre_session_list_check_wait_objs: "
|
||||
"trans_check_wait_objs(1) failed, removing trans");
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
}
|
||||
|
||||
if (psi->sesexec_trans != NULL &&
|
||||
psi->sesexec_trans->status == TRANS_STATUS_UP)
|
||||
{
|
||||
if (trans_check_wait_objs(psi->sesexec_trans) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "pre_session_list_check_wait_objs: "
|
||||
"trans_check_wait_objs(2) failed, removing trans");
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get any action, and reset the requested one */
|
||||
action = psi->dispatcher_action;
|
||||
psi->dispatcher_action = E_PSD_NONE;
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case E_PSD_NONE:
|
||||
/* On to the next item on the list */
|
||||
++i;
|
||||
break;
|
||||
|
||||
case E_PSD_REMOVE_CLIENT_TRANS:
|
||||
trans_delete(psi->client_trans);
|
||||
psi->client_trans = NULL;
|
||||
/* On to the next item on the list */
|
||||
++i;
|
||||
break;
|
||||
case E_PSD_TERMINATE_PRE_SESSION:
|
||||
free_pre_session_item(psi);
|
||||
list_remove_item(g_pre_session_list, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2013
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file pre_session_list.h
|
||||
* @brief List of pre-session connections to sesman (declarations)
|
||||
*
|
||||
* Items on this list are moved to the session list once they have
|
||||
* authenticated and a session is started.
|
||||
*
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PRE_SESSION_LIST_H
|
||||
#define PRE_SESSION_LIST_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
/**
|
||||
* Type describing the login state of a pre-session item
|
||||
*/
|
||||
enum ps_login_state
|
||||
{
|
||||
E_PS_LOGIN_NOT_LOGGED_IN = 0,
|
||||
E_PS_LOGIN_SYS,
|
||||
E_PS_LOGIN_UDS
|
||||
};
|
||||
|
||||
/**
|
||||
* Action we require the dispatcher to do for us
|
||||
*
|
||||
* We can't do some things in an SCP or EICP callback, so we have to
|
||||
* ask the dispatcher to do them. For example, we can't delete the
|
||||
* client_trans as the callback stack won't be expecting this.
|
||||
*/
|
||||
enum pre_session_dispatcher_action
|
||||
{
|
||||
E_PSD_NONE = 0,
|
||||
E_PSD_REMOVE_CLIENT_TRANS,
|
||||
E_PSD_TERMINATE_PRE_SESSION
|
||||
};
|
||||
|
||||
/**
|
||||
* Type for managing sesman connections from SCP clients (xrdp, etc)
|
||||
* and any sesexec processes we've created for them.
|
||||
*/
|
||||
struct pre_session_item
|
||||
{
|
||||
struct trans *client_trans; ///< SCP link to sesman client
|
||||
struct trans *sesexec_trans; ///< ECP link to sesexec
|
||||
pid_t sesexec_pid; ///< PID of sesexec (if sesexec is active)
|
||||
char peername[15 + 1]; ///< Name of peer, if known, for logging
|
||||
enum ps_login_state login_state; ///< Login state
|
||||
/**
|
||||
* Any action which a callback requires the dispatcher to
|
||||
* do out of scope of the callback */
|
||||
enum pre_session_dispatcher_action dispatcher_action;
|
||||
uid_t uid; ///< User
|
||||
char *username; ///< Username from UID (at time of logon)
|
||||
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the module
|
||||
* @param list_size Number of pre-session items allowed
|
||||
* @return 0 for success
|
||||
*
|
||||
* Errors are logged
|
||||
*/
|
||||
int
|
||||
pre_session_list_init(unsigned int list_size);
|
||||
|
||||
/**
|
||||
* Clean up the module on program exit
|
||||
*/
|
||||
void
|
||||
pre_session_list_cleanup(void);
|
||||
|
||||
/**
|
||||
* Returns the number of items on the pre-session list
|
||||
* @return Item count
|
||||
*/
|
||||
unsigned int
|
||||
pre_session_list_get_count(void);
|
||||
|
||||
/**
|
||||
* Allocates a new pre-session item on the list
|
||||
*
|
||||
* @return pointer to new pre-session object or NULL for no memory
|
||||
*
|
||||
* After allocating the session, you must initialise the sesexec_trans field
|
||||
* with a valid transport.
|
||||
*
|
||||
* The session is removed by pre_session_list_get_wait_objs() or
|
||||
* pre_session_check_wait_objs() when the client
|
||||
* transport goes down (or wasn't allocated in the first place).
|
||||
*/
|
||||
struct pre_session_item *
|
||||
pre_session_list_new(void);
|
||||
|
||||
/**
|
||||
* Set the peername of a pre-session
|
||||
*
|
||||
* @param psi pre-session-item
|
||||
* @param name Name to set
|
||||
* @result 0 for success
|
||||
*/
|
||||
int
|
||||
pre_session_list_set_peername(struct pre_session_item *psi, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the wait objs for the pre-session list module
|
||||
* @param @robjs Objects array to update
|
||||
* @param robjs_count Elements in robjs (by reference)
|
||||
* @return 0 for success
|
||||
*/
|
||||
int
|
||||
pre_session_list_get_wait_objs(tbus robjs[], int *robjs_count);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check the wait objs for the pre-session list module
|
||||
* @return 0 for success
|
||||
*/
|
||||
int
|
||||
pre_session_list_check_wait_objs(void);
|
||||
|
||||
#endif // PRE_SESSION_LIST_H
|
||||
+272
-391
@@ -30,106 +30,149 @@
|
||||
|
||||
#include "trans.h"
|
||||
#include "os_calls.h"
|
||||
#include "eicp.h"
|
||||
#include "ercp.h"
|
||||
#include "scp.h"
|
||||
#include "sesman_config.h"
|
||||
|
||||
#include "scp_process.h"
|
||||
#include "sesman.h"
|
||||
#include "sesman_access.h"
|
||||
#include "sesman_auth.h"
|
||||
#include "guid.h"
|
||||
#include "sesman_config.h"
|
||||
#include "os_calls.h"
|
||||
#include "pre_session_list.h"
|
||||
#include "session_list.h"
|
||||
#include "session.h"
|
||||
#include "sesman.h"
|
||||
#include "sesexec_control.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
/**************************************************************************//**
|
||||
* Logs an authentication failure message
|
||||
*
|
||||
* @param username Username
|
||||
* @param ip_addr IP address, if known
|
||||
*
|
||||
* The message is intended for use by fail2ban. Make changes with care.
|
||||
*/
|
||||
static void
|
||||
log_authfail_message(const char *username, const char *ip_addr)
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_set_peername_request(struct pre_session_item *psi)
|
||||
{
|
||||
if (ip_addr == NULL || ip_addr[0] == '\0')
|
||||
int rv;
|
||||
const char *peername;
|
||||
|
||||
rv = scp_get_set_peername_request(psi->client_trans, &peername);
|
||||
if (rv == 0)
|
||||
{
|
||||
ip_addr = "unknown";
|
||||
if (pre_session_list_set_peername(psi, peername) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Failed to set connection peername from %s to %s",
|
||||
psi->peername, peername);
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "AUTHFAIL: user=%s ip=%s time=%d",
|
||||
username, ip_addr, g_time1());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
process_sys_login_request(struct pre_session_item *psi)
|
||||
{
|
||||
int rv;
|
||||
const char *username;
|
||||
const char *password;
|
||||
const char *ip_addr;
|
||||
int send_client_reply = 1;
|
||||
|
||||
rv = scp_get_sys_login_request(psi->client_trans, &username,
|
||||
&password, &ip_addr);
|
||||
if (rv == 0)
|
||||
{
|
||||
enum scp_login_status errorcode;
|
||||
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Received system login request from %s for user: %s IP: %s",
|
||||
psi->peername, username, ip_addr);
|
||||
|
||||
if (psi->login_state != E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
errorcode = E_SCP_LOGIN_ALREADY_LOGGED_IN;
|
||||
LOG(LOG_LEVEL_ERROR, "Connection is already logged in for %s",
|
||||
psi->username);
|
||||
}
|
||||
else if ((psi->username = g_strdup(username)) == NULL)
|
||||
{
|
||||
errorcode = E_SCP_LOGIN_NO_MEMORY;
|
||||
LOG(LOG_LEVEL_ERROR, "Memory allocation failure logging in %s",
|
||||
username);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a sesexec process to handle the login
|
||||
*
|
||||
* We won't check for the user being valid here, as this might
|
||||
* lead to information leakage */
|
||||
if (sesexec_start(psi) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't start sesexec to authenticate user");
|
||||
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
int eicp_stat;
|
||||
eicp_stat = eicp_send_sys_login_request(psi->sesexec_trans,
|
||||
username,
|
||||
password,
|
||||
ip_addr,
|
||||
psi->client_trans->sck);
|
||||
if (eicp_stat != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't ask sesexec to authenticate user");
|
||||
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We've handed over responsibility for the
|
||||
* SCP communication */
|
||||
send_client_reply = 0;
|
||||
psi->dispatcher_action = E_PSD_REMOVE_CLIENT_TRANS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (send_client_reply)
|
||||
{
|
||||
/* We only get here if something has gone
|
||||
* wrong with the handover to sesexec */
|
||||
rv = scp_send_login_response(psi->client_trans, errorcode, 1);
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* Mode parameter for authenticate_and_authorize_connection()
|
||||
*/
|
||||
enum login_mode
|
||||
{
|
||||
AM_SYSTEM,
|
||||
AM_UDS
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticate and authorize the connection
|
||||
* Authenticate and authorize a UDS connection
|
||||
*
|
||||
* @param sc Connection to sesman
|
||||
* @param login_mode Describes the type of login in use
|
||||
* @param psi Connection to sesman
|
||||
* @param uid UID for user
|
||||
* @param username Name for user
|
||||
* @param password Password (AM_SYSTEM) or NULL.
|
||||
* @param ip_addr Remote IP address (AM_SYSTEM) or NULL.
|
||||
* @return Status for the operation
|
||||
*
|
||||
* @pre sc->auth_info, sc->username and sc->ip_addr must be NULL
|
||||
*
|
||||
* @post If E_SCP_LOGIN_OK is returned, sc->auth_info is non-NULL
|
||||
* @post If E_SCP_LOGIN_OK is returned, sc->username is non-NULL
|
||||
* @post If E_SCP_LOGIN_OK is returned, sc->ip_addr is non-NULL
|
||||
*
|
||||
* @post If E_SCP_LOGIN_OK is returned, psi->username is non-NULL
|
||||
*/
|
||||
static enum scp_login_status
|
||||
authenticate_and_authorize_connection(struct sesman_con *sc,
|
||||
enum login_mode login_mode,
|
||||
authenticate_and_authorize_uds_connection(struct pre_session_item *psi,
|
||||
int uid,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *ip_addr)
|
||||
const char *username)
|
||||
{
|
||||
enum scp_login_status status = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
struct auth_info *auth_info = NULL;
|
||||
|
||||
/* Check preconditions */
|
||||
if (sc->auth_info != NULL || sc->username != NULL || sc->ip_addr != NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Internal error - connection already logged in");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (login_mode)
|
||||
{
|
||||
case AM_SYSTEM:
|
||||
auth_info = auth_userpass(username, password, ip_addr, &status);
|
||||
break;
|
||||
case AM_UDS:
|
||||
auth_info = auth_uds(username, &status);
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_LEVEL_ERROR, "%s called with invalid mode %d",
|
||||
__func__, (int)login_mode);
|
||||
}
|
||||
|
||||
struct auth_info *auth_info = auth_uds(username, &status);
|
||||
if (auth_info != NULL)
|
||||
{
|
||||
if (status != E_SCP_LOGIN_OK)
|
||||
{
|
||||
/* This shouldn't happen */
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Unexpected status return %d from auth call",
|
||||
"Unexpected status return %d from auth_uds call",
|
||||
(int)status);
|
||||
}
|
||||
else if (!access_login_allowed(&g_cfg->sec, username))
|
||||
@@ -139,39 +182,29 @@ authenticate_and_authorize_connection(struct sesman_con *sc,
|
||||
"user: %s", username);
|
||||
}
|
||||
|
||||
/* If all is well, put the auth_info in the sesman connection
|
||||
* for later use. If not, remove the auth_info */
|
||||
/* If all is well, add info to the sesman connection for later use */
|
||||
if (status == E_SCP_LOGIN_OK)
|
||||
{
|
||||
char *dup_username = g_strdup(username);
|
||||
char *dup_ip_addr =
|
||||
(ip_addr == NULL) ? g_strdup("") : g_strdup(ip_addr);
|
||||
|
||||
if (dup_username == NULL || dup_ip_addr == NULL)
|
||||
if ((psi->username = g_strdup(username)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s : Memory allocation failed",
|
||||
__func__);
|
||||
g_free(dup_username);
|
||||
g_free(dup_ip_addr);
|
||||
g_free(psi->username);
|
||||
psi->username = NULL;
|
||||
status = E_SCP_LOGIN_NO_MEMORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
sc->ip_addr = dup_ip_addr;
|
||||
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
|
||||
username);
|
||||
psi->login_state = E_PS_LOGIN_UDS;
|
||||
psi->uid = uid;
|
||||
psi->start_ip_addr[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (status != E_SCP_LOGIN_OK)
|
||||
{
|
||||
auth_end(auth_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -179,199 +212,7 @@ authenticate_and_authorize_connection(struct sesman_con *sc,
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_set_peername_request(struct sesman_con *sc)
|
||||
{
|
||||
int rv;
|
||||
const char *peername;
|
||||
|
||||
rv = scp_get_set_peername_request(sc->t, &peername);
|
||||
if (rv == 0)
|
||||
{
|
||||
if (sesman_set_connection_peername(sc, peername) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Failed to set connection peername from %s to %s",
|
||||
sc->peername, peername);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
process_sys_login_request(struct sesman_con *sc)
|
||||
{
|
||||
int rv;
|
||||
const char *supplied_username;
|
||||
const char *password;
|
||||
const char *ip_addr;
|
||||
|
||||
rv = scp_get_sys_login_request(sc->t, &supplied_username,
|
||||
&password, &ip_addr);
|
||||
if (rv == 0)
|
||||
{
|
||||
enum scp_login_status errorcode;
|
||||
int server_closed = 1;
|
||||
int uid;
|
||||
char *username = NULL;
|
||||
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Received system login request from %s for user: %s IP: %s",
|
||||
sc->peername, supplied_username, ip_addr);
|
||||
|
||||
if (sc->auth_info != NULL)
|
||||
{
|
||||
errorcode = E_SCP_LOGIN_ALREADY_LOGGED_IN;
|
||||
LOG(LOG_LEVEL_ERROR, "Connection is already logged in for %s",
|
||||
sc->username);
|
||||
}
|
||||
else if (g_getuser_info_by_name(supplied_username,
|
||||
&uid, NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
/* we can't get a UID for the user */
|
||||
errorcode = E_SCP_LOGIN_NOT_AUTHENTICATED;
|
||||
LOG(LOG_LEVEL_ERROR, "Can't get UID for user %s",
|
||||
supplied_username);
|
||||
log_authfail_message(username, ip_addr);
|
||||
}
|
||||
else if (g_getuser_info_by_uid(uid,
|
||||
&username, NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
LOG(LOG_LEVEL_ERROR, "Can't reverse lookup UID %d", uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_strcmp(supplied_username, username) != 0)
|
||||
{
|
||||
/*
|
||||
* If using a federated naming service (e.g. AD), the
|
||||
* username supplied may not match that name mapped to by
|
||||
* the UID. We will generate a warning in this instance so
|
||||
* the user can see what is being used within sesman
|
||||
*/
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Using username %s for the session (from UID %d)",
|
||||
username, uid);
|
||||
}
|
||||
|
||||
errorcode = authenticate_and_authorize_connection(
|
||||
sc, AM_SYSTEM,
|
||||
uid, username,
|
||||
password, ip_addr);
|
||||
if (errorcode == E_SCP_LOGIN_OK)
|
||||
{
|
||||
server_closed = 0;
|
||||
}
|
||||
else if (errorcode == E_SCP_LOGIN_NOT_AUTHENTICATED)
|
||||
{
|
||||
log_authfail_message(username, ip_addr);
|
||||
if (sc->auth_retry_count > 0)
|
||||
{
|
||||
/* Password problem? Invite the user to retry */
|
||||
server_closed = 0;
|
||||
--sc->auth_retry_count;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(username);
|
||||
}
|
||||
|
||||
if (server_closed)
|
||||
{
|
||||
/* Expecting no more client messages. Close the connection
|
||||
* after returning from this callback */
|
||||
sc->close_requested = 1;
|
||||
}
|
||||
|
||||
rv = scp_send_login_response(sc->t, errorcode, server_closed);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_uds_login_request(struct sesman_con *sc)
|
||||
process_uds_login_request(struct pre_session_item *psi)
|
||||
{
|
||||
enum scp_login_status errorcode;
|
||||
int rv;
|
||||
@@ -380,25 +221,25 @@ process_uds_login_request(struct sesman_con *sc)
|
||||
char *username = NULL;
|
||||
int server_closed = 1;
|
||||
|
||||
rv = g_sck_get_peer_cred(sc->t->sck, &pid, &uid, NULL);
|
||||
rv = g_sck_get_peer_cred(psi->client_trans->sck, &pid, &uid, NULL);
|
||||
if (rv != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Unable to get peer credentials for socket %d",
|
||||
(int)sc->t->sck);
|
||||
(int)psi->client_trans->sck);
|
||||
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Received UDS login request from %s for UID: %d from PID: %d",
|
||||
sc->peername, uid, pid);
|
||||
psi->peername, uid, pid);
|
||||
|
||||
if (sc->auth_info != NULL)
|
||||
if (psi->login_state != E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
errorcode = E_SCP_LOGIN_ALREADY_LOGGED_IN;
|
||||
LOG(LOG_LEVEL_ERROR, "Connection is already logged in for %s",
|
||||
sc->username);
|
||||
psi->username);
|
||||
}
|
||||
else if (g_getuser_info_by_uid(uid, &username,
|
||||
NULL, NULL, NULL, NULL) != 0)
|
||||
@@ -408,10 +249,8 @@ process_uds_login_request(struct sesman_con *sc)
|
||||
}
|
||||
else
|
||||
{
|
||||
errorcode = authenticate_and_authorize_connection(
|
||||
sc, AM_UDS,
|
||||
uid, username,
|
||||
NULL, NULL);
|
||||
errorcode = authenticate_and_authorize_uds_connection(
|
||||
psi, uid, username);
|
||||
g_free(username);
|
||||
|
||||
if (errorcode == E_SCP_LOGIN_OK)
|
||||
@@ -424,27 +263,40 @@ process_uds_login_request(struct sesman_con *sc)
|
||||
if (server_closed)
|
||||
{
|
||||
/* Close the connection after returning from this callback */
|
||||
sc->close_requested = 1;
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
}
|
||||
|
||||
return scp_send_login_response(sc->t, errorcode, server_closed);
|
||||
return scp_send_login_response(psi->client_trans, errorcode, server_closed);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
logout_pre_session(struct pre_session_item *psi)
|
||||
{
|
||||
if (psi->login_state != E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
(void)eicp_send_logout_request(psi->sesexec_trans);
|
||||
trans_delete(psi->sesexec_trans);
|
||||
psi->sesexec_trans = NULL;
|
||||
psi->uid = (uid_t) -1;
|
||||
g_free(psi->username);
|
||||
psi->username = NULL;
|
||||
psi->start_ip_addr[0] = '\0';
|
||||
|
||||
psi->login_state = E_PS_LOGIN_NOT_LOGGED_IN;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_logout_request(struct sesman_con *sc)
|
||||
process_logout_request(struct pre_session_item *psi)
|
||||
{
|
||||
if (sc->auth_info != NULL)
|
||||
if (psi->login_state != E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Logging out %s from sesman", sc->username);
|
||||
auth_end(sc->auth_info);
|
||||
sc->auth_info = NULL;
|
||||
sc->uid = -1;
|
||||
g_free(sc->username);
|
||||
sc->username = NULL;
|
||||
g_free(sc->ip_addr);
|
||||
sc->ip_addr = NULL;
|
||||
LOG(LOG_LEVEL_INFO, "Logging out %s from sesman", psi->username);
|
||||
logout_pre_session(psi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -453,117 +305,146 @@ process_logout_request(struct sesman_con *sc)
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_create_session_request(struct sesman_con *sc)
|
||||
process_create_session_request(struct pre_session_item *psi)
|
||||
{
|
||||
int rv;
|
||||
// Parameters for a new session (if required). Filled in as
|
||||
// we go along.
|
||||
struct session_parameters sp = {0};
|
||||
const char *shellptr;
|
||||
const char *dirptr;
|
||||
/* Client parameters describing new session*/
|
||||
enum scp_session_type type;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned char bpp;
|
||||
const char *shell;
|
||||
const char *directory;
|
||||
|
||||
struct guid guid;
|
||||
int display = 0;
|
||||
struct session_item *s_item = NULL;
|
||||
int send_client_reply = 1;
|
||||
|
||||
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, &shellptr, &dirptr);
|
||||
rv = scp_get_create_session_request(psi->client_trans,
|
||||
&type, &width, &height,
|
||||
&bpp, &shell, &directory);
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
if (sc->auth_info == NULL)
|
||||
if (psi->login_state == E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
status = E_SCP_SCREATE_NOT_LOGGED_IN;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"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);
|
||||
"Received request from %s to create a session for user %s",
|
||||
psi->peername, psi->username);
|
||||
|
||||
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)
|
||||
s_item = session_list_get_bydata(psi->uid, type, width, height,
|
||||
bpp, psi->start_ip_addr);
|
||||
if (s_item != NULL)
|
||||
{
|
||||
// Found an existing session
|
||||
if (sc->ip_addr[0] != '\0')
|
||||
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 (psi->start_ip_addr[0] != '\0')
|
||||
{
|
||||
LOG( LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d, ip %s",
|
||||
sc->username, s_item->display, s_item->pid,
|
||||
sc->ip_addr);
|
||||
psi->username, display,
|
||||
s_item->sesexec_pid, psi->start_ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, "
|
||||
"display :%d.0, session_pid %d",
|
||||
sc->username, s_item->display, s_item->pid);
|
||||
psi->username, display, s_item->sesexec_pid);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// If we created an authentication process for this SCP
|
||||
// connection, close it gracefully
|
||||
logout_pre_session(psi);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to create a new session
|
||||
//
|
||||
// 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)
|
||||
else if (g_cfg->sess.max_sessions > 0 &&
|
||||
session_list_get_count() >= g_cfg->sess.max_sessions)
|
||||
{
|
||||
status = E_SCP_SCREATE_MAX_REACHED;
|
||||
}
|
||||
else if ((display = session_list_get_available_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 sesexec process if we don't have one (UDS login)
|
||||
else if (psi->sesexec_trans == NULL && sesexec_start(psi) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't start sesexec to authenticate user");
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
// Pass the session create request to sesexec
|
||||
int eicp_stat;
|
||||
eicp_stat = eicp_send_create_session_request(
|
||||
psi->sesexec_trans,
|
||||
psi->client_trans->sck,
|
||||
display,
|
||||
type, width, height,
|
||||
bpp, shell, directory);
|
||||
|
||||
status = allocate_and_start_session(auth_info,
|
||||
sc->username,
|
||||
sc->ip_addr,
|
||||
&sp);
|
||||
if (status != E_SCP_SCREATE_OK)
|
||||
if (eicp_stat != 0)
|
||||
{
|
||||
// Close the auth session down as it can't be re-used.
|
||||
auth_end(auth_info);
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Can't ask sesexec to authenticate user");
|
||||
status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've handed over responsibility for the
|
||||
// SCP communication
|
||||
send_client_reply = 0;
|
||||
|
||||
// Further comms from sesexec comes over the ERCP
|
||||
// protocol
|
||||
ercp_trans_from_eicp_trans(psi->sesexec_trans,
|
||||
sesman_ercp_data_in,
|
||||
(void *)s_item);
|
||||
|
||||
// Move the transport over to the session list item
|
||||
s_item->sesexec_trans = psi->sesexec_trans;
|
||||
s_item->sesexec_pid = psi->sesexec_pid;
|
||||
psi->sesexec_trans = NULL;
|
||||
psi->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently a create session request is the last thing on a
|
||||
* connection, and results in automatic closure */
|
||||
sc->close_requested = 1;
|
||||
|
||||
rv = scp_send_create_session_response(sc->t, status,
|
||||
display, &guid);
|
||||
// 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.
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
if (send_client_reply)
|
||||
{
|
||||
rv = scp_send_create_session_response(psi->client_trans,
|
||||
status, display, &guid);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -572,7 +453,7 @@ process_create_session_request(struct sesman_con *sc)
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_list_sessions_request(struct sesman_con *sc)
|
||||
process_list_sessions_request(struct pre_session_item *psi)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
@@ -580,9 +461,9 @@ process_list_sessions_request(struct sesman_con *sc)
|
||||
unsigned int cnt = 0;
|
||||
unsigned int i;
|
||||
|
||||
if (sc->auth_info == NULL)
|
||||
if (psi->login_state == E_PS_LOGIN_NOT_LOGGED_IN)
|
||||
{
|
||||
rv = scp_send_list_sessions_response(sc->t,
|
||||
rv = scp_send_list_sessions_response(psi->client_trans,
|
||||
E_SCP_LS_NOT_LOGGED_IN,
|
||||
NULL);
|
||||
}
|
||||
@@ -590,14 +471,13 @@ process_list_sessions_request(struct sesman_con *sc)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Received request from %s to list sessions for user %s",
|
||||
sc->peername, sc->username);
|
||||
psi->peername, psi->username);
|
||||
|
||||
info = session_list_get_byuid(sc->uid, &cnt,
|
||||
SESMAN_SESSION_STATUS_ALL);
|
||||
info = session_list_get_byuid(psi->uid, &cnt, 0);
|
||||
|
||||
for (i = 0; rv == 0 && i < cnt; ++i)
|
||||
{
|
||||
rv = scp_send_list_sessions_response(sc->t,
|
||||
rv = scp_send_list_sessions_response(psi->client_trans,
|
||||
E_SCP_LS_SESSION_INFO,
|
||||
&info[i]);
|
||||
}
|
||||
@@ -605,7 +485,7 @@ process_list_sessions_request(struct sesman_con *sc)
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
rv = scp_send_list_sessions_response(sc->t,
|
||||
rv = scp_send_list_sessions_response(psi->client_trans,
|
||||
E_SCP_LS_END_OF_LIST,
|
||||
NULL);
|
||||
}
|
||||
@@ -617,54 +497,54 @@ process_list_sessions_request(struct sesman_con *sc)
|
||||
/******************************************************************************/
|
||||
|
||||
static int
|
||||
process_close_connection_request(struct sesman_con *sc)
|
||||
process_close_connection_request(struct pre_session_item *psi)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "Received request to close connection from %s",
|
||||
sc->peername);
|
||||
psi->peername);
|
||||
|
||||
/* Expecting no more client messages. Close the connection
|
||||
* after returning from this callback */
|
||||
sc->close_requested = 1;
|
||||
psi->dispatcher_action = E_PSD_TERMINATE_PRE_SESSION;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
scp_process(struct sesman_con *sc)
|
||||
scp_process(struct pre_session_item *psi)
|
||||
{
|
||||
enum scp_msg_code msgno;
|
||||
int rv = 0;
|
||||
|
||||
switch ((msgno = scp_msg_in_get_msgno(sc->t)))
|
||||
switch ((msgno = scp_msg_in_get_msgno(psi->client_trans)))
|
||||
{
|
||||
case E_SCP_SET_PEERNAME_REQUEST:
|
||||
rv = process_set_peername_request(sc);
|
||||
rv = process_set_peername_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_SYS_LOGIN_REQUEST:
|
||||
rv = process_sys_login_request(sc);
|
||||
rv = process_sys_login_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_UDS_LOGIN_REQUEST:
|
||||
rv = process_uds_login_request(sc);
|
||||
rv = process_uds_login_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_LOGOUT_REQUEST:
|
||||
rv = process_logout_request(sc);
|
||||
rv = process_logout_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_CREATE_SESSION_REQUEST:
|
||||
rv = process_create_session_request(sc);
|
||||
rv = process_create_session_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_LIST_SESSIONS_REQUEST:
|
||||
rv = process_list_sessions_request(sc);
|
||||
rv = process_list_sessions_request(psi);
|
||||
break;
|
||||
|
||||
case E_SCP_CLOSE_CONNECTION_REQUEST:
|
||||
rv = process_close_connection_request(sc);
|
||||
rv = process_close_connection_request(psi);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -676,3 +556,4 @@ scp_process(struct sesman_con *sc)
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef SCP_PROCESS_H
|
||||
#define SCP_PROCESS_H
|
||||
|
||||
struct sesman_con;
|
||||
struct pre_session_item;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -36,6 +36,6 @@ struct sesman_con;
|
||||
*
|
||||
*/
|
||||
int
|
||||
scp_process(struct sesman_con *sc);
|
||||
scp_process(struct pre_session_item *sc);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
AM_CPPFLAGS = \
|
||||
-DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \
|
||||
-DXRDP_SBIN_PATH=\"${sbindir}\" \
|
||||
-DXRDP_LIBEXEC_PATH=\"${libexecdir}/xrdp\" \
|
||||
-DXRDP_SOCKET_PATH=\"${socketdir}\" \
|
||||
-I$(top_srcdir)/sesman/libsesman \
|
||||
-I$(top_srcdir)/libipm \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
SESEXEC_EXTRA_LIBS =
|
||||
|
||||
pkglibexec_PROGRAMS = \
|
||||
xrdp-sesexec
|
||||
|
||||
xrdp_sesexec_SOURCES = \
|
||||
sesexec.c \
|
||||
sesexec.h \
|
||||
session.c \
|
||||
session.h \
|
||||
eicp_server.c \
|
||||
eicp_server.h \
|
||||
ercp_server.c \
|
||||
ercp_server.h \
|
||||
env.c \
|
||||
env.h \
|
||||
login_info.c \
|
||||
login_info.h \
|
||||
xauth.c \
|
||||
xauth.h \
|
||||
xwait.c \
|
||||
xwait.h
|
||||
|
||||
xrdp_sesexec_LDFLAGS =
|
||||
|
||||
xrdp_sesexec_LDADD = \
|
||||
$(top_builddir)/sesman/libsesman/libsesman.la \
|
||||
$(top_builddir)/libipm/libipm.la \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
$(SESEXEC_EXTRA_LIBS)
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 eicp_server.c
|
||||
* @brief eicp (executive initialisation control protocol) server function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "trans.h"
|
||||
|
||||
#include "eicp.h"
|
||||
#include "eicp_server.h"
|
||||
#include "login_info.h"
|
||||
#include "os_calls.h"
|
||||
#include "ercp.h"
|
||||
#include "scp.h"
|
||||
#include "sesexec.h"
|
||||
#include "session.h"
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_sys_login_request(struct trans *self)
|
||||
{
|
||||
const char *username;
|
||||
const char *password;
|
||||
const char *ip_addr;
|
||||
int scp_fd;
|
||||
|
||||
int rv = eicp_get_sys_login_request(self, &username,
|
||||
&password, &ip_addr, &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
|
||||
{
|
||||
g_login_info = login_info_sys_login_user(scp_trans, username,
|
||||
password, ip_addr);
|
||||
|
||||
if (g_login_info != NULL)
|
||||
{
|
||||
rv = eicp_send_sys_login_response(self, 1,
|
||||
g_login_info->uid, scp_fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = eicp_send_sys_login_response(self, 0, (uid_t) -1, 0);
|
||||
}
|
||||
|
||||
trans_delete(scp_trans); // Closes scp_fd as well
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_logout_request(struct trans *self)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp-sesexec pid %d is now logging out", g_pid);
|
||||
sesexec_terminate_main_loop(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_create_session_request(struct trans *self)
|
||||
{
|
||||
int scp_fd;
|
||||
struct session_parameters sp = {0};
|
||||
int rv;
|
||||
|
||||
rv = eicp_get_create_session_request(self, &scp_fd, &sp.display,
|
||||
&sp.type, &sp.width, &sp.height,
|
||||
&sp.bpp, &sp.shell, &sp.directory);
|
||||
if (rv == 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);
|
||||
rv = 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)
|
||||
{
|
||||
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
if (scp_status == E_SCP_SCREATE_OK)
|
||||
{
|
||||
// Try to create the session
|
||||
sp.guid = guid_new();
|
||||
scp_status = session_start(g_login_info, &sp, &g_session_data);
|
||||
}
|
||||
|
||||
// Return the status to the SCP client
|
||||
rv = scp_send_create_session_response(scp_trans, scp_status,
|
||||
sp.display, &sp.guid);
|
||||
trans_delete(scp_trans);
|
||||
|
||||
// Further comms from sesexec 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)
|
||||
{
|
||||
rv = ercp_send_session_announce_event(
|
||||
self,
|
||||
sp.display,
|
||||
g_login_info->uid,
|
||||
sp.type,
|
||||
sp.width,
|
||||
sp.height,
|
||||
sp.bpp,
|
||||
&sp.guid,
|
||||
g_login_info->ip_addr,
|
||||
session_get_start_time(g_session_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = ercp_send_session_finished_event(self);
|
||||
sesexec_terminate_main_loop(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
eicp_server(struct trans *self)
|
||||
{
|
||||
int rv = 0;
|
||||
enum eicp_msg_code msgno;
|
||||
|
||||
switch ((msgno = eicp_msg_in_get_msgno(self)))
|
||||
{
|
||||
case E_EICP_SYS_LOGIN_REQUEST:
|
||||
rv = handle_sys_login_request(self);
|
||||
break;
|
||||
|
||||
case E_EICP_LOGOUT_REQUEST:
|
||||
rv = handle_logout_request(self);
|
||||
break;
|
||||
|
||||
case E_EICP_CREATE_SESSION_REQUEST:
|
||||
rv = handle_create_session_request(self);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
eicp_msgno_to_str(msgno, buff, sizeof(buff));
|
||||
LOG(LOG_LEVEL_ERROR, "Ignored EICP message %s", buff);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 eicp_server.h
|
||||
* @brief eicp (executive initialisation control protocol) server function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EICP_SERVER_H
|
||||
#define EICP_SERVER_H
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Processes an EICP message
|
||||
* @param self The EICP transport the message is coming in on
|
||||
*
|
||||
*/
|
||||
int
|
||||
eicp_server(struct trans *self);
|
||||
|
||||
#endif // EICP_SERVER_H
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "sesman.h"
|
||||
#include "sesexec.h"
|
||||
#include "ssl_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_sockets.h"
|
||||
@@ -62,10 +62,10 @@ env_check_password_file(const char *filename, const char *passwd)
|
||||
ssl_sha1_transform(sha1, passwd, passwd_bytes);
|
||||
ssl_sha1_complete(sha1, passwd_hash);
|
||||
ssl_sha1_info_delete(sha1);
|
||||
g_snprintf(passwd_hash_text, 39, "%2.2x%2.2x%2.2x%2.2x",
|
||||
g_snprintf(passwd_hash_text, sizeof(passwd_hash_text),
|
||||
"%2.2x%2.2x%2.2x%2.2x",
|
||||
(tui8)passwd_hash[0], (tui8)passwd_hash[1],
|
||||
(tui8)passwd_hash[2], (tui8)passwd_hash[3]);
|
||||
passwd_hash_text[39] = 0;
|
||||
passwd = passwd_hash_text;
|
||||
|
||||
/* create file from password */
|
||||
@@ -138,28 +138,28 @@ env_set_user(int uid, char **passwd_file, int display,
|
||||
g_setenv("PATH", "/sbin:/bin:/usr/bin:/usr/local/bin", 1);
|
||||
}
|
||||
#endif
|
||||
g_mk_socket_path(0);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
g_setenv("SHELL", pw_shell, 1);
|
||||
g_setenv("USER", pw_username, 1);
|
||||
g_setenv("LOGNAME", pw_username, 1);
|
||||
g_sprintf(text, "%d", uid);
|
||||
g_snprintf(text, sizeof(text), "%d", uid);
|
||||
g_setenv("UID", text, 1);
|
||||
g_setenv("HOME", pw_dir, 1);
|
||||
g_set_current_dir(pw_dir);
|
||||
g_sprintf(text, ":%d.0", display);
|
||||
g_snprintf(text, sizeof(text), ":%d.0", display);
|
||||
g_setenv("DISPLAY", text, 1);
|
||||
g_setenv("XRDP_SESSION", "1", 1);
|
||||
// Use our PID as the XRDP_SESSION value
|
||||
g_snprintf(text, sizeof(text), "%d", g_pid);
|
||||
g_setenv("XRDP_SESSION", text, 1);
|
||||
/* XRDP_SOCKET_PATH should be set even here. It's used by
|
||||
* xorgxrdp and the pulseaudio plugin */
|
||||
g_setenv("XRDP_SOCKET_PATH", XRDP_SOCKET_PATH, 1);
|
||||
/* pulse sink socket */
|
||||
g_snprintf(text, sizeof(text) - 1, CHANSRV_PORT_OUT_BASE_STR, display);
|
||||
g_snprintf(text, sizeof(text), CHANSRV_PORT_OUT_BASE_STR, display);
|
||||
g_setenv("XRDP_PULSE_SINK_SOCKET", text, 1);
|
||||
/* pulse source socket */
|
||||
g_snprintf(text, sizeof(text) - 1, CHANSRV_PORT_IN_BASE_STR, display);
|
||||
g_snprintf(text, sizeof(text), CHANSRV_PORT_IN_BASE_STR, display);
|
||||
g_setenv("XRDP_PULSE_SOURCE_SOCKET", text, 1);
|
||||
if ((env_names != 0) && (env_values != 0) &&
|
||||
(env_names->count == env_values->count))
|
||||
@@ -191,12 +191,14 @@ env_set_user(int uid, char **passwd_file, int display,
|
||||
|
||||
len = g_snprintf(NULL, 0, "%s/.vnc/sesman_passwd-%s@%s:%d",
|
||||
pw_dir, pw_username, hostname, display);
|
||||
++len; // Allow for terminator
|
||||
|
||||
*passwd_file = (char *) g_malloc(len + 1, 1);
|
||||
*passwd_file = (char *) g_malloc(len, 1);
|
||||
if (*passwd_file != NULL)
|
||||
{
|
||||
/* Try legacy names first, remove if found */
|
||||
g_sprintf(*passwd_file, "%s/.vnc/sesman_%s_passwd:%d",
|
||||
g_snprintf(*passwd_file, len,
|
||||
"%s/.vnc/sesman_%s_passwd:%d",
|
||||
pw_dir, pw_username, display);
|
||||
if (g_file_exist(*passwd_file))
|
||||
{
|
||||
@@ -204,7 +206,8 @@ env_set_user(int uid, char **passwd_file, int display,
|
||||
"password file %s", *passwd_file);
|
||||
g_file_delete(*passwd_file);
|
||||
}
|
||||
g_sprintf(*passwd_file, "%s/.vnc/sesman_%s_passwd",
|
||||
g_snprintf(*passwd_file, len,
|
||||
"%s/.vnc/sesman_%s_passwd",
|
||||
pw_dir, pw_username);
|
||||
if (g_file_exist(*passwd_file))
|
||||
{
|
||||
@@ -212,7 +215,8 @@ env_set_user(int uid, char **passwd_file, int display,
|
||||
"password file %s", *passwd_file);
|
||||
g_file_delete(*passwd_file);
|
||||
}
|
||||
g_sprintf(*passwd_file, "%s/.vnc/sesman_passwd-%s@%s:%d",
|
||||
g_snprintf(*passwd_file, len,
|
||||
"%s/.vnc/sesman_passwd-%s@%s:%d",
|
||||
pw_dir, pw_username, hostname, display);
|
||||
}
|
||||
}
|
||||
@@ -221,10 +225,12 @@ env_set_user(int uid, char **passwd_file, int display,
|
||||
/* we use auth_file_path as requested */
|
||||
len = g_snprintf(NULL, 0, g_cfg->auth_file_path, pw_username);
|
||||
|
||||
*passwd_file = (char *) g_malloc(len + 1, 1);
|
||||
++len; // Allow for terminator
|
||||
*passwd_file = (char *) g_malloc(len, 1);
|
||||
if (*passwd_file != NULL)
|
||||
{
|
||||
g_sprintf(*passwd_file, g_cfg->auth_file_path, pw_username);
|
||||
g_snprintf(*passwd_file, len,
|
||||
g_cfg->auth_file_path, pw_username);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 ercp_server.c
|
||||
* @brief ercp (executive run-time control protocol) server function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
#include "sesexec.h"
|
||||
#include "session.h"
|
||||
#include "trans.h"
|
||||
|
||||
#include "ercp.h"
|
||||
#include "ercp_server.h"
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
handle_session_reconnect_event(struct trans *self)
|
||||
{
|
||||
session_reconnect(g_login_info, g_session_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
ercp_server(struct trans *self)
|
||||
{
|
||||
int rv = 0;
|
||||
enum ercp_msg_code msgno;
|
||||
|
||||
switch ((msgno = ercp_msg_in_get_msgno(self)))
|
||||
{
|
||||
case E_ERCP_SESSION_RECONNECT_EVENT:
|
||||
rv = handle_session_reconnect_event(self);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
ercp_msgno_to_str(msgno, buff, sizeof(buff));
|
||||
LOG(LOG_LEVEL_ERROR, "Ignored ERCP message %s", buff);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 ercp_server.h
|
||||
* @brief ercp (executive run-time control protocol) server function
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ERCP_SERVER_H
|
||||
#define ERCP_SERVER_H
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Processes an ERCP message
|
||||
* @param self The ERCP transport the message is coming in on
|
||||
*
|
||||
*/
|
||||
int
|
||||
ercp_server(struct trans *self);
|
||||
|
||||
#endif // ERCP_SERVER_H
|
||||
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 login_info.c
|
||||
* @brief Define functionality associated with user logins for sesexec
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "login_info.h"
|
||||
|
||||
#include "trans.h"
|
||||
|
||||
#include "sesman_auth.h"
|
||||
#include "sesman_access.h"
|
||||
#include "sesman_config.h"
|
||||
#include "login_info.h"
|
||||
#include "os_calls.h"
|
||||
#include "scp.h"
|
||||
#include "sesexec.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Logs an authentication failure message
|
||||
*
|
||||
* @param username Username
|
||||
* @param ip_addr IP address, if known
|
||||
*
|
||||
* The message is intended for use by fail2ban. Make changes with care.
|
||||
*/
|
||||
static void
|
||||
log_authfail_message(const char *username, const char *ip_addr)
|
||||
{
|
||||
if (ip_addr == NULL || ip_addr[0] == '\0')
|
||||
{
|
||||
ip_addr = "unknown";
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "AUTHFAIL: user=%s ip=%s time=%d",
|
||||
username, ip_addr, g_time1());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Authenticate and authorize the connection
|
||||
*
|
||||
* @param username Name for user
|
||||
* @param password Password
|
||||
* @param ip_addr Remote IP address
|
||||
* @param login_info Structure to fill in for a successful login
|
||||
* @return Status for the operation
|
||||
*
|
||||
* @post If E_SCP_LOGIN_OK is returned, g_login_info is filled in
|
||||
*
|
||||
*/
|
||||
static enum scp_login_status
|
||||
authenticate_and_authorize_connection(const char *supplied_username,
|
||||
const char *password,
|
||||
const char *ip_addr,
|
||||
struct login_info *login_info)
|
||||
{
|
||||
int uid;
|
||||
char *username; // From reverse-looking up the UID
|
||||
enum scp_login_status status;
|
||||
struct auth_info *auth_info;
|
||||
|
||||
if (g_getuser_info_by_name(supplied_username,
|
||||
&uid, NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
/* we can't get a UID for the user */
|
||||
LOG(LOG_LEVEL_ERROR, "Can't get UID for user %s",
|
||||
supplied_username);
|
||||
log_authfail_message(supplied_username, ip_addr);
|
||||
status = E_SCP_LOGIN_NOT_AUTHENTICATED;
|
||||
}
|
||||
else if (g_getuser_info_by_uid(uid,
|
||||
&username,
|
||||
NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't reverse lookup UID %d", uid);
|
||||
status = E_SCP_LOGIN_NOT_AUTHENTICATED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_strcmp(username, supplied_username) != 0)
|
||||
{
|
||||
/*
|
||||
* If using a federated naming service (e.g. AD), the username
|
||||
* supplied may not match that name mapped to by the UID. We
|
||||
* will generate a warning in this instance so the user can see
|
||||
* what is being used
|
||||
*/
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Using username %s for the session (from UID %d)",
|
||||
username, uid);
|
||||
}
|
||||
|
||||
auth_info = auth_userpass(username, password, ip_addr, &status);
|
||||
|
||||
/* Sanity check on result of call */
|
||||
if ((auth_info != NULL && status != E_SCP_LOGIN_OK) ||
|
||||
(auth_info == NULL && status == E_SCP_LOGIN_OK))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Bugcheck; inconsistent auth result. "
|
||||
"info = %p, status = %d", (void *)auth_info, (int)status);
|
||||
status = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
auth_end(auth_info);
|
||||
auth_info = NULL;
|
||||
}
|
||||
|
||||
/* Group access allowed? */
|
||||
if (status == E_SCP_LOGIN_OK &&
|
||||
!access_login_allowed(&g_cfg->sec, username))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Username okay but group problem for "
|
||||
"user: %s", username);
|
||||
status = E_SCP_LOGIN_NOT_AUTHORIZED;
|
||||
auth_end(auth_info);
|
||||
auth_info = NULL;
|
||||
}
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case E_SCP_LOGIN_OK:
|
||||
{
|
||||
char *dup_username = g_strdup(username);
|
||||
char *dup_ip_addr = g_strdup(ip_addr);
|
||||
|
||||
if (dup_username == NULL || dup_ip_addr == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s : Memory allocation failed",
|
||||
__func__);
|
||||
g_free(dup_username);
|
||||
g_free(dup_ip_addr);
|
||||
status = E_SCP_LOGIN_NO_MEMORY;
|
||||
auth_end(auth_info);
|
||||
auth_info = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
|
||||
username);
|
||||
login_info->uid = uid;
|
||||
login_info->username = dup_username;
|
||||
login_info->ip_addr = dup_ip_addr;
|
||||
login_info->auth_info = auth_info;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case E_SCP_LOGIN_NOT_AUTHENTICATED:
|
||||
log_authfail_message(username, ip_addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(username);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
get_scp_client_retry(struct trans *scp_trans,
|
||||
const char **username, const char **password,
|
||||
const char **ip_addr)
|
||||
{
|
||||
int got_message = 0;
|
||||
|
||||
// Wait for an SCP message
|
||||
enum scp_msg_code msgno;
|
||||
|
||||
scp_msg_in_reset(scp_trans);
|
||||
|
||||
if (scp_msg_in_wait_available(scp_trans) == 0)
|
||||
{
|
||||
msgno = scp_msg_in_get_msgno(scp_trans);
|
||||
switch (msgno)
|
||||
{
|
||||
case E_SCP_SYS_LOGIN_REQUEST:
|
||||
if (scp_get_sys_login_request(scp_trans, username,
|
||||
password, ip_addr) == 0)
|
||||
{
|
||||
got_message = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case E_SCP_CLOSE_CONNECTION_REQUEST:
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buff[64];
|
||||
scp_msgno_to_str(msgno, buff, sizeof(buff));
|
||||
LOG(LOG_LEVEL_ERROR, "unexpected message %s from SCP client",
|
||||
buff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return got_message;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct login_info *
|
||||
login_info_sys_login_user(struct trans *scp_trans,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *ip_addr)
|
||||
{
|
||||
struct login_info *result;
|
||||
enum scp_login_status status = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
int server_closed = 0;
|
||||
|
||||
if ((result = g_new0(struct login_info, 1)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Allocation failure logging in user");
|
||||
}
|
||||
else
|
||||
{
|
||||
int first_time = 1;
|
||||
unsigned int retry_count = g_cfg->sec.login_retry;
|
||||
|
||||
result->uid = (uid_t) -1;
|
||||
|
||||
while (status != E_SCP_LOGIN_OK && !server_closed)
|
||||
{
|
||||
// First time round, we have credentials supplied by the
|
||||
// caller. On subsequent trips, we have to wait for the
|
||||
// SCP client to send us more.
|
||||
if (first_time)
|
||||
{
|
||||
first_time = 0;
|
||||
}
|
||||
else if (!get_scp_client_retry(scp_trans, &username,
|
||||
&password, &ip_addr))
|
||||
{
|
||||
status = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
status = authenticate_and_authorize_connection(username,
|
||||
password,
|
||||
ip_addr,
|
||||
result);
|
||||
|
||||
if (status != E_SCP_LOGIN_OK)
|
||||
{
|
||||
if (retry_count > 0)
|
||||
{
|
||||
--retry_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
server_closed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (scp_send_login_response(scp_trans, status, server_closed) != 0)
|
||||
{
|
||||
status = E_SCP_LOGIN_GENERAL_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != E_SCP_LOGIN_OK)
|
||||
{
|
||||
login_info_free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct login_info *
|
||||
login_info_uds_login_user(struct trans *scp_trans)
|
||||
{
|
||||
struct login_info *result;
|
||||
int uid; // Needed as g_sck_get_peer_cred() doesn't use uid_t
|
||||
|
||||
// Allocate a struct for the result, with the IP address set to ""
|
||||
if ((result = g_new0(struct login_info, 1)) == NULL ||
|
||||
(result->ip_addr = g_new0(char, 1)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Allocation failure logging in user");
|
||||
}
|
||||
else if (g_sck_get_peer_cred(scp_trans->sck, NULL, &uid, NULL) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Unable to get peer credentials for SCP socket");
|
||||
}
|
||||
else if (g_getuser_info_by_uid(uid, &result->username,
|
||||
NULL, NULL, NULL, NULL) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't reverse lookup UID %d", result->uid);
|
||||
}
|
||||
else if ((result->auth_info = auth_uds(result->username, NULL)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't authorize user %s over UDS",
|
||||
result->username);
|
||||
}
|
||||
else if (!access_login_allowed(&g_cfg->sec, result->username))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Access denied for user %s by your system admin",
|
||||
result->username);
|
||||
}
|
||||
else
|
||||
{
|
||||
result->uid = (uid_t)uid;
|
||||
return result;
|
||||
}
|
||||
|
||||
login_info_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
login_info_free(struct login_info *self)
|
||||
{
|
||||
if (self != NULL)
|
||||
{
|
||||
g_free(self->username);
|
||||
g_free(self->ip_addr);
|
||||
if (self->auth_info != NULL)
|
||||
{
|
||||
auth_end(self->auth_info);
|
||||
}
|
||||
g_free(self);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 login_info.h
|
||||
* @brief Declare functionality associated with user logins for sesexec
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LOGIN_INFO_H
|
||||
#define LOGIN_INFO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct trans;
|
||||
|
||||
/**
|
||||
* Information associated with the logged-in user
|
||||
*/
|
||||
struct login_info
|
||||
{
|
||||
uid_t uid;
|
||||
char *username;
|
||||
char *ip_addr;
|
||||
struct auth_info *auth_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Attempt a system login using username/password
|
||||
* @param scp_trans SCP transport for talking to the client
|
||||
* @param username Username from xrdp
|
||||
* @param password Password from xrdp
|
||||
* @param ip_addr IP address for xrdp client
|
||||
*
|
||||
* @result Allocated login_info struct for a successful login
|
||||
*
|
||||
* This is a wrapper around the dialogue between sesexec and the SCP process
|
||||
* which is required to start a session.
|
||||
*
|
||||
* While this call is in operation, only the scp_trans transport will
|
||||
* be checked for messages. Incoming messages on other transports will be
|
||||
* ignored. The dialog can also be terminated by a SIGTERM if the SCP
|
||||
* transport is configured to allow this.
|
||||
*
|
||||
* The username in the returned structure may differ from the passed-in
|
||||
* username if multiple names map to the same UID. This can happen with
|
||||
* federated naming services (e.g. AD, LDAP)
|
||||
*/
|
||||
struct login_info *
|
||||
login_info_sys_login_user(struct trans *scp_trans,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *ip_addr);
|
||||
|
||||
/**
|
||||
* @brief Create a login_info structure using UDS credentials
|
||||
*
|
||||
* This should be a formality, as by the time sesexec tries this, sesman
|
||||
* should already have done it.
|
||||
*
|
||||
* Errors are logged.
|
||||
*
|
||||
* @param scp_trans SCP transport for talking to the client
|
||||
* @param ip_addr IP address for xrdp client
|
||||
*
|
||||
* @result Allocated login_info struct for a successful login
|
||||
*/
|
||||
struct login_info *
|
||||
login_info_uds_login_user(struct trans *scp_trans);
|
||||
|
||||
/**
|
||||
* Free a struct login_info
|
||||
*/
|
||||
void
|
||||
login_info_free(struct login_info *self);
|
||||
|
||||
#endif // LOGIN_INFO_H
|
||||
@@ -0,0 +1,521 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Matt Burt 2023
|
||||
*
|
||||
* 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 sesexec.c
|
||||
* @brief Main program file for session executive process
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "eicp.h"
|
||||
#include "eicp_server.h"
|
||||
#include "ercp.h"
|
||||
#include "ercp_server.h"
|
||||
#include "login_info.h"
|
||||
#include "sesexec.h"
|
||||
#include "sesman_config.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "session.h"
|
||||
#include "string_calls.h"
|
||||
#include "trans.h"
|
||||
#include "xrdp_sockets.h"
|
||||
|
||||
struct startup_params
|
||||
{
|
||||
const char *sesman_ini;
|
||||
};
|
||||
|
||||
/*
|
||||
* Program-scope globals
|
||||
*/
|
||||
struct config_sesman *g_cfg;
|
||||
unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 };
|
||||
struct login_info *g_login_info;
|
||||
struct session_data *g_session_data;
|
||||
|
||||
tintptr g_term_event = 0;
|
||||
tintptr g_sigchld_event = 0;
|
||||
pid_t g_pid;
|
||||
|
||||
/*
|
||||
* Module-scope globals
|
||||
*/
|
||||
static struct trans *g_ecp_trans;
|
||||
static int g_terminate_loop = 0;
|
||||
static int g_terminate_status = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Command line argument parser
|
||||
* @param[in] argc number of command line arguments
|
||||
* @param[in] argv pointer array of commandline arguments
|
||||
* @param[out] startup_params Returned startup parameters
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int
|
||||
process_params(int argc, char **argv,
|
||||
struct startup_params *startup_params)
|
||||
{
|
||||
int index;
|
||||
const char *option;
|
||||
const char *value;
|
||||
|
||||
startup_params->sesman_ini = DEFAULT_SESMAN_INI;
|
||||
|
||||
index = 1;
|
||||
|
||||
while (index < argc)
|
||||
{
|
||||
option = argv[index];
|
||||
|
||||
if (index + 1 < argc)
|
||||
{
|
||||
value = argv[index + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (g_strcmp(option, "-c") == 0)
|
||||
{
|
||||
index++;
|
||||
startup_params->sesman_ini = value;
|
||||
}
|
||||
else /* unknown option */
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#if 0
|
||||
static int
|
||||
sesexec_scp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
|
||||
rv = scp_msg_in_check_available(self, &available);
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
struct sesman_con *sc = (struct sesman_con *)self->callback_data;
|
||||
//if ((rv = scp_process(sc)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s: scp_process failed", __func__);
|
||||
}
|
||||
scp_msg_in_reset(self);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
sesexec_eicp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
|
||||
rv = eicp_msg_in_check_available(self, &available);
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
if ((rv = eicp_server(self)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s: eicp_server failed", __func__);
|
||||
}
|
||||
eicp_msg_in_reset(self);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesexec_ercp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
|
||||
rv = ercp_msg_in_check_available(self, &available);
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
if ((rv = ercp_server(self)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s: ercp_server failed", __func__);
|
||||
}
|
||||
ercp_msg_in_reset(self);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Informs the main loop a termination signal has been received
|
||||
*/
|
||||
static void
|
||||
set_term_event(int sig)
|
||||
{
|
||||
/* Don't try to use a wait obj in a child process */
|
||||
if (g_getpid() == g_pid)
|
||||
{
|
||||
g_set_wait_obj(g_term_event);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* No-op signal handler.
|
||||
*/
|
||||
static void
|
||||
sig_no_op(int sig)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Informs the main loop a child exiting signal has been received
|
||||
*/
|
||||
static void
|
||||
set_sigchld_event(int sig)
|
||||
{
|
||||
/* Don't try to use a wait obj in a child process */
|
||||
if (g_getpid() == g_pid)
|
||||
{
|
||||
g_set_wait_obj(g_sigchld_event);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesexec_is_term(void)
|
||||
{
|
||||
return g_terminate_loop || g_is_wait_obj_set(g_term_event);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
sesexec_terminate_main_loop(int status)
|
||||
{
|
||||
g_terminate_loop = 1;
|
||||
g_terminate_status = status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void
|
||||
process_sigchld_event(void)
|
||||
{
|
||||
struct exit_status e;
|
||||
int pid;
|
||||
|
||||
// Check for any finished children
|
||||
while ((pid = g_waitchild(&e)) > 0)
|
||||
{
|
||||
session_process_child_exit(g_session_data, pid, &e);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* @brief Starts sesexec main loop
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sesexec_main_loop(void)
|
||||
{
|
||||
int error = 0;
|
||||
int robjs_count;
|
||||
intptr_t robjs[32];
|
||||
|
||||
g_terminate_loop = 0;
|
||||
g_terminate_status = 0;
|
||||
g_login_info = NULL;
|
||||
|
||||
while (!g_terminate_loop)
|
||||
{
|
||||
robjs_count = 0;
|
||||
robjs[robjs_count++] = g_term_event;
|
||||
robjs[robjs_count++] = g_sigchld_event;
|
||||
|
||||
error = trans_get_wait_objs(g_ecp_trans, robjs, &robjs_count);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: "
|
||||
"trans_get_wait_objs(ECP) failed");
|
||||
sesexec_terminate_main_loop(error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_obj_wait(robjs, robjs_count, NULL, 0, 0) != 0)
|
||||
{
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_WARNING, "sesexec_main_loop: "
|
||||
"Unexpected error from g_obj_wait()");
|
||||
g_sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_is_wait_obj_set(g_term_event)) /* term */
|
||||
{
|
||||
g_reset_wait_obj(g_term_event);
|
||||
if (session_active(g_session_data))
|
||||
{
|
||||
// Ask the active session to terminate
|
||||
LOG(LOG_LEVEL_INFO, "sesexec_main_loop: "
|
||||
"sesexec asked to terminate. "
|
||||
"Terminating active session");
|
||||
session_send_term(g_session_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Terminate immediately
|
||||
LOG(LOG_LEVEL_INFO, "sesexec_main_loop: "
|
||||
"sesexec asked to terminate. "
|
||||
"No session is active");
|
||||
sesexec_terminate_main_loop(0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_is_wait_obj_set(g_sigchld_event)) /* SIGCHLD */
|
||||
{
|
||||
g_reset_wait_obj(g_sigchld_event);
|
||||
|
||||
// See whether the session goes from active to inactive
|
||||
// after processing SIGCHLD
|
||||
int session_was_active = session_active(g_session_data);
|
||||
process_sigchld_event();
|
||||
if (session_was_active && !session_active(g_session_data))
|
||||
{
|
||||
// We've finished the session. Tell sesman and
|
||||
// finish up.
|
||||
(void)ercp_send_session_finished_event(g_ecp_trans);
|
||||
|
||||
session_data_free(g_session_data);
|
||||
g_session_data = NULL;
|
||||
sesexec_terminate_main_loop(0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
error = trans_check_wait_objs(g_ecp_trans);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesexec_main_loop: "
|
||||
"trans_check_wait_objs failed for ECP transport");
|
||||
sesexec_terminate_main_loop(error);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
login_info_free(g_login_info);
|
||||
|
||||
return g_terminate_status;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int start_logging(const char *sesman_ini)
|
||||
{
|
||||
char text[256];
|
||||
int rv = 1;
|
||||
if (!g_file_exist(sesman_ini))
|
||||
{
|
||||
g_printf("Config file %s does not exist\n", sesman_ini);
|
||||
}
|
||||
else
|
||||
{
|
||||
enum logReturns log_error;
|
||||
log_error = log_start(sesman_ini, "xrdp-sesexec", 0);
|
||||
|
||||
if (log_error != LOG_STARTUP_OK)
|
||||
{
|
||||
switch (log_error)
|
||||
{
|
||||
case LOG_ERROR_MALLOC:
|
||||
g_writeln("error on malloc. cannot start logging. quitting.");
|
||||
break;
|
||||
case LOG_ERROR_FILE_OPEN:
|
||||
g_writeln("error opening log file [%s]. quitting.",
|
||||
getLogFile(text, sizeof(text) - 1));
|
||||
break;
|
||||
default:
|
||||
// Assume sufficient messages have already been generated
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
get_eicp_fd(char errstr[], unsigned int errstr_size)
|
||||
{
|
||||
const char *s = g_getenv("EICP_FD");
|
||||
const char *p;
|
||||
int fd;
|
||||
|
||||
errstr[0] = '\0';
|
||||
|
||||
if (s == NULL || s[0] == '\0')
|
||||
{
|
||||
g_snprintf(errstr, errstr_size,
|
||||
"Can't read EICP_FD environment variable");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (p = s ; isdigit(*p) ; ++p)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
if (*p != '\0')
|
||||
{
|
||||
g_snprintf(errstr, errstr_size, "EICP_FD has non-digit char '%c'", *p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((p - s) > 4)
|
||||
{
|
||||
g_snprintf(errstr, errstr_size, "EICP_FD has too many digits");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = g_atoi(s);
|
||||
if (!g_file_is_open(fd))
|
||||
{
|
||||
g_snprintf(errstr, errstr_size, "EICP_FD %d is not open", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int error = 1;
|
||||
struct startup_params startup_params = {0};
|
||||
int errored_argc;
|
||||
int eicp_fd;
|
||||
char eicp_errstr[128];
|
||||
/*
|
||||
* Check the EICP transport file descriptor is provided and open
|
||||
* before opening any log files, config files, etc. We then open
|
||||
* log files, and log errors at that point */
|
||||
eicp_fd = get_eicp_fd(eicp_errstr, sizeof(eicp_errstr));
|
||||
|
||||
g_init("xrdp-sesexec");
|
||||
|
||||
//g_sleep(15 * 1000);
|
||||
errored_argc = process_params(argc, argv, &startup_params);
|
||||
if (errored_argc > 0)
|
||||
{
|
||||
g_writeln("Unknown option: %s", argv[errored_argc]);
|
||||
}
|
||||
/* starting logging subsystem
|
||||
*
|
||||
* For historic reasons, we share a log file with sesman */
|
||||
else if (start_logging(startup_params.sesman_ini) == 0)
|
||||
{
|
||||
/* reading config
|
||||
*
|
||||
* For historic reasons, we share a config with sesman */
|
||||
if ((g_cfg = config_read(startup_params.sesman_ini)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS, "error reading config %s: %s",
|
||||
startup_params.sesman_ini, g_get_strerror());
|
||||
}
|
||||
else if (eicp_fd < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "%s", eicp_errstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char text[128];
|
||||
|
||||
g_pid = g_getpid();
|
||||
|
||||
/* signal handling */
|
||||
g_snprintf(text, sizeof(text), "xrdp_sesexec_%8.8x_main_term",
|
||||
g_pid);
|
||||
g_term_event = g_create_wait_obj(text);
|
||||
g_snprintf(text, sizeof(text), "xrdp_sesexec_%8.8x_sigchld",
|
||||
g_pid);
|
||||
g_sigchld_event = g_create_wait_obj(text);
|
||||
|
||||
// No need to terminate on SIGINT for sesexec. This can
|
||||
// also make it hard to debug sessions.
|
||||
//g_signal_user_interrupt(set_term_event);
|
||||
g_signal_terminate(set_term_event); /* SIGTERM */
|
||||
g_signal_pipe(sig_no_op); /* SIGPIPE */
|
||||
g_signal_child_stop(set_sigchld_event);
|
||||
|
||||
/* Set up an EICP process handler
|
||||
* Errors are logged by this call if necessary */
|
||||
g_ecp_trans = eicp_init_trans_from_fd(eicp_fd,
|
||||
TRANS_TYPE_SERVER,
|
||||
sesexec_is_term);
|
||||
if (g_ecp_trans != NULL)
|
||||
{
|
||||
g_ecp_trans->trans_data_in = sesexec_eicp_data_in;
|
||||
g_ecp_trans->callback_data = NULL;
|
||||
|
||||
/* start program main loop */
|
||||
LOG(LOG_LEVEL_INFO, "starting xrdp-sesexec with pid %d", g_pid);
|
||||
error = sesexec_main_loop();
|
||||
trans_delete(g_ecp_trans);
|
||||
}
|
||||
|
||||
g_delete_wait_obj(g_term_event);
|
||||
}
|
||||
config_free(g_cfg);
|
||||
log_end();
|
||||
}
|
||||
|
||||
g_deinit();
|
||||
g_exit(error);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* 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 sesexec.h
|
||||
* @brief Main include file
|
||||
* @author Jay Sorg
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SESEXEC_H
|
||||
#define SESEXEC_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct config_sesman;
|
||||
struct trans;
|
||||
struct login_info;
|
||||
struct session_data;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#define USE_BSD_SETLOGIN
|
||||
#endif
|
||||
|
||||
/* Globals */
|
||||
extern struct config_sesman *g_cfg;
|
||||
extern unsigned char g_fixedkey[8];
|
||||
extern struct login_info *g_login_info;
|
||||
extern struct session_data *g_session_data;
|
||||
|
||||
extern tintptr g_term_event;
|
||||
extern tintptr g_sigchld_event;
|
||||
extern pid_t g_pid;
|
||||
|
||||
|
||||
/**
|
||||
* Callback to process incoming ERCP data
|
||||
*/
|
||||
int
|
||||
sesexec_ercp_data_in(struct trans *self);
|
||||
|
||||
/*
|
||||
* Check for termination
|
||||
*/
|
||||
int
|
||||
sesexec_is_term(void);
|
||||
|
||||
/*
|
||||
* Terminate the sesexec main loop
|
||||
*/
|
||||
void
|
||||
sesexec_terminate_main_loop(int status);
|
||||
|
||||
#endif // SESEXEC_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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.h
|
||||
* @brief Session management definitions
|
||||
* @author Jay Sorg, Simone Fedele
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "guid.h"
|
||||
#include "scp_application_types.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
struct login_info;
|
||||
struct exit_status;
|
||||
|
||||
/**
|
||||
* Information used to start a session
|
||||
*/
|
||||
struct session_parameters
|
||||
{
|
||||
unsigned int display;
|
||||
enum scp_session_type type;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned char bpp;
|
||||
struct guid guid;
|
||||
const char *shell; // Must not be NULL
|
||||
const char *directory; // Must not be NULL
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data involved in running a session (opaque type)
|
||||
*
|
||||
* Allocate with session_start() and free with
|
||||
* session_data_free() once session_active() returns zero.
|
||||
*/
|
||||
struct session_data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief starts a session
|
||||
*
|
||||
* @param login_info info for logged in user
|
||||
* @param s Session parameters
|
||||
* @param[out] session_data Pointer to session data for the session
|
||||
*
|
||||
* session_data is only set if E_SCP_CREATE_OK is returned
|
||||
* @return status
|
||||
*/
|
||||
enum scp_screate_status
|
||||
session_start(struct login_info *login_info,
|
||||
const struct session_parameters *s,
|
||||
struct session_data **session_data);
|
||||
|
||||
/**
|
||||
* Processes an exited child process
|
||||
*
|
||||
* The PID of the child process is removed from the session_data.
|
||||
*
|
||||
* @param sd session_data for this session
|
||||
* @param pid PID of exited process
|
||||
* @param e Exit status of the exited process
|
||||
*/
|
||||
void
|
||||
session_process_child_exit(struct session_data *sd,
|
||||
int pid,
|
||||
const struct exit_status *e);
|
||||
|
||||
/**
|
||||
* Returns a count of active processes in the session
|
||||
*
|
||||
* @param sd session_data for this session
|
||||
*/
|
||||
unsigned int
|
||||
session_active(const struct session_data *sd);
|
||||
|
||||
/**
|
||||
* Returns the start time for an active session
|
||||
*
|
||||
* @param sd session_data for this session
|
||||
*/
|
||||
time_t
|
||||
session_get_start_time(const struct session_data *sd);
|
||||
|
||||
/***
|
||||
* Ask a session to terminate by signalling the window manager
|
||||
*
|
||||
* @param sd session_data for this session
|
||||
*/
|
||||
void
|
||||
session_send_term(struct session_data *sd);
|
||||
|
||||
/**
|
||||
* Frees a session_data object
|
||||
*
|
||||
* @param sd session_data for this session
|
||||
*
|
||||
* Do not call this until session_active() returns zero, or you
|
||||
* lose the ability to track the session PIDs
|
||||
*/
|
||||
void
|
||||
session_data_free(struct session_data *session_data);
|
||||
|
||||
/**
|
||||
* Runs the reconnect script for the session
|
||||
*/
|
||||
void
|
||||
session_reconnect(struct login_info *login_info,
|
||||
struct session_data *sd);
|
||||
|
||||
#endif // SESSION_H
|
||||
@@ -103,8 +103,7 @@ wait_for_xserver(uid_t uid,
|
||||
pid_t pid = g_fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create pipe : %s",
|
||||
g_get_strerror());
|
||||
// Error already logged
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) 2023 Matt Burt
|
||||
*
|
||||
* 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 sesexec_control.c
|
||||
* @brief Start/stop session executive process
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include "sesman_config.h"
|
||||
#include "eicp.h"
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "pre_session_list.h"
|
||||
#include "string_calls.h"
|
||||
#include "sesexec_control.h"
|
||||
#include "sesman.h"
|
||||
#include "trans.h"
|
||||
#include "xrdp_sockets.h"
|
||||
|
||||
#define SESEXEC_SHORTNAME "xrdp-sesexec"
|
||||
#define SESEXEC_LONGNAME XRDP_LIBEXEC_PATH "/" SESEXEC_SHORTNAME
|
||||
|
||||
// Some platforms using setsid() benefit from sesexec being
|
||||
// forked again, so the UNIX session can be created cleanly
|
||||
// See FreeBSD bug
|
||||
// ports/157282: effective login name is not set by xrdp-sesman
|
||||
// https://www.freebsd.org/cgi/query-pr.cgi?pr=157282
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#define USE_BSD_SETLOGIN 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Adds entries to the args list for running sesexec
|
||||
*
|
||||
* @param args Argument list
|
||||
* @return 0 for memory allocation failure, 1 for success
|
||||
*/
|
||||
static int
|
||||
create_exec_args_add_entries(struct list *args)
|
||||
{
|
||||
if (!list_add_strdup(args, SESEXEC_SHORTNAME))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (g_strcmp(g_cfg->sesman_ini, DEFAULT_SESMAN_INI) != 0)
|
||||
{
|
||||
if (!list_add_strdup_multi(args, "-c", g_cfg->sesman_ini, NULL))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Create an args list for sesexec
|
||||
* @return NULL if memory could not be allocated
|
||||
*
|
||||
* The result must be freed with list_delete() after use
|
||||
*/
|
||||
static struct list *
|
||||
create_exec_args(void)
|
||||
{
|
||||
struct list *result = list_create();
|
||||
if (result != NULL)
|
||||
{
|
||||
result->auto_free = 1;
|
||||
if (!create_exec_args_add_entries(result))
|
||||
{
|
||||
list_delete(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
sesexec_start(struct pre_session_item *psi)
|
||||
{
|
||||
// Local socket pair used to set up the EICP channel for sesexec
|
||||
// We also use the socket pair to communicate the PID of sesexec back
|
||||
// to sesman. Technically we only need this if USE_BSD_SETLOGIN
|
||||
// is set, but removing this variable complicates the code so
|
||||
// much it isn't worth it.
|
||||
int sck[2] = {-1, -1};
|
||||
int rv = -1;
|
||||
int size;
|
||||
const char *exe = SESEXEC_LONGNAME;
|
||||
struct list *args = NULL;
|
||||
|
||||
if (!g_executable_exist(exe))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't execute %s", exe);
|
||||
}
|
||||
else if ((args = create_exec_args()) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Out of memory running sesexec");
|
||||
}
|
||||
else if (g_sck_local_socketpair(sck) < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create sesexec EICP socket [%s]",
|
||||
g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
int pid = g_fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
// Error already logged
|
||||
g_file_close(sck[0]);
|
||||
g_file_close(sck[1]);
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Sesexec process */
|
||||
g_file_close(sck[0]);
|
||||
|
||||
#if USE_BSD_SETLOGIN
|
||||
if (g_fork() != 0)
|
||||
{
|
||||
g_exit(0);
|
||||
}
|
||||
#endif
|
||||
// Send our pid back to sesman
|
||||
pid = g_getpid();
|
||||
size = g_file_write(sck[1], (const char *)&pid, sizeof(pid));
|
||||
|
||||
if (size != sizeof(pid))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't write to PID socket [%s]",
|
||||
g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Put the number of the file descriptor in EICP_FD
|
||||
* in the environment */
|
||||
char buff[64];
|
||||
g_snprintf(buff, sizeof(buff), "%d", sck[1]);
|
||||
g_setenv("EICP_FD", buff, 1);
|
||||
|
||||
/* [Development] Log all file descriptors not marked cloexec
|
||||
* other than stdin, stdout, stderr, and the EICP fd in sck[1].
|
||||
*/
|
||||
if (sck[1] < 3)
|
||||
{
|
||||
// EICP fd has overwritten one of the standard descriptors
|
||||
LOG_DEVEL_LEAKING_FDS("xrdp-sesexec", 3, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEVEL_LEAKING_FDS("xrdp-sesexec", 3, sck[1]);
|
||||
LOG_DEVEL_LEAKING_FDS("xrdp-sesexec", sck[1] + 1, -1);
|
||||
}
|
||||
|
||||
g_execvp_list(exe, args);
|
||||
|
||||
// Shouldn't get here. Errors are logged if we do.
|
||||
}
|
||||
g_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_file_close(sck[1]);
|
||||
|
||||
// Get the PID from the child (or the grancdchild)
|
||||
int size = g_file_read(sck[0], (char *)&pid, sizeof(pid));
|
||||
|
||||
if (size != sizeof(pid))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't read PID of sesexec process [%s]",
|
||||
g_get_strerror());
|
||||
g_file_close(sck[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct trans *t = eicp_init_trans_from_fd(sck[0],
|
||||
TRANS_TYPE_CLIENT,
|
||||
sesman_is_term);
|
||||
if (t == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Can't create sesexec transport [%s]",
|
||||
g_get_strerror());
|
||||
g_file_close(sck[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
t->trans_data_in = sesman_eicp_data_in;
|
||||
t->callback_data = (void *)psi;
|
||||
psi->sesexec_trans = t;
|
||||
psi->sesexec_pid = pid;
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(args);
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) 2023 Matt Burt
|
||||
*
|
||||
* 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 sesexec_control.h
|
||||
* @brief Start/stop session executive process
|
||||
* @author Matt Burt
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SESEXEC_H
|
||||
#define SESEXEC_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct trans;
|
||||
struct pre_session_item;
|
||||
|
||||
/**
|
||||
* Start a session executive
|
||||
* @param psi Pre-session item to allocate EICP transport to
|
||||
* @result 0 for success
|
||||
*
|
||||
* If non-zero is returned, all errors have been logged.
|
||||
* If zero is returned, the sesexec_trans and sesexec_pid fields of
|
||||
* the pre-session-item have been initialised.
|
||||
*/
|
||||
|
||||
int
|
||||
sesexec_start(struct pre_session_item *psi);
|
||||
|
||||
#endif // SESEXEC_H
|
||||
+156
-180
@@ -35,22 +35,26 @@
|
||||
|
||||
#include "sesman_auth.h"
|
||||
#include "sesman_config.h"
|
||||
#include "eicp.h"
|
||||
#include "eicp_process.h"
|
||||
#include "ercp.h"
|
||||
#include "ercp_process.h"
|
||||
#include "pre_session_list.h"
|
||||
#include "session_list.h"
|
||||
#include "lock_uds.h"
|
||||
#include "os_calls.h"
|
||||
#include "scp.h"
|
||||
#include "scp_process.h"
|
||||
#include "sesexec_control.h"
|
||||
#include "sig.h"
|
||||
#include "string_calls.h"
|
||||
#include "trans.h"
|
||||
#include "xrdp_configure_options.h"
|
||||
|
||||
/**
|
||||
* Maximum number of short-lived connections to sesman
|
||||
*
|
||||
* At the moment, all connections to sesman are short-lived. This may change
|
||||
* in the future
|
||||
* Maximum number of pre-session items
|
||||
*/
|
||||
#define MAX_SHORT_LIVED_CONNECTIONS 16
|
||||
#define MAX_PRE_SESSION_ITEMS 16
|
||||
|
||||
/**
|
||||
* Define the mode of operation of the program
|
||||
@@ -73,7 +77,6 @@ struct sesman_startup_params
|
||||
};
|
||||
|
||||
struct config_sesman *g_cfg;
|
||||
unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 };
|
||||
static tintptr g_term_event = 0;
|
||||
static tintptr g_sigchld_event = 0;
|
||||
static tintptr g_reload_event = 0;
|
||||
@@ -113,68 +116,6 @@ static int nocase_matches(const char *candidate, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a sesman_con struct
|
||||
*
|
||||
* @param trans Pointer to newly-allocated transport
|
||||
* @return struct sesman_con pointer
|
||||
*/
|
||||
static struct sesman_con *
|
||||
alloc_connection(struct trans *t)
|
||||
{
|
||||
struct sesman_con *result;
|
||||
|
||||
if ((result = g_new0(struct sesman_con, 1)) != NULL)
|
||||
{
|
||||
g_snprintf(result->peername, sizeof(result->peername), "%s", "unknown");
|
||||
result->t = t;
|
||||
result->auth_retry_count = g_cfg->sec.login_retry;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a sesman_con struct, freeing resources
|
||||
*
|
||||
* After this call, the passed-in pointer is invalid and must not be
|
||||
* referenced.
|
||||
*
|
||||
* Any auth_info struct found in the sesman_con is also deallocated.
|
||||
*
|
||||
* @param sc struct to de-allocate
|
||||
*/
|
||||
static void
|
||||
delete_connection(struct sesman_con *sc)
|
||||
{
|
||||
if (sc != NULL)
|
||||
{
|
||||
trans_delete(sc->t);
|
||||
if (sc->auth_info != NULL)
|
||||
{
|
||||
auth_end(sc->auth_info);
|
||||
}
|
||||
g_free(sc->username);
|
||||
g_free(sc->ip_addr);
|
||||
g_free(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
sesman_set_connection_peername(struct sesman_con *sc, const char *name)
|
||||
{
|
||||
int rv = 1;
|
||||
|
||||
if (sc != NULL && name != NULL)
|
||||
{
|
||||
g_snprintf(sc->peername, sizeof(sc->peername), "%s", name);
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
*
|
||||
@@ -300,40 +241,25 @@ static int sesman_listen_test(struct config_sesman *cfg)
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesman_close_all(unsigned int flags)
|
||||
sesman_close_all(void)
|
||||
{
|
||||
int index;
|
||||
struct sesman_con *sc;
|
||||
|
||||
LOG_DEVEL(LOG_LEVEL_TRACE, "sesman_close_all:");
|
||||
|
||||
pre_session_list_cleanup();
|
||||
session_list_cleanup();
|
||||
|
||||
g_delete_wait_obj(g_reload_event);
|
||||
g_delete_wait_obj(g_sigchld_event);
|
||||
g_delete_wait_obj(g_term_event);
|
||||
|
||||
sesman_delete_listening_transport();
|
||||
for (index = 0; index < g_con_list->count; index++)
|
||||
{
|
||||
sc = (struct sesman_con *) list_get_item(g_con_list, index);
|
||||
if (sc != NULL && (flags & SCA_CLOSE_AUTH_INFO) == 0)
|
||||
{
|
||||
// Prevent delete_connection() closing the auth_info down
|
||||
sc->auth_info = NULL;
|
||||
}
|
||||
delete_connection(sc);
|
||||
}
|
||||
|
||||
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)
|
||||
int
|
||||
sesman_scp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
@@ -342,8 +268,10 @@ sesman_data_in(struct trans *self)
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
struct sesman_con *sc = (struct sesman_con *)self->callback_data;
|
||||
if ((rv = scp_process(sc)) != 0)
|
||||
struct pre_session_item *psi;
|
||||
psi = (struct pre_session_item *)self->callback_data;
|
||||
|
||||
if ((rv = scp_process(psi)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_data_in: scp_process_msg failed");
|
||||
}
|
||||
@@ -357,30 +285,79 @@ sesman_data_in(struct trans *self)
|
||||
static int
|
||||
sesman_listen_conn_in(struct trans *self, struct trans *new_self)
|
||||
{
|
||||
struct sesman_con *sc;
|
||||
if (g_con_list->count >= MAX_SHORT_LIVED_CONNECTIONS)
|
||||
struct pre_session_item *psi;
|
||||
if (pre_session_list_get_count() >= MAX_PRE_SESSION_ITEMS)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_data_in: error, too many "
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_listen_conn_in: error, too many "
|
||||
"connections, rejecting");
|
||||
trans_delete(new_self);
|
||||
}
|
||||
else if ((sc = alloc_connection(new_self)) == NULL ||
|
||||
scp_init_trans(new_self) != 0)
|
||||
else if ((psi = pre_session_list_new()) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_data_in: No memory to allocate "
|
||||
"new connection");
|
||||
delete_connection(sc);
|
||||
trans_delete(new_self);
|
||||
}
|
||||
else if (scp_init_trans(new_self) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_data_in: Can't init SCP connection");
|
||||
trans_delete(new_self);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_self->callback_data = (void *)sc;
|
||||
new_self->trans_data_in = sesman_data_in;
|
||||
list_add_item(g_con_list, (intptr_t) sc);
|
||||
new_self->callback_data = (void *)psi;
|
||||
new_self->trans_data_in = sesman_scp_data_in;
|
||||
psi->client_trans = new_self;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesman_eicp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
|
||||
rv = eicp_msg_in_check_available(self, &available);
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
struct pre_session_item *psi;
|
||||
psi = (struct pre_session_item *)self->callback_data;
|
||||
if ((rv = eicp_process(psi)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_eicp_data_in: eicp_process_msg failed");
|
||||
}
|
||||
eicp_msg_in_reset(self);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesman_ercp_data_in(struct trans *self)
|
||||
{
|
||||
int rv;
|
||||
int available;
|
||||
|
||||
rv = ercp_msg_in_check_available(self, &available);
|
||||
|
||||
if (rv == 0 && available)
|
||||
{
|
||||
struct session_item *si = (struct session_item *)self->callback_data;
|
||||
if ((rv = ercp_process(si)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_ercp_data_in: ercp_process_msg failed");
|
||||
}
|
||||
ercp_msg_in_reset(self);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Informs the main loop a termination signal has been received
|
||||
@@ -395,9 +372,21 @@ set_term_event(int sig)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* No-op signal handler.
|
||||
*/
|
||||
static void
|
||||
sig_no_op(int sig)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Informs the main loop a SIGCHLD has been received
|
||||
* Catch a SIGCHLD and ignore the main loop
|
||||
*
|
||||
* In theory we could use waitpid() in the signal handler, but that
|
||||
* would prevent us adding any logging
|
||||
*/
|
||||
static void
|
||||
set_sigchld_event(int sig)
|
||||
@@ -437,7 +426,7 @@ sesman_delete_listening_transport(void)
|
||||
}
|
||||
g_list_trans = NULL;
|
||||
|
||||
unlock_uds(g_list_trans_lock);
|
||||
unlock_uds(g_list_trans_lock); // Won't unlock anything for a child process
|
||||
g_list_trans_lock = NULL;
|
||||
}
|
||||
|
||||
@@ -488,6 +477,13 @@ sesman_create_listening_transport(const struct config_sesman *cfg)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
sesman_is_term(void)
|
||||
{
|
||||
return g_is_wait_obj_set(g_term_event);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
*
|
||||
@@ -499,12 +495,7 @@ sesman_main_loop(void)
|
||||
{
|
||||
int error;
|
||||
int robjs_count;
|
||||
int wobjs_count;
|
||||
int timeout;
|
||||
int index;
|
||||
intptr_t robjs[32];
|
||||
intptr_t wobjs[32];
|
||||
struct sesman_con *scon;
|
||||
intptr_t robjs[1024];
|
||||
|
||||
g_con_list = list_create();
|
||||
if (g_con_list == NULL)
|
||||
@@ -524,47 +515,41 @@ sesman_main_loop(void)
|
||||
error = 0;
|
||||
while (!error)
|
||||
{
|
||||
timeout = -1;
|
||||
robjs_count = 0;
|
||||
robjs[robjs_count++] = g_term_event;
|
||||
robjs[robjs_count++] = g_sigchld_event;
|
||||
robjs[robjs_count++] = g_reload_event;
|
||||
wobjs_count = 0;
|
||||
for (index = 0; index < g_con_list->count; index++)
|
||||
{
|
||||
scon = (struct sesman_con *)list_get_item(g_con_list, index);
|
||||
if (scon != NULL)
|
||||
{
|
||||
error = trans_get_wait_objs_rw(scon->t,
|
||||
robjs, &robjs_count,
|
||||
wobjs, &wobjs_count, &timeout);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"trans_get_wait_objs_rw failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_list_trans != NULL)
|
||||
{
|
||||
/* g_list_trans might be NULL on a reconfigure if sesman
|
||||
* is unable to listen again */
|
||||
error = trans_get_wait_objs_rw(g_list_trans, robjs, &robjs_count,
|
||||
wobjs, &wobjs_count, &timeout);
|
||||
error = trans_get_wait_objs(g_list_trans, robjs, &robjs_count);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"trans_get_wait_objs_rw failed");
|
||||
"trans_get_wait_objs failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout) != 0)
|
||||
error = pre_session_list_get_wait_objs(robjs, &robjs_count);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"pre_session_list_get_wait_objs failed");
|
||||
break;
|
||||
}
|
||||
|
||||
error = session_list_get_wait_objs(robjs, &robjs_count);
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"session_list_get_wait_objs failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_obj_wait(robjs, robjs_count, NULL, 0, -1) != 0)
|
||||
{
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_WARNING, "sesman_main_loop: "
|
||||
@@ -579,10 +564,14 @@ sesman_main_loop(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_is_wait_obj_set(g_sigchld_event)) /* A child has exited */
|
||||
if (g_is_wait_obj_set(g_sigchld_event)) /* term */
|
||||
{
|
||||
g_reset_wait_obj(g_sigchld_event);
|
||||
sig_sesman_session_end();
|
||||
// Prevent any zombies from hanging around
|
||||
while (g_waitchild(NULL) > 0)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_is_wait_obj_set(g_reload_event)) /* We're asked to reload */
|
||||
@@ -591,33 +580,6 @@ sesman_main_loop(void)
|
||||
sig_sesman_reload_cfg();
|
||||
}
|
||||
|
||||
index = 0;
|
||||
while (index < g_con_list->count)
|
||||
{
|
||||
int remove_con = 0;
|
||||
scon = (struct sesman_con *)list_get_item(g_con_list, index);
|
||||
if (trans_check_wait_objs(scon->t) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"trans_check_wait_objs failed, removing trans");
|
||||
remove_con = 1;
|
||||
}
|
||||
else if (scon->close_requested)
|
||||
{
|
||||
remove_con = 1;
|
||||
}
|
||||
|
||||
if (remove_con)
|
||||
{
|
||||
delete_connection(scon);
|
||||
list_remove_item(g_con_list, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_list_trans != NULL)
|
||||
{
|
||||
error = trans_check_wait_objs(g_list_trans);
|
||||
@@ -628,11 +590,25 @@ sesman_main_loop(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error = pre_session_list_check_wait_objs();
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"pre_session_list_check_wait_objs failed");
|
||||
break;
|
||||
}
|
||||
|
||||
sesman_close_all(SCA_CLOSE_AUTH_INFO);
|
||||
list_delete(g_con_list);
|
||||
return 0;
|
||||
error = session_list_check_wait_objs();
|
||||
if (error != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
|
||||
"session_list_check_wait_objs failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -641,7 +617,7 @@ print_version(void)
|
||||
{
|
||||
g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
|
||||
g_writeln(" The xrdp session manager");
|
||||
g_writeln(" Copyright (C) 2004-2020 Jay Sorg, "
|
||||
g_writeln(" Copyright (C) 2004-2023 Jay Sorg, "
|
||||
"Neutrino Labs, and all contributors.");
|
||||
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
|
||||
g_writeln("%s", "");
|
||||
@@ -714,16 +690,14 @@ main(int argc, char **argv)
|
||||
enum logReturns log_error;
|
||||
char text[256];
|
||||
char pid_file[256];
|
||||
char default_sesman_ini[256];
|
||||
struct sesman_startup_params startup_params = {0};
|
||||
int errored_argc;
|
||||
int daemon;
|
||||
|
||||
g_init("xrdp-sesman");
|
||||
g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH);
|
||||
g_snprintf(default_sesman_ini, 255, "%s/sesman.ini", XRDP_CFG_PATH);
|
||||
|
||||
startup_params.sesman_ini = default_sesman_ini;
|
||||
startup_params.sesman_ini = DEFAULT_SESMAN_INI;
|
||||
|
||||
errored_argc = sesman_process_params(argc, argv, &startup_params);
|
||||
if (errored_argc > 0)
|
||||
@@ -921,10 +895,11 @@ main(int argc, char **argv)
|
||||
g_snprintf(text, 255, "xrdp_sesman_%8.8x_reload", g_pid);
|
||||
g_reload_event = g_create_wait_obj(text);
|
||||
|
||||
g_signal_hang_up(set_reload_event); /* SIGHUP */
|
||||
g_signal_user_interrupt(set_term_event); /* SIGINT */
|
||||
g_signal_terminate(set_term_event); /* SIGTERM */
|
||||
g_signal_pipe(sig_no_op); /* SIGPIPE */
|
||||
g_signal_child_stop(set_sigchld_event); /* SIGCHLD */
|
||||
g_signal_hang_up(set_reload_event); /* SIGHUP */
|
||||
|
||||
if (daemon)
|
||||
{
|
||||
@@ -953,7 +928,7 @@ main(int argc, char **argv)
|
||||
"starting xrdp-sesman with pid %d", g_pid);
|
||||
|
||||
/* make sure the socket directory exists */
|
||||
g_mk_socket_path("xrdp-sesman");
|
||||
g_mk_socket_path();
|
||||
|
||||
/* make sure the /tmp/.X11-unix directory exists */
|
||||
if (!g_directory_exist("/tmp/.X11-unix"))
|
||||
@@ -966,7 +941,11 @@ main(int argc, char **argv)
|
||||
g_chmod_hex("/tmp/.X11-unix", 0x1777);
|
||||
}
|
||||
|
||||
if ((error = pre_session_list_init(MAX_PRE_SESSION_ITEMS)) == 0 &&
|
||||
(error = session_list_init()) == 0)
|
||||
{
|
||||
error = sesman_main_loop();
|
||||
}
|
||||
|
||||
/* clean up PID file on exit */
|
||||
if (daemon)
|
||||
@@ -974,12 +953,9 @@ main(int argc, char **argv)
|
||||
g_file_delete(pid_file);
|
||||
}
|
||||
|
||||
sesman_delete_wait_objects();
|
||||
sesman_close_all();
|
||||
|
||||
if (!daemon)
|
||||
{
|
||||
log_end();
|
||||
}
|
||||
|
||||
config_free(g_cfg);
|
||||
g_deinit();
|
||||
|
||||
+31
-40
@@ -27,33 +27,11 @@
|
||||
#ifndef SESMAN_H
|
||||
#define SESMAN_H
|
||||
|
||||
/**
|
||||
* Type for managing sesman connections from xrdp (etc)
|
||||
*/
|
||||
struct sesman_con
|
||||
{
|
||||
struct trans *t;
|
||||
char peername[15 + 1]; /* Name of peer, if known, for logging */
|
||||
int close_requested; /* Set to close the connection normally */
|
||||
unsigned int auth_retry_count;
|
||||
struct auth_info *auth_info; /* non-NULL for an authenticated connection */
|
||||
int uid; /* User */
|
||||
char *username; /* Username from UID (at time of logon) */
|
||||
char *ip_addr; /* Connecting IP address */
|
||||
};
|
||||
struct config_sesman;
|
||||
struct trans;
|
||||
|
||||
/* Globals */
|
||||
extern struct config_sesman *g_cfg;
|
||||
extern unsigned char g_fixedkey[8];
|
||||
|
||||
/**
|
||||
* Set the peername of a connection
|
||||
*
|
||||
* @param name Name to set
|
||||
* @result 0 for success
|
||||
*/
|
||||
int
|
||||
sesman_set_connection_peername(struct sesman_con *sc, const char *name);
|
||||
|
||||
/**
|
||||
* Close all file descriptors used by sesman.
|
||||
@@ -61,24 +39,13 @@ sesman_set_connection_peername(struct sesman_con *sc, const char *name);
|
||||
* This is generally used after forking, to make sure the
|
||||
* file descriptors used by the main process are not disturbed
|
||||
*
|
||||
* This call will also release all trans and SCP_SESSION objects
|
||||
* held by sesman
|
||||
*
|
||||
* @param flags Set SCA_CLOSE_AUTH_INFO to close any open auth_info
|
||||
* objects. By default these are not cleared, and should
|
||||
* only be done so when exiting sesman.
|
||||
* This call will also :-
|
||||
* - release all trans objects held by sesman
|
||||
* - Delete sesman wait objects
|
||||
* - Call sesman_delete_listening_transport()
|
||||
*/
|
||||
#define SCA_CLOSE_AUTH_INFO (1<<0)
|
||||
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);
|
||||
sesman_close_all(void);
|
||||
|
||||
/*
|
||||
* Remove the listening transport
|
||||
@@ -96,4 +63,28 @@ sesman_delete_listening_transport(void);
|
||||
int
|
||||
sesman_create_listening_transport(const struct config_sesman *cfg);
|
||||
|
||||
/**
|
||||
* Callback to process incoming SCP data
|
||||
*/
|
||||
int
|
||||
sesman_scp_data_in(struct trans *self);
|
||||
|
||||
/**
|
||||
* Callback to process incoming EICP data
|
||||
*/
|
||||
int
|
||||
sesman_eicp_data_in(struct trans *self);
|
||||
|
||||
/**
|
||||
* Callback to process incoming ERCP data
|
||||
*/
|
||||
int
|
||||
sesman_ercp_data_in(struct trans *self);
|
||||
|
||||
/*
|
||||
* Check for termination
|
||||
*/
|
||||
int
|
||||
sesman_is_term(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,6 +51,15 @@ X11DisplayOffset=10
|
||||
; Default: 0
|
||||
MaxSessions=50
|
||||
|
||||
;; MaxDisplayNumer - maximum number considered for an X display
|
||||
; Type: integer
|
||||
; Default: 63
|
||||
;
|
||||
; IANA only allocates TCP ports up to 6063 for X servers. If you are not
|
||||
; allowing TCP connections to your X servers you may safely increase this
|
||||
; number.
|
||||
#MaxDisplayNumber=63
|
||||
|
||||
;; KillDisconnected - kill disconnected sessions
|
||||
; Type: boolean
|
||||
; Default: false
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* 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.h
|
||||
* @brief Session management definitions
|
||||
* @author Jay Sorg, Simone Fedele
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "guid.h"
|
||||
#include "scp_application_types.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
struct auth_info;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
char shell[INFO_CLIENT_MAX_CB_LEN];
|
||||
char directory[INFO_CLIENT_MAX_CB_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief starts a session
|
||||
*
|
||||
* @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 *s,
|
||||
int *pid);
|
||||
|
||||
int
|
||||
session_reconnect(int display, int uid,
|
||||
struct auth_info *auth_info);
|
||||
|
||||
#endif // SESSION_H
|
||||
+319
-306
@@ -33,130 +33,115 @@
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
#include "arch.h"
|
||||
#include "session_list.h"
|
||||
#include "trans.h"
|
||||
|
||||
#include "sesman_auth.h"
|
||||
#include "sesman_config.h"
|
||||
#include "list.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;
|
||||
static struct list *g_session_list = NULL;
|
||||
|
||||
#define SESSION_IN_USE(si) \
|
||||
((si) != NULL && \
|
||||
(si)->sesexec_trans != NULL && \
|
||||
(si)->sesexec_trans->status == TRANS_STATUS_UP)
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_init(void)
|
||||
{
|
||||
int rv = 1;
|
||||
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");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_session_list->auto_free = 0;
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Frees resources allocated to a session_item
|
||||
*
|
||||
* @param si Session item
|
||||
*
|
||||
* @note Any pointer to this item on g_session_list will be invalid
|
||||
* after this call.
|
||||
*/
|
||||
static void
|
||||
free_session(struct session_item *si)
|
||||
{
|
||||
if (si != NULL)
|
||||
{
|
||||
if (si->sesexec_trans != NULL)
|
||||
{
|
||||
trans_delete(si->sesexec_trans);
|
||||
}
|
||||
g_free(si);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
session_list_cleanup(void)
|
||||
{
|
||||
if (g_session_list != NULL)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < g_session_list->count ; ++i)
|
||||
{
|
||||
struct session_item *si;
|
||||
si = (struct session_item *)list_get_item(g_session_list, i);
|
||||
free_session(si);
|
||||
}
|
||||
list_delete(g_session_list);
|
||||
g_session_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
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++;
|
||||
return g_session_list->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)
|
||||
session_list_new(void)
|
||||
{
|
||||
char policy_str[64];
|
||||
struct session_chain *tmp;
|
||||
int policy = g_cfg->sess.policy;
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_DEFAULT) != 0)
|
||||
struct session_item *result = g_new0(struct session_item, 1);
|
||||
if (result != NULL)
|
||||
{
|
||||
/* 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;
|
||||
result->state = E_SESSION_STARTING;
|
||||
if (!list_add_item(g_session_list, (tintptr)result))
|
||||
{
|
||||
g_free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -261,257 +246,237 @@ x_server_running_check_ports(int display)
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* called with the main thread
|
||||
returns boolean */
|
||||
/* Helper function for get_sorted_display_list():qsort() */
|
||||
static int
|
||||
is_display_in_chain(int display)
|
||||
icmp(const void *i1, const void *i2)
|
||||
{
|
||||
struct session_chain *chain;
|
||||
struct session_item *item;
|
||||
return *(const unsigned int *)i2 - *(const unsigned int *)i1;
|
||||
}
|
||||
|
||||
chain = g_sessions;
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
while (chain != 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)
|
||||
{
|
||||
item = chain->item;
|
||||
|
||||
if (item->display == display)
|
||||
LOG(LOG_LEVEL_ERROR, "Can't allocate memory for display list");
|
||||
}
|
||||
else if (g_session_list != NULL)
|
||||
{
|
||||
return 1;
|
||||
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);
|
||||
}
|
||||
|
||||
chain = chain->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return displays;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_get_available_display(void)
|
||||
{
|
||||
int display;
|
||||
int rv = -1;
|
||||
unsigned int max_alloc = 0;
|
||||
|
||||
display = g_cfg->sess.x11_display_offset;
|
||||
// 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;
|
||||
|
||||
while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions)
|
||||
for (display = g_cfg->sess.x11_display_offset;
|
||||
display <= g_cfg->sess.max_display_number;
|
||||
++display)
|
||||
{
|
||||
if (!is_display_in_chain(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))
|
||||
{
|
||||
return display;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
display++;
|
||||
}
|
||||
g_free(allocated_displays);
|
||||
|
||||
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)
|
||||
if (display > g_cfg->sess.max_display_number)
|
||||
{
|
||||
g_snprintf(uname, uname_len, "%s", ustr);
|
||||
g_free(ustr);
|
||||
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
|
||||
{
|
||||
g_snprintf(uname, uname_len, "<unknown>");
|
||||
rv = display;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
struct session_item *dummy;
|
||||
char policy_str[64];
|
||||
int policy = g_cfg->sess.policy;
|
||||
int i;
|
||||
|
||||
dummy = g_new0(struct session_item, 1);
|
||||
|
||||
if (0 == dummy)
|
||||
if (ip_addr == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session_get_bypid: out of memory");
|
||||
return 0;
|
||||
ip_addr = "";
|
||||
}
|
||||
|
||||
tmp = g_sessions;
|
||||
|
||||
while (tmp != 0)
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_DEFAULT) != 0)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session descriptor for pid %d is null!", pid);
|
||||
g_free(dummy);
|
||||
return 0;
|
||||
/* Before xrdp 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;
|
||||
}
|
||||
|
||||
if (tmp->item->pid == pid)
|
||||
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)
|
||||
{
|
||||
g_memcpy(dummy, tmp->item, sizeof(struct session_item));
|
||||
return dummy;
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: No matches possible", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
for (i = 0 ; i < g_session_list->count ; ++i)
|
||||
{
|
||||
struct session_item *si;
|
||||
si = (struct session_item *)list_get_item(g_session_list, i);
|
||||
if (!SESSION_IN_USE(si))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
g_free(dummy);
|
||||
return 0;
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: try %p type=%s U=%d B=%d D=(%dx%d) I=%s",
|
||||
__func__,
|
||||
si,
|
||||
SCP_SESSION_TYPE_TO_STR(si->type),
|
||||
si->uid, si->bpp,
|
||||
si->start_width, si->start_height,
|
||||
si->start_ip_addr);
|
||||
|
||||
if (si->type != type)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: Type doesn't match", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_U) && uid != si->uid)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: UID doesn't match for 'U' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_B) && si->bpp != bpp)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"%s: bpp doesn't match for 'B' policy", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((policy & SESMAN_CFG_SESS_POLICY_D) &&
|
||||
(si->start_width != width ||
|
||||
si->start_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(si->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__, si->display);
|
||||
return si;
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "%s: No matches found", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct scp_session_info *
|
||||
session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags)
|
||||
session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags)
|
||||
{
|
||||
struct session_chain *tmp;
|
||||
int i;
|
||||
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)
|
||||
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) && uid == si->uid)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
(*cnt) = 0;
|
||||
@@ -527,24 +492,23 @@ session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = g_sessions;
|
||||
index = 0;
|
||||
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);
|
||||
|
||||
while (tmp != 0 && index < count)
|
||||
if (SESSION_IN_USE(si) && uid == si->uid)
|
||||
{
|
||||
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);
|
||||
(sess[index]).sid = si->sesexec_pid;
|
||||
(sess[index]).display = si->display;
|
||||
(sess[index]).type = si->type;
|
||||
(sess[index]).height = si->start_height;
|
||||
(sess[index]).width = si->start_width;
|
||||
(sess[index]).bpp = si->bpp;
|
||||
(sess[index]).start_time = si->start_time;
|
||||
(sess[index]).uid = si->uid;
|
||||
(sess[index]).start_ip_addr = g_strdup(si->start_ip_addr);
|
||||
|
||||
/* Check for string allocation failures */
|
||||
if ((sess[index]).start_ip_addr == NULL)
|
||||
@@ -557,10 +521,6 @@ session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags)
|
||||
}
|
||||
}
|
||||
|
||||
/* go on */
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
(*cnt) = count;
|
||||
return sess;
|
||||
}
|
||||
@@ -580,3 +540,56 @@ free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt)
|
||||
|
||||
g_free(sesslist);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_get_wait_objs(tbus robjs[], int *robjs_count)
|
||||
{
|
||||
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))
|
||||
{
|
||||
robjs[(*robjs_count)++] = si->sesexec_trans->sck;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
session_list_check_wait_objs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < g_session_list->count; ++i)
|
||||
{
|
||||
struct session_item *si;
|
||||
si = (struct session_item *)list_get_item(g_session_list, i);
|
||||
if (SESSION_IN_USE(si))
|
||||
{
|
||||
if (trans_check_wait_objs(si->sesexec_trans) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "sesman_check_wait_objs: "
|
||||
"trans_check_wait_objs failed, removing trans");
|
||||
si->sesexec_trans->status = TRANS_STATUS_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
if (SESSION_IN_USE(si))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
free_session(si);
|
||||
list_remove_item(g_session_list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+75
-74
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2013
|
||||
* Copyright (C) Jay Sorg 2004-2023
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,61 +28,60 @@
|
||||
#ifndef SESSION_LIST_H
|
||||
#define SESSION_LIST_H
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.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
|
||||
enum session_state
|
||||
{
|
||||
SESMAN_SESSION_KILL_OK = 0,
|
||||
SESMAN_SESSION_KILL_NULLITEM,
|
||||
SESMAN_SESSION_KILL_NOTFOUND
|
||||
/**
|
||||
* Session definition is little more than a sesexec process. We're
|
||||
* waiting for more details of the session from sesexec */
|
||||
E_SESSION_STARTING,
|
||||
/** Session is fully active */
|
||||
E_SESSION_RUNNING
|
||||
};
|
||||
|
||||
struct scp_session_info;
|
||||
|
||||
/**
|
||||
* Object describing a session
|
||||
*
|
||||
* Unless otherwide noted, fields are only valid if
|
||||
* the status is E_SESSION_RUNNING
|
||||
*/
|
||||
struct session_item
|
||||
{
|
||||
int uid; /* UID of session */
|
||||
int pid; /* pid of sesman waiting for wm to end */
|
||||
enum session_state state;
|
||||
struct trans *sesexec_trans; // trans for sesexec process. Always valid.
|
||||
pid_t sesexec_pid; // pid for sesexec process. Always valid
|
||||
/**
|
||||
* May be valid if known when the session is starting, otherwise -1 */
|
||||
int display;
|
||||
int width;
|
||||
int height;
|
||||
int bpp;
|
||||
struct auth_info *auth_info;
|
||||
|
||||
/* status info */
|
||||
unsigned char status;
|
||||
uid_t uid;
|
||||
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];
|
||||
unsigned short start_width;
|
||||
unsigned short start_height;
|
||||
unsigned char bpp;
|
||||
struct guid guid;
|
||||
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
|
||||
time_t start_time;
|
||||
};
|
||||
|
||||
struct session_chain
|
||||
{
|
||||
struct session_chain *next;
|
||||
struct session_item *item;
|
||||
};
|
||||
/**
|
||||
* Initialise the module
|
||||
* @return 0 for success
|
||||
*
|
||||
* Errors are logged
|
||||
*/
|
||||
int
|
||||
session_list_init(void);
|
||||
|
||||
/**
|
||||
* Clean up the module on program exit
|
||||
*/
|
||||
void
|
||||
session_list_cleanup(void);
|
||||
|
||||
/**
|
||||
* Returns the number of sessions currently active
|
||||
@@ -92,18 +91,31 @@ unsigned int
|
||||
session_list_get_count(void);
|
||||
|
||||
/**
|
||||
* Adds a new session item to the chain
|
||||
* Allocates a new session on the list
|
||||
*
|
||||
* state will be E_SESSION_STARTING. Other data must be filled in by
|
||||
* the caller as appropriate.
|
||||
*
|
||||
* @return pointer to new session object or NULL for no memory
|
||||
*
|
||||
* After allocating the session, you must initialise the sesexec_trans field
|
||||
* with a valid transport.
|
||||
*
|
||||
* The session is removed by session_check_wait_objs() when the transport
|
||||
* goes down (or wasn't allocated in the first place).
|
||||
*/
|
||||
void
|
||||
session_list_add(struct session_chain *element);
|
||||
struct session_item *
|
||||
session_list_new(void);
|
||||
|
||||
/**
|
||||
* Get the next available display
|
||||
*
|
||||
* The display isn't reserved until the caller has allocated a new session
|
||||
* (with session_list_new()) and put the new display in it.
|
||||
*/
|
||||
int
|
||||
session_list_get_available_display(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief finds a session matching the supplied parameters
|
||||
@@ -119,45 +131,17 @@ session_list_get_bydata(uid_t uid,
|
||||
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
|
||||
* @param uid the UID for the descriptions
|
||||
* @param[out] cnt The number of sessions returned
|
||||
* @param flags Future expansion
|
||||
* @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);
|
||||
session_list_get_byuid(uid_t uid, unsigned int *cnt, unsigned int flags);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -168,4 +152,21 @@ session_list_get_byuid(int uid, unsigned int *cnt, unsigned char flags);
|
||||
void
|
||||
free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt);
|
||||
|
||||
/**
|
||||
* @brief Get the wait objs for the session list module
|
||||
* @param @robjs Objects array to update
|
||||
* @param robjs_count Elements in robjs (by reference)
|
||||
* @return 0 for success
|
||||
*/
|
||||
int
|
||||
session_list_get_wait_objs(tbus robjs[], int *robjs_count);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check the wait objs for the session list module
|
||||
* @return 0 for success
|
||||
*/
|
||||
int
|
||||
session_list_check_wait_objs(void);
|
||||
|
||||
#endif // SESSION_LIST_H
|
||||
|
||||
@@ -95,24 +95,3 @@ sig_sesman_reload_cfg(void)
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "configuration reloaded, log subsystem restarted");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
sig_sesman_session_end(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "receiving SIGCHLD");
|
||||
do
|
||||
{
|
||||
pid = g_waitchild(NULL);
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Process %d has exited", pid);
|
||||
|
||||
session_list_kill(pid);
|
||||
}
|
||||
}
|
||||
while (pid > 0);
|
||||
}
|
||||
|
||||
@@ -35,12 +35,4 @@
|
||||
void
|
||||
sig_sesman_reload_cfg(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief SIGCHLD handling code
|
||||
*
|
||||
*/
|
||||
void
|
||||
sig_sesman_session_end(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -308,7 +308,6 @@ main(int argc, char **argv)
|
||||
rv = g_system(amp.command);
|
||||
LOG(LOG_LEVEL_INFO, "command \"%s\" returned %d",
|
||||
amp.command, rv);
|
||||
auth_stop_session(auth_info);
|
||||
}
|
||||
}
|
||||
if (auth_info != NULL)
|
||||
|
||||
@@ -262,6 +262,23 @@ START_TEST(test_g_file_get_open_fds)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_g_file_is_open)
|
||||
{
|
||||
int devzerofd = g_file_open("/dev/zero");
|
||||
ck_assert(devzerofd >= 0);
|
||||
|
||||
// Check open file comes up as open
|
||||
ck_assert_int_ne(g_file_is_open(devzerofd), 0);
|
||||
|
||||
g_file_close(devzerofd);
|
||||
|
||||
// Check the now-closed file no longer registers as open
|
||||
ck_assert_int_eq(g_file_is_open(devzerofd), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_g_sck_fd_passing)
|
||||
{
|
||||
@@ -448,6 +465,7 @@ make_suite_test_os_calls(void)
|
||||
#endif
|
||||
tcase_add_test(tc_os_calls, test_g_file_cloexec);
|
||||
tcase_add_test(tc_os_calls, test_g_file_get_open_fds);
|
||||
tcase_add_test(tc_os_calls, test_g_file_is_open);
|
||||
tcase_add_test(tc_os_calls, test_g_sck_fd_passing);
|
||||
tcase_add_test(tc_os_calls, test_g_sck_fd_overflow);
|
||||
return s;
|
||||
|
||||
@@ -4,7 +4,7 @@ pkglibexec_PROGRAMS = \
|
||||
AM_LDFLAGS = -lX11 -lXrandr
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/sesman \
|
||||
-I$(top_srcdir)/sesman/sesexec \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
AM_CFLAGS = $(X_CFLAGS)
|
||||
|
||||
Reference in New Issue
Block a user