Files
xrdp/sesman/sesexec/eicp_server.c
T
matt335672 bee806d3af Add sesexec discover module
The module is a dummy to be filled in later

Other structural changes to sesexec:-
1) A failure of sesman needs to be detected and handled without
   causing sesexec to exit
2) If sesexec exits, the session can never be rediscovered. sesexec must
   be robust enough to stay up for the lifetime of the session so that
   the discovery function always works.
3) There is a mechanism for sesexec to terminate the session, but it
   doesn't work, as SIGCHLD is not processed while we are waiting for
   the session to finish. This needs fixing.
2025-03-12 11:08:03 +00:00

233 lines
7.4 KiB
C

/**
* 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 "sesexec_discover.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 status;
status = eicp_get_create_session_request(
self, &scp_fd, &sp.display,
&sp.type, &sp.width, &sp.height,
&sp.bpp, &sp.shell, &sp.directory);
if (status == 0)
{
// Need to talk to the SCP client
struct trans *scp_trans;
scp_trans = scp_init_trans_from_fd(scp_fd, TRANS_TYPE_SERVER,
sesexec_is_term);
if (scp_trans == NULL)
{
LOG(LOG_LEVEL_ERROR, "Can't create SCP trans");
g_file_close(scp_fd);
status = 1;
}
else
{
enum scp_screate_status scp_status = E_SCP_SCREATE_OK;
// Use the UID from the SCP connection if the user hasn't
// explicitly logged in
if (g_login_info == NULL &&
(g_login_info = login_info_uds_login_user(scp_trans)) == NULL)
{
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);
}
// Further comms to sesman is sent over the ERCP protocol
ercp_trans_from_eicp_trans(self,
sesexec_ercp_data_in,
(void *)self);
if (scp_status != E_SCP_SCREATE_OK)
{
// Tell sesman the session hasn't started
(void)ercp_send_session_finished_event(self);
}
else if ((status = ercp_send_session_announce_event(
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))) != 0)
{
// We failed to tell sesman about the new session. This
// probably means sesman has exited in the time between
// asking us to start a session, and our reply. This
// could be many seconds, and a new sesman may well
// have started.
// If we enable the restart functionality at
// this point, we have a race condition that could
// result in a session which sesman doesn't know
// about. The simplest thing to do in this rare situation
// is to abort the session - the user can create a
// new one
LOG(LOG_LEVEL_ERROR,
"sesman appears to have failed - stopping session");
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
}
else if ((status = sesexec_discover_enable()) != 0)
{
// Equally regrettable - we can't make the session
// discoverable, so we'll stop it. We can tell sesman
// about this one however.
LOG(LOG_LEVEL_ERROR,
"unable to make session discoverable"
" - stopping session");
(void)ercp_send_session_finished_event(self);
scp_status = E_SCP_SCREATE_GENERAL_ERROR;
}
// Return the status to the SCP client.
(void)scp_send_create_session_response(scp_trans, scp_status,
sp.display, &sp.guid);
trans_delete(scp_trans);
}
}
if (status != 0)
{
// Kill sesexec, and any active session
sesexec_terminate_main_loop(status);
}
return 0;
}
/******************************************************************************/
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;
}