xrdp/libipm/scp.c

566 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 *ip_addr)
{
int rv;
rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_GATEWAY_REQUEST,
"sss",
username,
password,
ip_addr);
/* 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 **ip_addr)
{
/* 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,
ip_addr);
}
/*****************************************************************************/
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 *ip_addr)
{
int rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_CREATE_SESSION_REQUEST,
"ssyqqysss",
username,
password,
type,
width,
height,
bpp,
shell,
directory,
ip_addr);
/* 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 **ip_addr)
{
/* 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,
ip_addr);
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->start_ip_addr);
}
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_start_ip_addr;
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_start_ip_addr);
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_start_ip_addr) + 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->start_ip_addr =
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->start_ip_addr, i_start_ip_addr);
}
}
}
*info = p;
}
return rv;
}