bee806d3af
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.
233 lines
7.4 KiB
C
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;
|
|
}
|