Introduce instance_name field into xrdp.ini and xrdp-sesrun, along with

the N policy in sesman.ini, allowing xrdp sessions to be tagged with an
instance name to enable persistent association with a specific
xrdp instance, to allow experiences where users reconnect to specific
sessions based on e.g. the xrdp listening port used.
This commit is contained in:
Leonard Nielsen
2026-01-20 12:00:40 +01:00
parent 259dc937bf
commit 0edde4c090
28 changed files with 162 additions and 51 deletions
+5 -1
View File
@@ -43,6 +43,7 @@ process_session_announce_event(struct session_item *si)
{
int rv;
const char *start_ip_addr;
const char *instance_name;
unsigned int display;
rv = ercp_get_session_announce_event(si->sesexec_trans,
@@ -54,7 +55,8 @@ process_session_announce_event(struct session_item *si)
&si->bpp,
&si->guid,
&start_ip_addr,
&si->start_time);
&si->start_time,
&instance_name);
if (rv == 0)
{
// We may already know the display we sent sesexec. If we do,
@@ -71,6 +73,8 @@ process_session_announce_event(struct session_item *si)
{
snprintf(si->start_ip_addr, sizeof(si->start_ip_addr),
"%s", start_ip_addr);
snprintf(si->xrdp_instance_name, sizeof(si->xrdp_instance_name),
"%s", instance_name);
si->display = display;
si->state = E_SESSION_RUNNING;
+1
View File
@@ -95,6 +95,7 @@ static const struct bitmask_char policy_bits[] =
{ SESMAN_CFG_SESS_POLICY_B, 'B' },
{ SESMAN_CFG_SESS_POLICY_D, 'D' },
{ SESMAN_CFG_SESS_POLICY_I, 'I' },
{ SESMAN_CFG_SESS_POLICY_N, 'N' },
BITMASK_CHAR_END_OF_LIST
};
+2 -1
View File
@@ -42,7 +42,8 @@ enum SESMAN_CFG_SESS_POLICY_BITS
SESMAN_CFG_SESS_POLICY_U = (1 << 2),
SESMAN_CFG_SESS_POLICY_B = (1 << 3),
SESMAN_CFG_SESS_POLICY_D = (1 << 4),
SESMAN_CFG_SESS_POLICY_I = (1 << 5)
SESMAN_CFG_SESS_POLICY_I = (1 << 5),
SESMAN_CFG_SESS_POLICY_N = (1 << 6)
};
/**
+1
View File
@@ -84,6 +84,7 @@ struct scp_list_item
uid_t uid; ///< User
char *username; ///< Username from UID (at time of logon)
char start_ip_addr[MAX_PEER_ADDRSTRLEN];
char xrdp_instance_name[MAX_XRDP_INSTANCE_NAMELEN]; ///< Instance name associated with session
int is_admin;
int create_session_in_progress; ///< Already handling a create_session
/// Display allocated for session. This is always valid (>= 0)
+6 -3
View File
@@ -439,6 +439,7 @@ process_create_session_request(struct scp_list_item *sli)
unsigned char bpp;
const char *shell;
const char *directory;
const char *instance_name;
struct guid guid;
int display = -1;
@@ -450,7 +451,8 @@ process_create_session_request(struct scp_list_item *sli)
rv = scp_get_create_session_request(sli->client_trans,
&type, &width, &height,
&bpp, &shell, &directory);
&bpp, &shell, &directory,
&instance_name);
if (rv == 0)
{
@@ -469,7 +471,7 @@ process_create_session_request(struct scp_list_item *sli)
sli->peername, sli->username);
s_item = session_list_get_bydata(sli->uid, type, width, height,
bpp, sli->start_ip_addr);
bpp, sli->start_ip_addr, instance_name);
if (s_item != NULL)
{
// Found an existing session
@@ -532,7 +534,8 @@ process_create_session_request(struct scp_list_item *sli)
sli->sesexec_trans,
display,
type, width, height,
bpp, shell, directory);
bpp, shell, directory,
instance_name);
if (eicp_stat != 0)
{
+4 -2
View File
@@ -150,7 +150,8 @@ handle_create_session_request(struct trans *self)
status = eicp_get_create_session_request(
self, &sp.display,
&sp.type, &sp.width, &sp.height,
&sp.bpp, &sp.shell, &sp.directory);
&sp.bpp, &sp.shell, &sp.directory,
&sp.instance_name);
if (status == 0)
{
enum scp_screate_status scp_status = E_SCP_SCREATE_OK;
@@ -185,7 +186,8 @@ handle_create_session_request(struct trans *self)
sp.bpp,
&sp.guid,
g_login_info->ip_addr,
session_get_start_time(g_session_data))) != 0)
session_get_start_time(g_session_data),
sp.instance_name)) != 0)
{
// We failed to tell sesman about the new session. This
// probably means sesman has exited in the time between
+2 -1
View File
@@ -100,7 +100,8 @@ discover_trans_conn_in(struct trans *trans, struct trans *new_trans)
sp->bpp,
&sp->guid,
g_login_info->ip_addr,
session_get_start_time(g_session_data));
session_get_start_time(g_session_data),
sp->instance_name);
// Tell semsan about the last client connect or disconnect
if (g_ccp_trans != NULL)
+2
View File
@@ -85,6 +85,7 @@ session_data_new(const struct session_parameters *sp)
// What string length do we need?
string_length += g_strlen(sp->shell) + 1;
string_length += g_strlen(sp->directory) + 1;
string_length += g_strlen(sp->instance_name) + 1;
struct session_data *sd = (struct session_data *)g_malloc(sizeof(*sd) + string_length, 0);
@@ -113,6 +114,7 @@ session_data_new(const struct session_parameters *sp)
COPY_STRING(sd->params.shell, sp->shell);
COPY_STRING(sd->params.directory, sp->directory);
COPY_STRING(sd->params.instance_name, sp->instance_name);
#undef COPY_STRING
}
+1
View File
@@ -49,6 +49,7 @@ struct session_parameters
struct guid guid;
const char *shell; // Must not be NULL
const char *directory; // Must not be NULL
const char *instance_name; //Must not be NULL
};
+1
View File
@@ -124,6 +124,7 @@ IdleTimeLimit=0
; B Sessions are separated by bits-per-pixel
; D Sessions are separated by initial display size
; I Sessions are separated by IP address
; N Sessions are separated by xrdp instance name
;
; The options U and B are always active, and cannot be de-selected.
;
+23 -6
View File
@@ -184,7 +184,8 @@ session_list_get_bydata(uid_t uid,
unsigned short width,
unsigned short height,
unsigned char bpp,
const char *ip_addr)
const char *ip_addr,
const char *instance_name)
{
char policy_str[64];
int policy = g_cfg->sess.policy;
@@ -195,6 +196,11 @@ session_list_get_bydata(uid_t uid,
ip_addr = "";
}
if (instance_name == NULL)
{
instance_name = "";
}
if ((policy & SESMAN_CFG_SESS_POLICY_DEFAULT) != 0)
{
/* Before xrdp v0.9.14, the default
@@ -206,11 +212,11 @@ session_list_get_bydata(uid_t uid,
config_output_policy_string(policy, policy_str, sizeof(policy_str));
LOG(LOG_LEVEL_DEBUG,
"%s: search policy=%s type=%s U=%d B=%d D=(%dx%d) I=%s",
"%s: search policy=%s type=%s U=%d B=%d D=(%dx%d) I=%s P=%s",
__func__,
policy_str, SCP_SESSION_TYPE_TO_STR(type),
uid, bpp, width, height,
ip_addr);
ip_addr, instance_name);
/* 'Separate' policy never matches */
if (policy & SESMAN_CFG_SESS_POLICY_SEPARATE)
@@ -229,13 +235,13 @@ session_list_get_bydata(uid_t uid,
}
LOG(LOG_LEVEL_DEBUG,
"%s: try %p type=%s U=%d B=%d D=(%dx%d) I=%s",
"%s: try %p type=%s U=%d B=%d D=(%dx%d) I=%s N=%s",
__func__,
si,
SCP_SESSION_TYPE_TO_STR(si->type),
si->uid, si->bpp,
si->start_width, si->start_height,
si->start_ip_addr);
si->start_ip_addr, si->xrdp_instance_name);
if (si->type != type)
{
@@ -274,6 +280,14 @@ session_list_get_bydata(uid_t uid,
continue;
}
if ((policy & SESMAN_CFG_SESS_POLICY_N) &&
g_strcmp(si->xrdp_instance_name, instance_name) != 0)
{
LOG(LOG_LEVEL_DEBUG,
"%s: Instance names don't match for 'N' policy", __func__);
continue;
}
LOG(LOG_LEVEL_DEBUG,
"%s: Got match, display=%d", __func__, si->display);
return si;
@@ -348,11 +362,13 @@ session_list_get_byuid(const uid_t *uid, unsigned int *cnt, unsigned int flags)
sess[index].client_ip = g_strdup(si->client_ip);
sess[index].client_name = g_strdup(si->client_name);
sess[index].last_connect_disconnect = si->last_connect_disconnect;
sess[index].xrdp_instance_name = g_strdup(si->xrdp_instance_name);
/* Check for string allocation failures */
if (sess[index].start_ip_addr == NULL ||
sess[index].client_ip == NULL ||
sess[index].client_name == NULL)
sess[index].client_name == NULL ||
sess[index].xrdp_instance_name == NULL)
{
free_session_info_list(sess, *cnt);
(*cnt) = 0;
@@ -397,6 +413,7 @@ free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt)
g_free(sesslist[i].start_ip_addr);
g_free(sesslist[i].client_ip);
g_free(sesslist[i].client_name);
g_free(sesslist[i].xrdp_instance_name);
}
}
+4 -1
View File
@@ -71,6 +71,8 @@ struct session_item
char client_ip[MAX_PEER_ADDRSTRLEN];
char client_name[INFO_CLIENT_NAME_BYTES_UTF8];
time_t last_connect_disconnect;
char xrdp_instance_name[MAX_XRDP_INSTANCE_NAMELEN];
/* allow a tag to be specified to distinguish sessions */
};
/**
@@ -140,7 +142,8 @@ session_list_get_bydata(uid_t uid,
unsigned short width,
unsigned short height,
unsigned char bpp,
const char *ip_addr);
const char *ip_addr,
const char *instance_name);
/**
* @brief retrieves session descriptions
+4
View File
@@ -166,6 +166,10 @@ print_session(const struct scp_session_info *s)
(s->last_connect_disconnect == 0) ? "-\n" :
ctime(&s->last_connect_disconnect));
}
if (s->xrdp_instance_name[0] != '\0')
{
printf("\txrdp instance name: %s\n", s->xrdp_instance_name);
}
g_free(username);
}
+14 -4
View File
@@ -103,6 +103,7 @@ struct session_params
const char *ip_addr;
const char *username;
const char *instance_name;
char password[MAX_PASSWORD_LEN + 1];
};
@@ -181,6 +182,7 @@ usage(void)
g_printf(" -t <type> Default:%s\n", DEFAULT_SESSION_TYPE);
g_printf(" -D <directory> Default: $HOME\n"
" -S <shell> Default: Defined window manager\n"
" -N <instance-name> Default: Empty\n"
" -p <password> TESTING ONLY - DO NOT USE IN PRODUCTION\n"
" -F <file-descriptor> Read password from this file descriptor\n"
" -c <sesman_ini> Alternative sesman.ini file\n");
@@ -189,6 +191,8 @@ usage(void)
g_printf("\nIf username is omitted, the current user is used.\n"
"If username is provided, password is needed.\n"
" Password is prompted for if -p or -F are not specified\n");
g_printf("\nThe instance name is used to associate the session with an xrdp\n"
"\ndaemon tagged with that particular name.\n");
}
@@ -297,11 +301,12 @@ parse_program_args(int argc, char *argv[], struct session_params *sp,
sp->directory = "";
sp->shell = "";
sp->ip_addr = "";
sp->instance_name = "";
sp->username = NULL;
sp->password[0] = '\0';
while ((opt = getopt(argc, argv, "g:b:s:t:D:S:p:F:c:")) != -1)
while ((opt = getopt(argc, argv, "g:b:s:t:D:S:p:F:c:N:")) != -1)
{
switch (opt)
{
@@ -367,6 +372,10 @@ parse_program_args(int argc, char *argv[], struct session_params *sp,
}
break;
case 'N':
sp->instance_name = optarg;
break;
case 'c':
*sesman_ini = optarg;
break;
@@ -491,13 +500,14 @@ send_create_session_request(struct trans *t, const struct session_params *sp)
{
LOG(LOG_LEVEL_DEBUG,
"width:%d height:%d bpp:%d code:%d\n"
"directory:\"%s\" shell:\"%s\"",
"directory:\"%s\" shell:\"%s\" instance_name:\"%s\"",
sp->width, sp->height, sp->bpp, sp->session_type,
sp->directory, sp->shell);
sp->directory, sp->shell, sp->instance_name);
return scp_send_create_session_request(
t, sp->session_type,
sp->width, sp->height, sp->bpp, sp->shell, sp->directory);
sp->width, sp->height, sp->bpp, sp->shell,
sp->directory, sp->instance_name);
}
/**************************************************************************//**