0db849fc5c
The TCP socket implementation of sesman has a number of limitations, namely that it is affected by firewalls, and also that determining the user on the other end requires a full authentication process. The advantage of the TCP socket is that sesman and xrdp can be run on separate machines. This is however not supported by the xorgxrdp backend (shared memory), and is insecure, in that passwords are sent in-the-clear, and the connection is susceptible to MitM attacks. This architecture has been deprecated in release notes since xrdp v0.9.17, and although it will continue to be supported in any further releases in the x0.9.x series, it will not be supported in the next major version.
567 lines
16 KiB
C
567 lines
16 KiB
C
/**
|
|
* 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/scp.c
|
|
* @brief scp definitions
|
|
* @author Simone Fedele/ Matt Burt
|
|
*/
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include <config_ac.h>
|
|
#endif
|
|
|
|
#include "scp.h"
|
|
#include "libipm.h"
|
|
#include "guid.h"
|
|
#include "trans.h"
|
|
#include "os_calls.h"
|
|
#include "string_calls.h"
|
|
#include "xrdp_sockets.h"
|
|
|
|
/*****************************************************************************/
|
|
static const char *
|
|
msgno_to_str(unsigned short n)
|
|
{
|
|
return
|
|
(n == E_SCP_GATEWAY_REQUEST) ? "SCP_GATEWAY_REQUEST" :
|
|
(n == E_SCP_GATEWAY_RESPONSE) ? "SCP_GATEWAY_RESPONSE" :
|
|
(n == E_SCP_CREATE_SESSION_REQUEST) ? "SCP_CREATE_SESSION_REQUEST" :
|
|
(n == E_SCP_CREATE_SESSION_RESPONSE) ? "SCP_CREATE_SESSION_RESPONSE" :
|
|
(n == E_SCP_LIST_SESSIONS_REQUEST) ? "SCP_LIST_SESSIONS_REQUEST" :
|
|
(n == E_SCP_LIST_SESSIONS_RESPONSE) ? "SCP_LIST_SESSIONS_RESPONSE" :
|
|
NULL;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
const char *
|
|
scp_msgno_to_str(enum scp_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
|
|
scp_port_to_unix_domain_path(const char *port, char *buff,
|
|
unsigned int bufflen)
|
|
{
|
|
/* GOTCHA: Changes to this logic should be mirrored in
|
|
* scp_port_to_display_string() */
|
|
|
|
int result;
|
|
|
|
/* Make sure we can safely de-reference 'port' */
|
|
if (port == NULL)
|
|
{
|
|
port = "";
|
|
}
|
|
|
|
if (port[0] == '/')
|
|
{
|
|
result = g_snprintf(buff, bufflen, "%s", port);
|
|
}
|
|
else
|
|
{
|
|
const char *sep;
|
|
if ((sep = g_strrchr(port, '/')) != NULL && sep != port)
|
|
{
|
|
/* We allow the user to specify an absolute path, but not
|
|
* a relative one with embedded '/' characters */
|
|
LOG(LOG_LEVEL_WARNING, "Ignoring path elements of '%s'", port);
|
|
port = sep + 1;
|
|
}
|
|
|
|
if (port[0] == '\0')
|
|
{
|
|
port = SCP_LISTEN_PORT_BASE_STR;
|
|
}
|
|
else if (g_strcmp(port, "3350") == 0)
|
|
{
|
|
/* Version v0.9.x and earlier of xrdp used a TCP port
|
|
* number. If we come across this, we'll ignore it for
|
|
* compatibility with old config files */
|
|
LOG(LOG_LEVEL_WARNING,
|
|
"Ignoring obsolete SCP port value '%s'", port);
|
|
port = SCP_LISTEN_PORT_BASE_STR;
|
|
}
|
|
|
|
result = g_snprintf(buff, bufflen, SESMAN_RUNTIME_PATH "/%s", port);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int
|
|
scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen)
|
|
{
|
|
/* Make sure we can safely de-reference 'port' */
|
|
if (port == NULL)
|
|
{
|
|
port = "";
|
|
}
|
|
|
|
/* Ignore any directories for the display */
|
|
const char *sep;
|
|
if ((sep = g_strrchr(port, '/')) != NULL)
|
|
{
|
|
port = sep + 1;
|
|
}
|
|
|
|
/* Check for a default */
|
|
if (port[0] == '\0' || g_strcmp(port, "3350") == 0)
|
|
{
|
|
port = SCP_LISTEN_PORT_BASE_STR;
|
|
}
|
|
|
|
return g_snprintf(buff, bufflen, "%s", port);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
struct trans *
|
|
scp_connect(const char *port,
|
|
int (*term_func)(void))
|
|
{
|
|
char sock_path[256];
|
|
struct trans *t;
|
|
|
|
(void)scp_port_to_unix_domain_path(port, sock_path, sizeof(sock_path));
|
|
if ((t = trans_create(TRANS_MODE_UNIX, 128, 128)) != NULL)
|
|
{
|
|
t->is_term = term_func;
|
|
|
|
if (trans_connect(t, NULL, sock_path, 3000) != 0)
|
|
{
|
|
trans_delete(t);
|
|
t = NULL;
|
|
}
|
|
else if (libipm_init_trans(t, LIBIPM_FAC_SCP, msgno_to_str) !=
|
|
E_LI_SUCCESS)
|
|
{
|
|
trans_delete(t);
|
|
t = NULL;
|
|
}
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int
|
|
scp_init_trans(struct trans *trans)
|
|
{
|
|
return libipm_init_trans(trans, LIBIPM_FAC_SCP, msgno_to_str);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_msg_in_check_available(struct trans *trans, int *available)
|
|
{
|
|
return libipm_msg_in_check_available(trans, available);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_msg_in_wait_available(struct trans *trans)
|
|
{
|
|
return libipm_msg_in_wait_available(trans);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void
|
|
scp_msg_in_reset(struct trans *trans)
|
|
{
|
|
libipm_msg_in_reset(trans);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
enum scp_msg_code
|
|
scp_msg_in_start(struct trans *trans)
|
|
{
|
|
return (enum scp_msg_code)libipm_msg_in_start(trans);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
int
|
|
scp_send_gateway_request(struct trans *trans,
|
|
const char *username,
|
|
const char *password,
|
|
const char *connection_description)
|
|
{
|
|
int rv;
|
|
|
|
rv = libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_GATEWAY_REQUEST,
|
|
"sss",
|
|
username,
|
|
password,
|
|
connection_description);
|
|
|
|
/* Wipe the output buffer to remove the password */
|
|
libipm_msg_out_erase(trans);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_gateway_request(struct trans *trans,
|
|
const char **username,
|
|
const char **password,
|
|
const char **connection_description)
|
|
{
|
|
/* 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, "sss", username, password,
|
|
connection_description);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_send_gateway_response(struct trans *trans,
|
|
int auth_result)
|
|
{
|
|
return libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_GATEWAY_RESPONSE,
|
|
"i",
|
|
auth_result);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_gateway_response(struct trans *trans,
|
|
int *auth_result)
|
|
{
|
|
int32_t i_auth_result = 0;
|
|
int rv = libipm_msg_in_parse(trans, "i", &i_auth_result);
|
|
if (rv == 0)
|
|
{
|
|
*auth_result = i_auth_result;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_send_create_session_request(struct trans *trans,
|
|
const char *username,
|
|
const char *password,
|
|
enum scp_session_type type,
|
|
unsigned short width,
|
|
unsigned short height,
|
|
unsigned char bpp,
|
|
const char *shell,
|
|
const char *directory,
|
|
const char *connection_description)
|
|
{
|
|
int rv = libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_CREATE_SESSION_REQUEST,
|
|
"ssyqqysss",
|
|
username,
|
|
password,
|
|
type,
|
|
width,
|
|
height,
|
|
bpp,
|
|
shell,
|
|
directory,
|
|
connection_description);
|
|
|
|
/* Wipe the output buffer to remove the password */
|
|
libipm_msg_out_erase(trans);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_create_session_request(struct trans *trans,
|
|
const char **username,
|
|
const char **password,
|
|
enum scp_session_type *type,
|
|
unsigned short *width,
|
|
unsigned short *height,
|
|
unsigned char *bpp,
|
|
const char **shell,
|
|
const char **directory,
|
|
const char **connection_description)
|
|
{
|
|
/* Intermediate values */
|
|
uint8_t i_type;
|
|
uint16_t i_width;
|
|
uint16_t i_height;
|
|
uint8_t i_bpp;
|
|
|
|
/* Make sure the buffer is cleared after processing this message */
|
|
libipm_set_flags(trans, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
|
|
|
|
int rv = libipm_msg_in_parse(
|
|
trans,
|
|
"ssyqqysss",
|
|
username,
|
|
password,
|
|
&i_type,
|
|
&i_width,
|
|
&i_height,
|
|
&i_bpp,
|
|
shell,
|
|
directory,
|
|
connection_description);
|
|
|
|
if (rv == 0)
|
|
{
|
|
*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;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_send_create_session_response(struct trans *trans,
|
|
int auth_result,
|
|
int display,
|
|
const struct guid *guid)
|
|
{
|
|
struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
|
|
|
return libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_CREATE_SESSION_RESPONSE,
|
|
"iiB",
|
|
auth_result,
|
|
display,
|
|
&guid_descriptor);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_create_session_response(struct trans *trans,
|
|
int *auth_result,
|
|
int *display,
|
|
struct guid *guid)
|
|
{
|
|
/* Intermediate values */
|
|
int32_t i_auth_result;
|
|
int32_t i_display;
|
|
|
|
const struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
|
|
|
|
int rv = libipm_msg_in_parse(
|
|
trans,
|
|
"iiB",
|
|
&i_auth_result,
|
|
&i_display,
|
|
&guid_descriptor);
|
|
if (rv == 0)
|
|
{
|
|
*auth_result = i_auth_result;
|
|
*display = i_display;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_send_list_sessions_request(struct trans *trans,
|
|
const char *username,
|
|
const char *password)
|
|
{
|
|
int rv;
|
|
|
|
rv = libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_LIST_SESSIONS_REQUEST,
|
|
"ss",
|
|
username,
|
|
password);
|
|
|
|
/* Wipe the output buffer to remove the password */
|
|
libipm_msg_out_erase(trans);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_list_sessions_request(struct trans *trans,
|
|
const char **username,
|
|
const char **password)
|
|
{
|
|
/* 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, "ss", username, password);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_send_list_sessions_response(
|
|
struct trans *trans,
|
|
enum scp_list_sessions_status status,
|
|
const struct scp_session_info *info)
|
|
{
|
|
int rv;
|
|
|
|
if (status != E_SCP_LS_SESSION_INFO)
|
|
{
|
|
rv = libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_LIST_SESSIONS_RESPONSE,
|
|
"i", status);
|
|
}
|
|
else
|
|
{
|
|
rv = libipm_msg_out_simple_send(
|
|
trans,
|
|
(int)E_SCP_LIST_SESSIONS_RESPONSE,
|
|
"iiuyqqyxss",
|
|
status,
|
|
info->sid,
|
|
info->display,
|
|
info->type,
|
|
info->width,
|
|
info->height,
|
|
info->bpp,
|
|
info->start_time,
|
|
info->username,
|
|
info->connection_description);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int
|
|
scp_get_list_sessions_response(
|
|
struct trans *trans,
|
|
enum scp_list_sessions_status *status,
|
|
struct scp_session_info **info)
|
|
{
|
|
int32_t i_status;
|
|
int rv;
|
|
|
|
if (info == NULL)
|
|
{
|
|
LOG_DEVEL(LOG_LEVEL_ERROR, "Bad pointer in %s", __func__);
|
|
rv = 1;
|
|
}
|
|
else if ((rv = libipm_msg_in_parse(trans, "i", &i_status)) == 0)
|
|
{
|
|
*status = (enum scp_list_sessions_status)i_status;
|
|
struct scp_session_info *p = NULL;
|
|
|
|
if (*status == E_SCP_LS_SESSION_INFO)
|
|
{
|
|
int32_t i_sid;
|
|
uint32_t i_display;
|
|
uint8_t i_type;
|
|
uint16_t i_width;
|
|
uint16_t i_height;
|
|
uint8_t i_bpp;
|
|
int64_t i_start_time;
|
|
char *i_username;
|
|
char *i_connection_description;
|
|
|
|
rv = libipm_msg_in_parse(
|
|
trans,
|
|
"iuyqqyxss",
|
|
&i_sid,
|
|
&i_display,
|
|
&i_type,
|
|
&i_width,
|
|
&i_height,
|
|
&i_bpp,
|
|
&i_start_time,
|
|
&i_username,
|
|
&i_connection_description);
|
|
|
|
if (rv == 0)
|
|
{
|
|
/* Allocate a block of memory large enough for the
|
|
* structure result, and the strings it contains */
|
|
unsigned int len = sizeof(struct scp_session_info) +
|
|
g_strlen(i_username) + 1 +
|
|
g_strlen(i_connection_description) + 1;
|
|
if ((p = (struct scp_session_info *)g_malloc(len, 1)) == NULL)
|
|
{
|
|
*status = E_SCP_LS_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
/* Set up the string pointers in the block to point
|
|
* into the memory allocated after the block */
|
|
p->username = (char *)p + sizeof(struct scp_session_info);
|
|
p->connection_description =
|
|
p->username + g_strlen(i_username) + 1;
|
|
|
|
/* Copy the data over */
|
|
p->sid = i_sid;
|
|
p->display = i_display;
|
|
p->type = (enum scp_session_type)i_type;
|
|
p->width = i_width;
|
|
p->height = i_height;
|
|
p->bpp = i_bpp;
|
|
p->start_time = i_start_time;
|
|
g_strcpy(p->username, i_username);
|
|
g_strcpy(p->connection_description,
|
|
i_connection_description);
|
|
}
|
|
}
|
|
}
|
|
*info = p;
|
|
}
|
|
return rv;
|
|
}
|