Add sesexec control module
This module provides a secure way for sesman to start the sesexec program and establish a private communications channel with it.
This commit is contained in:
parent
3d95954d87
commit
dadb393443
@ -24,6 +24,8 @@ xrdp_sesman_SOURCES = \
|
||||
scp_process.h \
|
||||
sesman.c \
|
||||
sesman.h \
|
||||
sesexec_control.c \
|
||||
sesexec_control.h \
|
||||
session.c \
|
||||
session.h \
|
||||
session_list.c \
|
||||
|
228
sesman/sesexec_control.c
Normal file
228
sesman/sesexec_control.c
Normal file
@ -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;
|
||||
}
|
49
sesman/sesexec_control.h
Normal file
49
sesman/sesexec_control.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user