You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xrdp-proprietary/xrdp/xrdp_mm.c

3663 lines
104 KiB

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* 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.
*
* module manager
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <string.h>
#include "xrdp.h"
#include "log.h"
#include "libraptorsmiface.h"
#ifndef USE_NOPAM
#if defined(HAVE__PAM_TYPES_H)
#define LINUXPAM 1
#include <security/_pam_types.h>
#elif defined(HAVE_PAM_CONSTANTS_H)
#define OPENPAM 1
#include <security/pam_constants.h>
#endif
#endif /* USE_NOPAM */
#include "xrdp_encoder.h"
#include "xrdp_sockets.h"
#define LLOG_LEVEL 1
#define LLOGLN(_level, _args) \
do \
{ \
if (_level < LLOG_LEVEL) \
{ \
g_write("xrdp:xrdp_mm [%10.10u]: ", g_time3()); \
g_writeln _args ; \
} \
} \
while (0)
/*****************************************************************************/
struct xrdp_mm *
xrdp_mm_create(struct xrdp_wm *owner)
{
struct xrdp_mm *self;
self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1);
self->wm = owner;
self->login_names = list_create();
self->login_names->auto_free = 1;
self->login_username = 0;
self->login_values = list_create();
self->login_values->auto_free = 1;
LLOGLN(0, ("xrdp_mm_create: bpp %d mcs_connection_type %d "
"jpeg_codec_id %d v3_codec_id %d rfx_codec_id %d "
"h264_codec_id %d",
self->wm->client_info->bpp,
self->wm->client_info->mcs_connection_type,
self->wm->client_info->jpeg_codec_id,
self->wm->client_info->v3_codec_id,
self->wm->client_info->rfx_codec_id,
self->wm->client_info->h264_codec_id));
self->encoder = xrdp_encoder_create(self);
return self;
}
/*****************************************************************************/
/* called from main thread */
static long
xrdp_mm_sync_unload(long param1, long param2)
{
return g_free_library(param1);
}
/*****************************************************************************/
/* called from main thread */
static long
xrdp_mm_sync_load(long param1, long param2)
{
long rv;
char *libname;
libname = (char *)param1;
rv = g_load_library(libname);
return rv;
}
/*****************************************************************************/
static void
xrdp_mm_module_cleanup(struct xrdp_mm *self)
{
log_message(LOG_LEVEL_DEBUG, "xrdp_mm_module_cleanup");
if (self->mod != 0)
{
if (self->mod_exit != 0)
{
/* let the module cleanup */
self->mod_exit(self->mod);
}
}
if (self->mod_handle != 0)
{
/* Let the main thread unload the module.*/
g_xrdp_sync(xrdp_mm_sync_unload, self->mod_handle, 0);
}
trans_delete(self->chan_trans);
self->chan_trans = 0;
self->chan_trans_up = 0;
self->mod_init = 0;
self->mod_exit = 0;
self->mod = 0;
self->mod_handle = 0;
if (self->wm->hide_log_window)
{
/* make sure autologin is off */
self->wm->session->client_info->rdp_autologin = 0;
xrdp_wm_set_login_mode(self->wm, 0); /* reset session */
}
}
/*****************************************************************************/
void
xrdp_mm_delete(struct xrdp_mm *self)
{
if (self == 0)
{
return;
}
/* free any module stuff */
xrdp_mm_module_cleanup(self);
/* shutdown thread */
xrdp_encoder_delete(self->encoder);
trans_delete(self->sesman_trans);
self->sesman_trans = 0;
self->sesman_trans_up = 0;
list_delete(self->login_names);
list_delete(self->login_values);
g_free(self);
}
/*****************************************************************************/
/* Send login information to sesman */
static int
xrdp_mm_send_login(struct xrdp_mm *self)
{
struct stream *s;
int rv;
int index;
int count;
int xserverbpp;
char *username;
char *password;
char *name;
char *value;
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"sending login info to session manager, please wait...");
username = 0;
password = 0;
self->code = 0;
xserverbpp = 0;
count = self->login_names->count;
for (index = 0; index < count; index++)
{
name = (char *)list_get_item(self->login_names, index);
value = (char *)list_get_item(self->login_values, index);
if (g_strcasecmp(name, "username") == 0)
{
username = value;
self->login_username = g_strdup(username);
}
else if (g_strcasecmp(name, "password") == 0)
{
password = value;
}
else if (g_strcasecmp(name, "code") == 0)
{
/* this code is either 0 for Xvnc, 10 for X11rdp or 20 for Xorg */
self->code = g_atoi(value);
}
else if (g_strcasecmp(name, "xserverbpp") == 0)
{
xserverbpp = g_atoi(value);
}
}
if ((username == 0) || (password == 0))
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Error finding username and password");
return 1;
}
s = trans_get_out_s(self->sesman_trans, 8192);
s_push_layer(s, channel_hdr, 8);
/* this code is either 0 for Xvnc, 10 for X11rdp or 20 for Xorg */
out_uint16_be(s, self->code);
index = g_strlen(username);
out_uint16_be(s, index);
out_uint8a(s, username, index);
index = g_strlen(password);
out_uint16_be(s, index);
out_uint8a(s, password, index);
out_uint16_be(s, self->wm->screen->width);
out_uint16_be(s, self->wm->screen->height);
/* select and send X server bpp */
if (xserverbpp == 0)
{
if (self->code == 20)
{
xserverbpp = 24; /* xorgxrdp is always at 24 bpp */
}
else
{
xserverbpp = self->wm->screen->bpp; /* use client's bpp */
}
}
out_uint16_be(s, xserverbpp);
/* send domain */
if(self->wm->client_info->domain[0]!='_')
{
index = g_strlen(self->wm->client_info->domain);
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->domain, index);
}
else
{
out_uint16_be(s, 0);
/* out_uint8a(s, "", 0); */
}
/* send program / shell */
index = g_strlen(self->wm->client_info->program);
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->program, index);
/* send directory */
index = g_strlen(self->wm->client_info->directory);
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->directory, index);
/* send client ip */
index = g_strlen(self->wm->client_info->client_ip);
out_uint16_be(s, index);
out_uint8a(s, self->wm->client_info->client_ip, index);
s_mark_end(s);
s_pop_layer(s, channel_hdr);
/* Version 0 of the protocol to sesman is currently used by XRDP */
out_uint32_be(s, 0); /* version */
index = (int)(s->end - s->data);
out_uint32_be(s, index); /* size */
rv = trans_force_write(self->sesman_trans);
if (rv != 0)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING,
"xrdp_mm_send_login: xrdp_mm_send_login failed");
}
return rv;
}
/*****************************************************************************/
/* returns error */
/* this goes through the login_names looking for one called 'aname'
then it copies the corresponding login_values item into 'dest'
'dest' must be at least 'dest_len' + 1 bytes in size */
static int
xrdp_mm_get_value(struct xrdp_mm *self, const char *aname, char *dest,
int dest_len)
{
char *name;
char *value;
int index;
int count;
int rv;
rv = 1;
/* find the library name */
dest[0] = 0;
count = self->login_names->count;
for (index = 0; index < count; index++)
{
name = (char *)list_get_item(self->login_names, index);
value = (char *)list_get_item(self->login_values, index);
if ((name == 0) || (value == 0))
{
break;
}
if (g_strcasecmp(name, aname) == 0)
{
g_strncpy(dest, value, dest_len);
rv = 0;
}
}
return rv;
}
/*****************************************************************************/
static int
xrdp_mm_setup_mod1(struct xrdp_mm *self)
{
void *func;
char lib[256];
char text[256];
if (self == 0)
{
return 1;
}
lib[0] = 0;
if (xrdp_mm_get_value(self, "lib", lib, 255) != 0)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"no library name specified in xrdp.ini, please add "
"lib=libxrdp-vnc.so or similar");
return 1;
}
if (lib[0] == 0)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"empty library name specified in xrdp.ini, please "
"add lib=libxrdp-vnc.so or similar");
return 1;
}
if (self->mod_handle == 0)
{
g_snprintf(text, 255, "%s/%s", XRDP_MODULE_PATH, lib);
/* Let the main thread load the lib,*/
self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (tintptr)text, 0);
if (self->mod_handle != 0)
{
func = g_get_proc_address(self->mod_handle, "mod_init");
if (func == 0)
{
func = g_get_proc_address(self->mod_handle, "_mod_init");
}
if (func == 0)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"error finding proc mod_init in %s, "
"not a valid xrdp backend", lib);
}
self->mod_init = (struct xrdp_mod * ( *)(void))func;
func = g_get_proc_address(self->mod_handle, "mod_exit");
if (func == 0)
{
func = g_get_proc_address(self->mod_handle, "_mod_exit");
}
if (func == 0)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"error finding proc mod_exit in %s, "
"not a valid xrdp backend", lib);
}
self->mod_exit = (int ( *)(struct xrdp_mod *))func;
if ((self->mod_init != 0) && (self->mod_exit != 0))
{
self->mod = self->mod_init();
if (self->mod != 0)
{
g_writeln("loaded module '%s' ok, interface size %d, version %d", lib,
self->mod->size, self->mod->version);
}
}
else
{
log_message(LOG_LEVEL_ERROR,"no mod_init or mod_exit address found");
}
}
else
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"error loading %s specified in xrdp.ini, please "
"add a valid entry like lib=libxrdp-vnc.so or "
"similar", lib);
return 1;
}
if (self->mod != 0)
{
self->mod->wm = (long)(self->wm);
self->mod->server_begin_update = server_begin_update;
self->mod->server_end_update = server_end_update;
self->mod->server_bell_trigger = server_bell_trigger;
self->mod->server_fill_rect = server_fill_rect;
self->mod->server_screen_blt = server_screen_blt;
self->mod->server_paint_rect = server_paint_rect;
self->mod->server_set_pointer = server_set_pointer;
self->mod->server_set_pointer_ex = server_set_pointer_ex;
self->mod->server_palette = server_palette;
self->mod->server_msg = server_msg;
self->mod->server_is_term = server_is_term;
self->mod->server_set_clip = server_set_clip;
self->mod->server_reset_clip = server_reset_clip;
self->mod->server_set_fgcolor = server_set_fgcolor;
self->mod->server_set_bgcolor = server_set_bgcolor;
self->mod->server_set_opcode = server_set_opcode;
self->mod->server_set_mixmode = server_set_mixmode;
self->mod->server_set_brush = server_set_brush;
self->mod->server_set_pen = server_set_pen;
self->mod->server_draw_line = server_draw_line;
self->mod->server_add_char = server_add_char;
self->mod->server_draw_text = server_draw_text;
self->mod->server_reset = server_reset;
self->mod->server_query_channel = server_query_channel;
self->mod->server_get_channel_id = server_get_channel_id;
self->mod->server_send_to_channel = server_send_to_channel;
self->mod->server_create_os_surface = server_create_os_surface;
self->mod->server_switch_os_surface = server_switch_os_surface;
self->mod->server_delete_os_surface = server_delete_os_surface;
self->mod->server_paint_rect_os = server_paint_rect_os;
self->mod->server_set_hints = server_set_hints;
self->mod->server_window_new_update = server_window_new_update;
self->mod->server_window_delete = server_window_delete;
self->mod->server_window_icon = server_window_icon;
self->mod->server_window_cached_icon = server_window_cached_icon;
self->mod->server_notify_new_update = server_notify_new_update;
self->mod->server_notify_delete = server_notify_delete;
self->mod->server_monitored_desktop = server_monitored_desktop;
self->mod->server_add_char_alpha = server_add_char_alpha;
self->mod->server_create_os_surface_bpp = server_create_os_surface_bpp;
self->mod->server_paint_rect_bpp = server_paint_rect_bpp;
self->mod->server_composite = server_composite;
self->mod->server_paint_rects = server_paint_rects;
self->mod->server_session_info = server_session_info;
self->mod->si = (tintptr) &(self->wm->session->si);
}
}
/* id self->mod is null, there must be a problem */
if (self->mod == 0)
{
DEBUG(("problem loading lib in xrdp_mm_setup_mod1"));
return 1;
}
return 0;
}
/*****************************************************************************/
static int
xrdp_mm_setup_mod2(struct xrdp_mm *self, tui8 *guid)
{
char text[256];
char raptortext[256];
const char *name;
const char *value;
int i;
int rv;
int key_flags;
int device_flags;
int use_uds;
rv = 1; /* failure */
g_memset(text, 0, sizeof(text));
if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event))
{
if (self->mod->mod_start(self->mod, self->wm->screen->width,
self->wm->screen->height,
self->wm->screen->bpp) != 0)
{
g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */
}
}
if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event))
{
if (self->display > 0)
{
if (self->code == 0) /* Xvnc */
{
g_snprintf(text, 255, "%d", 5900 + self->display);
}
else if (self->code == 10 || self->code == 20) /* X11rdp/Xorg */
{
char* rsmip = raptor_sm_get_ip_for_username(self->login_username, true);
if (strcmp(rsmip, "ERROR") == 0) {
g_snprintf(raptortext, 255, "[LICENSE] Instantaneous limit exceeded.");
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext);
g_snprintf(raptortext, 255, "[LICENSE] Login for user %s denied.", self->login_username);
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext);
g_free(rsmip);
raptor_sm_session_terminated(self->login_username);
return 1;
}
int allocdisplay = raptor_sm_get_display_for_username(self->login_username);
if ((raptor_sm_sesslimit_reached(self->login_username)) && (allocdisplay < 0)) {
g_snprintf(raptortext, 255, "[LICENSE] Maximum concurrent session");
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext);
g_snprintf(raptortext, 255, "[LICENSE] limit exceeded for group.");
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext);
g_snprintf(raptortext, 255, "[LICENSE] Login for user %s denied.", self->login_username);
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING, raptortext);
g_free(rsmip);
raptor_sm_session_terminated(self->login_username);
return 1;
}
else {
if (allocdisplay >= 0) {
self->display = allocdisplay;
}
self->mod->mod_set_param(self->mod, "ip", rsmip);
#ifdef DISABLE_UNIX_DOMAIN_SOCKETS
use_uds = 0;
#else
use_uds = 1;
if (g_strcmp(rsmip, "127.0.0.1") != 0) {
use_uds = 0;
}
#endif
}
g_free(rsmip);
if (use_uds)
{
g_snprintf(text, 255, XRDP_X11RDP_STR, self->display);
}
else
{
g_snprintf(text, 255, "%d", 6200 + self->display);
}
}
else
{
g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */
}
}
}
if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event))
{
/* this adds the port to the end of the list, it will already be in
the list as -1
the module should use the last one */
if (g_strlen(text) > 0)
{
list_add_item(self->login_names, (long)g_strdup("port"));
list_add_item(self->login_values, (long)g_strdup(text));
}
/* always set these */
self->mod->mod_set_param(self->mod, "client_info",
(const char *) (self->wm->session->client_info));
name = self->wm->session->client_info->hostname;
self->mod->mod_set_param(self->mod, "hostname", name);
g_snprintf(text, 255, "%d", self->wm->session->client_info->keylayout);
self->mod->mod_set_param(self->mod, "keylayout", text);
if (guid != 0)
{
self->mod->mod_set_param(self->mod, "guid", (char *) guid);
}
for (i = 0; i < self->login_names->count; i++)
{
name = (const char *) list_get_item(self->login_names, i);
value = (const char *) list_get_item(self->login_values, i);
if (strcmp(name, "ip") != 0) {
self->mod->mod_set_param(self->mod, name, value);
}
}
/* connect */
if (self->mod->mod_connect(self->mod) == 0)
{
rv = 0; /* connect success */
}
else
{
xrdp_wm_show_log(self->wm);
if (self->wm->hide_log_window)
{
rv = 1;
}
}
}
if (rv == 0)
{
/* sync modifiers */
key_flags = 0;
device_flags = 0;
if (self->wm->scroll_lock)
{
key_flags |= 1;
}
if (self->wm->num_lock)
{
key_flags |= 2;
}
if (self->wm->caps_lock)
{
key_flags |= 4;
}
if (self->mod != 0)
{
if (self->mod->mod_event != 0)
{
self->mod->mod_event(self->mod, 17, key_flags, device_flags,
key_flags, device_flags);
}
}
}
return rv;
}
/*****************************************************************************/
/* returns error
send a list of channels to the channel handler */
static int
xrdp_mm_trans_send_channel_setup(struct xrdp_mm *self, struct trans *trans)
{
int index;
int chan_id;
int chan_flags;
int size;
struct stream *s;
char chan_name[256];
g_memset(chan_name, 0, sizeof(char) * 256);
s = trans_get_out_s(trans, 8192);
if (s == 0)
{
return 1;
}
s_push_layer(s, iso_hdr, 8);
s_push_layer(s, mcs_hdr, 8);
s_push_layer(s, sec_hdr, 2);
index = 0;
while (libxrdp_query_channel(self->wm->session, index, chan_name,
&chan_flags) == 0)
{
chan_id = libxrdp_get_channel_id(self->wm->session, chan_name);
out_uint8a(s, chan_name, 8);
out_uint16_le(s, chan_id);
out_uint16_le(s, chan_flags);
index++;
}
s_mark_end(s);
s_pop_layer(s, sec_hdr);
out_uint16_le(s, index);
s_pop_layer(s, mcs_hdr);
size = (int)(s->end - s->p);
out_uint32_le(s, 3); /* msg id */
out_uint32_le(s, size); /* msg size */
s_pop_layer(s, iso_hdr);
size = (int)(s->end - s->p);
out_uint32_le(s, 0); /* version */
out_uint32_le(s, size); /* block size */
return trans_force_write(trans);
}
/*****************************************************************************/
/* returns error
data coming in from the channel handler, send it to the client */
static int
xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct stream *s)
{
int size;
int total_size;
int chan_id;
int chan_flags;
int rv;
in_uint16_le(s, chan_id);
in_uint16_le(s, chan_flags);
in_uint16_le(s, size);
in_uint32_le(s, total_size);
rv = 0;
if (rv == 0)
{
rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size,
chan_flags);
}
return rv;
}
/*****************************************************************************/
/* returns error
process rail create window order */
static int
xrdp_mm_process_rail_create_window(struct xrdp_mm* self, struct stream* s)
{
int flags;
int window_id;
int title_bytes;
int index;
int bytes;
int rv;
struct rail_window_state_order rwso;
g_memset(&rwso, 0, sizeof(rwso));
in_uint32_le(s, window_id);
g_writeln("xrdp_mm_process_rail_create_window: 0x%8.8x", window_id);
in_uint32_le(s, rwso.owner_window_id);
in_uint32_le(s, rwso.style);
in_uint32_le(s, rwso.extended_style);
in_uint32_le(s, rwso.show_state);
in_uint16_le(s, title_bytes);
if (title_bytes > 0)
{
rwso.title_info = g_new(char, title_bytes + 1);
in_uint8a(s, rwso.title_info, title_bytes);
rwso.title_info[title_bytes] = 0;
}
in_uint32_le(s, rwso.client_offset_x);
in_uint32_le(s, rwso.client_offset_y);
in_uint32_le(s, rwso.client_area_width);
in_uint32_le(s, rwso.client_area_height);
in_uint32_le(s, rwso.rp_content);
in_uint32_le(s, rwso.root_parent_handle);
in_uint32_le(s, rwso.window_offset_x);
in_uint32_le(s, rwso.window_offset_y);
in_uint32_le(s, rwso.window_client_delta_x);
in_uint32_le(s, rwso.window_client_delta_y);
in_uint32_le(s, rwso.window_width);
in_uint32_le(s, rwso.window_height);
in_uint16_le(s, rwso.num_window_rects);
if (rwso.num_window_rects > 0)
{
bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects;
rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0);
for (index = 0; index < rwso.num_window_rects; index++)
{
in_uint16_le(s, rwso.window_rects[index].left);
in_uint16_le(s, rwso.window_rects[index].top);
in_uint16_le(s, rwso.window_rects[index].right);
in_uint16_le(s, rwso.window_rects[index].bottom);
}
}
in_uint32_le(s, rwso.visible_offset_x);
in_uint32_le(s, rwso.visible_offset_y);
in_uint16_le(s, rwso.num_visibility_rects);
if (rwso.num_visibility_rects > 0)
{
bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects;
rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0);
for (index = 0; index < rwso.num_visibility_rects; index++)
{
in_uint16_le(s, rwso.visibility_rects[index].left);
in_uint16_le(s, rwso.visibility_rects[index].top);
in_uint16_le(s, rwso.visibility_rects[index].right);
in_uint16_le(s, rwso.visibility_rects[index].bottom);
}
}
in_uint32_le(s, flags);
rv = libxrdp_orders_init(self->wm->session);
if (rv == 0)
{
rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags);
}
if (rv == 0)
{
rv = libxrdp_orders_send(self->wm->session);
}
g_free(rwso.title_info);
g_free(rwso.window_rects);
g_free(rwso.visibility_rects);
return rv;
}
#if 0
/*****************************************************************************/
/* returns error
process rail configure window order */
static int
xrdp_mm_process_rail_configure_window(struct xrdp_mm* self, struct stream* s)
{
int flags;
int window_id;
int index;
int bytes;
int rv;
struct rail_window_state_order rwso;
g_memset(&rwso, 0, sizeof(rwso));
in_uint32_le(s, window_id);
g_writeln("xrdp_mm_process_rail_configure_window: 0x%8.8x", window_id);
in_uint32_le(s, rwso.client_offset_x);
in_uint32_le(s, rwso.client_offset_y);
in_uint32_le(s, rwso.client_area_width);
in_uint32_le(s, rwso.client_area_height);
in_uint32_le(s, rwso.rp_content);
in_uint32_le(s, rwso.root_parent_handle);
in_uint32_le(s, rwso.window_offset_x);
in_uint32_le(s, rwso.window_offset_y);
in_uint32_le(s, rwso.window_client_delta_x);
in_uint32_le(s, rwso.window_client_delta_y);
in_uint32_le(s, rwso.window_width);
in_uint32_le(s, rwso.window_height);
in_uint16_le(s, rwso.num_window_rects);
if (rwso.num_window_rects > 0)
{
bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects;
rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0);
for (index = 0; index < rwso.num_window_rects; index++)
{
in_uint16_le(s, rwso.window_rects[index].left);
in_uint16_le(s, rwso.window_rects[index].top);
in_uint16_le(s, rwso.window_rects[index].right);
in_uint16_le(s, rwso.window_rects[index].bottom);
}
}
in_uint32_le(s, rwso.visible_offset_x);
in_uint32_le(s, rwso.visible_offset_y);
in_uint16_le(s, rwso.num_visibility_rects);
if (rwso.num_visibility_rects > 0)
{
bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects;
rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0);
for (index = 0; index < rwso.num_visibility_rects; index++)
{
in_uint16_le(s, rwso.visibility_rects[index].left);
in_uint16_le(s, rwso.visibility_rects[index].top);
in_uint16_le(s, rwso.visibility_rects[index].right);
in_uint16_le(s, rwso.visibility_rects[index].bottom);
}
}
in_uint32_le(s, flags);
rv = libxrdp_orders_init(self->wm->session);
if (rv == 0)
{
rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags);
}
if (rv == 0)
{
rv = libxrdp_orders_send(self->wm->session);
}
g_free(rwso.window_rects);
g_free(rwso.visibility_rects);
return rv;
}
#endif
/*****************************************************************************/
/* returns error
process rail destroy window order */
static int
xrdp_mm_process_rail_destroy_window(struct xrdp_mm* self, struct stream* s)
{
int window_id;
int rv;
in_uint32_le(s, window_id);
g_writeln("xrdp_mm_process_rail_destroy_window 0x%8.8x", window_id);
rv = libxrdp_orders_init(self->wm->session);
if (rv == 0)
{
rv = libxrdp_window_delete(self->wm->session, window_id);
}
if (rv == 0)
{
rv = libxrdp_orders_send(self->wm->session);
}
return rv;
}
/*****************************************************************************/
/* returns error
process rail update window (show state) order */
static int
xrdp_mm_process_rail_show_window(struct xrdp_mm* self, struct stream* s)
{
int window_id;
int rv;
int flags;
struct rail_window_state_order rwso;
g_memset(&rwso, 0, sizeof(rwso));
in_uint32_le(s, window_id);
in_uint32_le(s, flags);
in_uint32_le(s, rwso.show_state);
g_writeln("xrdp_mm_process_rail_show_window 0x%8.8x %x", window_id,
rwso.show_state);
rv = libxrdp_orders_init(self->wm->session);
if (rv == 0)
{
rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags);
}
if (rv == 0)
{
rv = libxrdp_orders_send(self->wm->session);
}
return rv;
}
/*****************************************************************************/
/* returns error
process rail update window (title) order */
static int
xrdp_mm_process_rail_update_window_text(struct xrdp_mm* self, struct stream* s)
{
int size;
int flags;
int rv;
int window_id;
struct rail_window_state_order rwso;
g_writeln("xrdp_mm_process_rail_update_window_text:");
in_uint32_le(s, window_id);
in_uint32_le(s, flags);
g_writeln(" update window title info: 0x%8.8x", window_id);
g_memset(&rwso, 0, sizeof(rwso));
in_uint32_le(s, size); /* title size */
rwso.title_info = g_new(char, size + 1);
in_uint8a(s, rwso.title_info, size);
rwso.title_info[size] = 0;
g_writeln(" set window title %s size %d 0x%8.8x", rwso.title_info, size, flags);
rv = libxrdp_orders_init(self->wm->session);
if (rv == 0)
{
rv = libxrdp_window_new_update(self->wm->session, window_id, &rwso, flags);
}
if (rv == 0)
{
rv = libxrdp_orders_send(self->wm->session);
}
g_writeln(" set window title %s %d", rwso.title_info, rv);
g_free(rwso.title_info);
return rv;
}
/*****************************************************************************/
/* returns error
process alternate secondary drawing orders for rail channel */
static int
xrdp_mm_process_rail_drawing_orders(struct xrdp_mm* self, struct stream *s)
{
int order_type;
int rv;
rv = 0;
in_uint32_le(s, order_type);
switch(order_type)
{
case 2: /* create_window */
xrdp_mm_process_rail_create_window(self, s);
break;
case 4: /* destroy_window */
xrdp_mm_process_rail_destroy_window(self, s);
break;
case 6: /* show_window */
rv = xrdp_mm_process_rail_show_window(self, s);
break;
case 8: /* update title info */
rv = xrdp_mm_process_rail_update_window_text(self, s);
break;
default:
break;
}
return rv;
}
/******************************************************************************/
int
xrdp_mm_drdynvc_up(struct xrdp_mm* self)
{
LLOGLN(0, ("xrdp_mm_drdynvc_up:"));
return 0;
}
/*****************************************************************************/
/* open response from client going to channel server */
static int
xrdp_mm_drdynvc_open_response(intptr_t id, int chan_id, int creation_status)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
LLOGLN(10, ("xrdp_mm_drdynvc_open_response: chan_id %d creation_status %d",
chan_id, creation_status));
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 24); /* size */
out_uint32_le(s, 13); /* msg id */
out_uint32_le(s, 16); /* size */
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, creation_status); /* status */
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* close response from client going to channel server */
static int
xrdp_mm_drdynvc_close_response(intptr_t id, int chan_id)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 20); /* size */
out_uint32_le(s, 15); /* msg id */
out_uint32_le(s, 12); /* size */
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* part data from client going to channel server */
static int
xrdp_mm_drdynvc_data_first(intptr_t id, int chan_id, char *data,
int bytes, int total_bytes)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8 + 4 + 4 + 4 + bytes);
out_uint32_le(s, 17); /* msg id */
out_uint32_le(s, 8 + 4 + 4 + 4 + bytes);
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, bytes);
out_uint32_le(s, total_bytes);
out_uint8a(s, data, bytes);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* data from client going to channel server */
static int
xrdp_mm_drdynvc_data(intptr_t id, int chan_id, char *data, int bytes)
{
struct trans *trans;
struct stream *s;
struct xrdp_wm* wm;
struct xrdp_process *pro;
int chansrv_chan_id;
pro = (struct xrdp_process *) id;
wm = pro->wm;
trans = wm->mm->chan_trans;
s = trans_get_out_s(trans, 8192);
if (s == NULL)
{
return 1;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8 + 4 + 4 + bytes);
out_uint32_le(s, 19); /* msg id */
out_uint32_le(s, 8 + 4 + 4 + bytes);
chansrv_chan_id = wm->mm->xr2cr_cid_map[chan_id];
out_uint32_le(s, chansrv_chan_id);
out_uint32_le(s, bytes);
out_uint8a(s, data, bytes);
s_mark_end(s);
return trans_write_copy(trans);
}
/*****************************************************************************/
/* open message from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_channel_open(struct xrdp_mm* self,
struct stream *s)
{
int name_bytes;
int flags;
int error;
int chan_id;
int chansrv_chan_id;
char *name;
struct xrdp_drdynvc_procs procs;
if (!s_check_rem(s, 2))
{
return 1;
}
in_uint32_le(s, name_bytes);
if ((name_bytes < 1) || (name_bytes > 1024))
{
return 1;
}
name = g_new(char, name_bytes + 1);
if (name == NULL)
{
return 1;
}
if (!s_check_rem(s, name_bytes))
{
g_free(name);
return 1;
}
in_uint8a(s, name, name_bytes);
name[name_bytes] = 0;
if (!s_check_rem(s, 8))
{
g_free(name);
return 1;
}
in_uint32_le(s, flags);
in_uint32_le(s, chansrv_chan_id);
if (flags == 0)
{
/* open static channel, not supported */
g_free(name);
return 1;
}
else
{
/* dynamic channel */
g_memset(&procs, 0, sizeof(procs));
procs.open_response = xrdp_mm_drdynvc_open_response;
procs.close_response = xrdp_mm_drdynvc_close_response;
procs.data_first = xrdp_mm_drdynvc_data_first;
procs.data = xrdp_mm_drdynvc_data;
chan_id = 0;
error = libxrdp_drdynvc_open(self->wm->session, name, flags, &procs,
&chan_id);
if (error != 0)
{
g_free(name);
return 1;
}
self->xr2cr_cid_map[chan_id] = chansrv_chan_id;
self->cs2xr_cid_map[chansrv_chan_id] = chan_id;
}
g_free(name);
return 0;
}
/*****************************************************************************/
/* close message from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_channel_close(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
if (!s_check_rem(s, 4))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
/* close dynamic channel */
error = libxrdp_drdynvc_close(self->wm->session, chan_id);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* data from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_data_first(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
int data_bytes;
int total_bytes;
char *data;
if (!s_check_rem(s, 12))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
in_uint32_le(s, data_bytes);
in_uint32_le(s, total_bytes);
if ((!s_check_rem(s, data_bytes)))
{
return 1;
}
in_uint8p(s, data, data_bytes);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
error = libxrdp_drdynvc_data_first(self->wm->session, chan_id, data,
data_bytes, total_bytes);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* data from channel server going to client */
static int
xrdp_mm_trans_process_drdynvc_data(struct xrdp_mm* self,
struct stream *s)
{
int chansrv_chan_id;
int chan_id;
int error;
int data_bytes;
char *data;
if (!s_check_rem(s, 8))
{
return 1;
}
in_uint32_le(s, chansrv_chan_id);
in_uint32_le(s, data_bytes);
if ((!s_check_rem(s, data_bytes)))
{
return 1;
}
in_uint8p(s, data, data_bytes);
chan_id = self->cs2xr_cid_map[chansrv_chan_id];
error = libxrdp_drdynvc_data(self->wm->session, chan_id, data, data_bytes);
if (error != 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* returns error
process a message for the channel handler */
static int
xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans,
struct stream *s)
{
int rv;
int id;
int size;
char *next_msg;
char *s_end;
rv = 0;
while (s_check_rem(s, 8))
{
next_msg = s->p;
in_uint32_le(s, id);
in_uint32_le(s, size);
if (size < 8)
{
return 1;
}
if (!s_check_rem(s, size - 8))
{
return 1;
}
next_msg += size;
s_end = s->end;
s->end = next_msg;
LLOGLN(10, ("xrdp_mm_chan_process_msg: got msg id %d", id));
switch (id)
{
case 8: /* channel data */
rv = xrdp_mm_trans_process_channel_data(self, s);
break;
case 10: /* rail alternate secondary drawing orders */
rv = xrdp_mm_process_rail_drawing_orders(self, s);
break;
case 12:
rv = xrdp_mm_trans_process_drdynvc_channel_open(self, s);
break;
case 14:
rv = xrdp_mm_trans_process_drdynvc_channel_close(self, s);
break;
case 16:
rv = xrdp_mm_trans_process_drdynvc_data_first(self, s);
break;
case 18:
rv = xrdp_mm_trans_process_drdynvc_data(self, s);
break;
default:
log_message(LOG_LEVEL_ERROR,"xrdp_mm_chan_process_msg: unknown id %d", id);
break;
}
s->end = s_end;
if (rv != 0)
{
LLOGLN(0, ("xrdp_mm_chan_process_msg: error rv %d id %d", rv, id));
rv = 0;
}
s->p = next_msg;
}
return rv;
}
/*****************************************************************************/
/* this is callback from trans obj
returns error */
static int
xrdp_mm_chan_data_in(struct trans *trans)
{
struct xrdp_mm *self;
struct stream *s;
int size;
int error;
if (trans == 0)
{
return 1;
}
self = (struct xrdp_mm *)(trans->callback_data);
s = trans_get_in_s(trans);
if (s == 0)
{
return 1;
}
if (trans->extra_flags == 0)
{
in_uint8s(s, 4); /* id */
in_uint32_le(s, size);
LLOGLN(10, ("xrdp_mm_chan_data_in: got header, size %d", size));
if (size > 8)
{
self->chan_trans->header_size = size;
trans->extra_flags = 1;
return 0;
}
}
/* here, the entire message block is read in, process it */
error = xrdp_mm_chan_process_msg(self, trans, s);
self->chan_trans->header_size = 8;
trans->extra_flags = 0;
init_stream(s, 0);
LLOGLN(10, ("xrdp_mm_chan_data_in: got whole message, reset for "
"next header"));
return error;
}
/*****************************************************************************/
/* connect to chansrv */
static int
xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
{
int index;
self->usechansrv = 1;
/* connect channel redir */
#ifdef DISABLE_UNIX_DOMAIN_SOCKETS
if (0)
#else
if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0))
#endif
{
/* unix socket */
self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192);
}
else
{
/* tcp */
self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192);
}
self->chan_trans->is_term = g_is_term;
self->chan_trans->si = &(self->wm->session->si);
self->chan_trans->my_source = XRDP_SOURCE_CHANSRV;
self->chan_trans->trans_data_in = xrdp_mm_chan_data_in;
self->chan_trans->header_size = 8;
self->chan_trans->callback_data = self;
self->chan_trans->no_stream_init_on_data_in = 1;
self->chan_trans->extra_flags = 0;
/* try to connect up to 4 times */
for (index = 0; index < 4; index++)
{
if (trans_connect(self->chan_trans, ip, port, 3000) == 0)
{
self->chan_trans_up = 1;
break;
}
g_sleep(1000);
log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: connect failed "
"trying again...");
}
if (!(self->chan_trans_up))
{
log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in "
"trans_connect chan");
}
if (self->chan_trans_up)
{
if (xrdp_mm_trans_send_channel_setup(self, self->chan_trans) != 0)
{
log_message(LOG_LEVEL_ERROR,"xrdp_mm_connect_chansrv: error in "
"xrdp_mm_trans_send_channel_setup");
}
else
{
log_message(LOG_LEVEL_DEBUG,"xrdp_mm_connect_chansrv: chansrv "
"connect successful");
}
}
return 0;
}
static void cleanup_sesman_connection(struct xrdp_mm *self)
{
self->delete_sesman_trans = 1;
self->connected_state = 0;
if (self->wm->login_mode != 10)
{
xrdp_wm_set_login_mode(self->wm, 11);
xrdp_mm_module_cleanup(self);
}
}
/*****************************************************************************/
/* does the section in xrdp.ini has any channel.*=true | false */
static int
xrdp_mm_update_allowed_channels(struct xrdp_mm *self)
{
int index;
int count;
int chan_id;
int disabled;
const char *name;
const char *value;
const char *chan_name;
struct xrdp_session *session;
session = self->wm->session;
count = self->login_names->count;
for (index = 0; index < count; index++)
{
name = (const char *) list_get_item(self->login_names, index);
if (g_strncasecmp(name, "channel.", 8) == 0)
{
value = (const char *) list_get_item(self->login_values, index);
chan_name = name + 8;
chan_id = libxrdp_get_channel_id(session, chan_name);
disabled = !g_text2bool(value);
libxrdp_disable_channel(session, chan_id, disabled);
if (disabled)
{
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
"channel id %d is disabled", chan_name, chan_id);
}
else
{
g_writeln("xrdp_mm_update_allowed_channels: channel %s "
"channel id %d is allowed", chan_name, chan_id);
}
}
}
return 0;
}
/*****************************************************************************/
static int
xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s)
{
int ok;
int display;
int rv;
char ip[256];
char port[256];
tui8 guid[16];
tui8* pguid;
rv = 0;
in_uint16_be(s, ok);
in_uint16_be(s, display);
pguid = 0;
if (s_check_rem(s, 16))
{
in_uint8a(s, guid, 16);
pguid = guid;
}
if (ok)
{
self->display = display;
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "login successful on display %d", display);
if (xrdp_mm_setup_mod1(self) == 0)
{
if (xrdp_mm_setup_mod2(self, pguid) == 0)
{
xrdp_mm_get_value(self, "ip", ip, 255);
xrdp_wm_set_login_mode(self->wm, 10);
self->wm->dragging = 0;
/* connect channel redir */
#ifdef DISABLE_UNIX_DOMAIN_SOCKETS
if (0)
#else
if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0))
#endif
{
g_snprintf(port, 255, XRDP_CHANSRV_STR, display);
}
else
{
g_snprintf(port, 255, "%d", 7200 + display);
}
xrdp_mm_update_allowed_channels(self);
xrdp_mm_connect_chansrv(self, ip, port);
}
}
}
else
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"login failed for display %d", display);
xrdp_wm_show_log(self->wm);
if (self->wm->hide_log_window)
{
rv = 1;
}
}
cleanup_sesman_connection(self);
return rv;
}
/*****************************************************************************/
static int
xrdp_mm_get_sesman_port(char *port, int port_bytes)
{
int fd;
int error;
int index;
char *val;
char cfg_file[256];
struct list *names;
struct list *values;
g_memset(cfg_file, 0, sizeof(char) * 256);
/* default to port 3350 */
g_strncpy(port, "3350", port_bytes - 1);
/* see if port is in sesman.ini file */
g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH);
fd = g_file_open(cfg_file);
if (fd >= 0)
{
names = list_create();
names->auto_free = 1;
values = list_create();
values->auto_free = 1;
if (file_read_section(fd, "Globals", names, values) == 0)
{
for (index = 0; index < names->count; index++)
{
val = (char *)list_get_item(names, index);
if (val != 0)
{
if (g_strcasecmp(val, "ListenPort") == 0)
{
val = (char *)list_get_item(values, index);
error = g_atoi(val);
if ((error > 0) && (error < 65000))
{
g_strncpy(port, val, port_bytes - 1);
}
break;
}
}
}
}
list_delete(names);
list_delete(values);
g_file_close(fd);
}
return 0;
}
/*****************************************************************************/
/* returns error
data coming from client that need to go to channel handler */
int
xrdp_mm_process_channel_data(struct xrdp_mm *self, tbus param1, tbus param2,
tbus param3, tbus param4)
{
struct stream *s;
int rv;
int length;
int total_length;
int flags;
int id;
char *data;
rv = 0;
if ((self->chan_trans != 0) && self->chan_trans_up)
{
s = trans_get_out_s(self->chan_trans, 8192);
if (s != 0)
{
id = LOWORD(param1);
flags = HIWORD(param1);
length = param2;
data = (char *)param3;
total_length = param4;
if (total_length < length)
{
log_message(LOG_LEVEL_DEBUG,"WARNING in xrdp_mm_process_channel_data(): total_len < length");
total_length = length;
}
out_uint32_le(s, 0); /* version */
out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + length);
out_uint32_le(s, 5); /* msg id */
out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + length);
out_uint16_le(s, id);
out_uint16_le(s, flags);
out_uint16_le(s, length);
out_uint32_le(s, total_length);
out_uint8a(s, data, length);
s_mark_end(s);
rv = trans_force_write(self->chan_trans);
}
}
return rv;
}
/*****************************************************************************/
/* This is the callback registered for sesman communication replies. */
static int
xrdp_mm_sesman_data_in(struct trans *trans)
{
struct xrdp_mm *self;
struct stream *s;
int version;
int size;
int error;
int code;
if (trans == 0)
{
return 1;
}
self = (struct xrdp_mm *)(trans->callback_data);
s = trans_get_in_s(trans);
if (s == 0)
{
return 1;
}
in_uint32_be(s, version);
in_uint32_be(s, size);
error = trans_force_read(trans, size - 8);
if (error == 0)
{
in_uint16_be(s, code);
switch (code)
{
/* even when the request is denied the reply will hold 3 as the command. */
case 3:
error = xrdp_mm_process_login_response(self, s);
break;
default:
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Undefined reply code %d received from sesman",
code);
cleanup_sesman_connection(self);
break;
}
}
return error;
}
#ifndef USE_NOPAM
/*********************************************************************/
/* return 0 on success */
static int
access_control(char *username, char *password, char *srv)
{
int reply;
int rec = 32+1; /* 32 is reserved for PAM failures this means connect failure */
struct stream *in_s;
struct stream *out_s;
unsigned long version;
unsigned short int dummy;
unsigned short int pAM_errorcode;
unsigned short int code;
unsigned long size;
int index;
int socket = g_tcp_socket();
char port[8];
if (socket != -1)
{
xrdp_mm_get_sesman_port(port, sizeof(port));
/* we use a blocking socket here */
reply = g_tcp_connect(socket, srv, port);
if (reply == 0)
{
make_stream(in_s);
init_stream(in_s, 500);
make_stream(out_s);
init_stream(out_s, 500);
s_push_layer(out_s, channel_hdr, 8);
out_uint16_be(out_s, 4); /*0x04 means SCP_GW_AUTHENTICATION*/
index = g_strlen(username);
out_uint16_be(out_s, index);
out_uint8a(out_s, username, index);
index = g_strlen(password);
out_uint16_be(out_s, index);
out_uint8a(out_s, password, index);
s_mark_end(out_s);
s_pop_layer(out_s, channel_hdr);
out_uint32_be(out_s, 0); /* version */
index = (int)(out_s->end - out_s->data);
out_uint32_be(out_s, index); /* size */
/* g_writeln("Number of data to send : %d",index); */
reply = g_tcp_send(socket, out_s->data, index, 0);
free_stream(out_s);
if (reply > 0)
{
/* We wait in 5 sec for a reply from sesman*/
if (g_sck_can_recv(socket, 5000))
{
reply = g_tcp_recv(socket, in_s->end, 500, 0);
if (reply > 0)
{
in_s->end = in_s->end + reply;
in_uint32_be(in_s, version);
/*g_writeln("Version number in reply from sesman: %d",version) ; */
in_uint32_be(in_s, size);
if ((size == 14) && (version == 0))
{
in_uint16_be(in_s, code);
in_uint16_be(in_s, pAM_errorcode); /* this variable holds the PAM error code if the variable is >32 it is a "invented" code */
in_uint16_be(in_s, dummy);
if (code != 4) /*0x04 means SCP_GW_AUTHENTICATION*/
{
log_message(LOG_LEVEL_ERROR, "Returned cmd code from "
"sesman is corrupt");
}
else
{
rec = pAM_errorcode; /* here we read the reply from the access control */
}
}
else
{
log_message(LOG_LEVEL_ERROR, "Corrupt reply size or "
"version from sesman: %ld", size);
}
}
else
{
log_message(LOG_LEVEL_ERROR, "No data received from sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR, "Timeout when waiting for sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR, "No success sending to sesman");
}
free_stream(in_s);
g_tcp_close(socket);
}
else
{
log_message(LOG_LEVEL_ERROR, "Failure connecting to socket sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR, "Failure creating socket - for access control");
}
if (socket != -1)
g_tcp_close(socket);
return rec;
}
#endif
/*****************************************************************************/
/* This routine clears all states to make sure that our next login will be
* as expected. If the user does not press ok on the log window and try to
* connect again we must make sure that no previous information is stored.*/
static void
cleanup_states(struct xrdp_mm *self)
{
if (self != NULL)
{
self-> connected_state = 0; /* true if connected to sesman else false */
self-> sesman_trans = NULL; /* connection to sesman */
self-> sesman_trans_up = 0; /* true once connected to sesman */
self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */
self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */
self-> code = 0; /* 0 Xvnc session, 10 X11rdp session, 20 Xorg session */
self-> sesman_controlled = 0; /* true if this is a sesman session */
self-> chan_trans = NULL; /* connection to chansrv */
self-> chan_trans_up = 0; /* true once connected to chansrv */
self-> delete_chan_trans = 0; /* boolean set when done with channel connection */
self-> usechansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */
}
}
#ifndef USE_NOPAM
static const char *
getPAMError(const int pamError, char *text, int text_bytes)
{
switch (pamError)
{
#if defined(LINUXPAM)
case PAM_SUCCESS:
return "Success";
case PAM_OPEN_ERR:
return "dlopen() failure";
case PAM_SYMBOL_ERR:
return "Symbol not found";
case PAM_SERVICE_ERR:
return "Error in service module";
case PAM_SYSTEM_ERR:
return "System error";
case PAM_BUF_ERR:
return "Memory buffer error";
case PAM_PERM_DENIED:
return "Permission denied";
case PAM_AUTH_ERR:
return "Authentication failure";
case PAM_CRED_INSUFFICIENT:
return "Insufficient credentials to access authentication data";
case PAM_AUTHINFO_UNAVAIL:
return "Authentication service cannot retrieve authentication info.";
case PAM_USER_UNKNOWN:
return "User not known to the underlying authentication module";
case PAM_MAXTRIES:
return "Have exhausted maximum number of retries for service.";
case PAM_NEW_AUTHTOK_REQD:
return "Authentication token is no longer valid; new one required.";
case PAM_ACCT_EXPIRED:
return "User account has expired";
case PAM_CRED_UNAVAIL:
return "Authentication service cannot retrieve user credentials";
case PAM_CRED_EXPIRED:
return "User credentials expired";
case PAM_CRED_ERR:
return "Failure setting user credentials";
case PAM_NO_MODULE_DATA:
return "No module specific data is present";
case PAM_BAD_ITEM:
return "Bad item passed to pam_*_item()";
case PAM_CONV_ERR:
return "Conversation error";
case PAM_AUTHTOK_ERR:
return "Authentication token manipulation error";
case PAM_AUTHTOK_LOCK_BUSY:
return "Authentication token lock busy";
case PAM_AUTHTOK_DISABLE_AGING:
return "Authentication token aging disabled";
case PAM_TRY_AGAIN:
return "Failed preliminary check by password service";
case PAM_IGNORE:
return "Please ignore underlying account module";
case PAM_MODULE_UNKNOWN:
return "Module is unknown";
case PAM_AUTHTOK_EXPIRED:
return "Authentication token expired";
case PAM_CONV_AGAIN:
return "Conversation is waiting for event";
case PAM_INCOMPLETE:
return "Application needs to call libpam again";
case 32 + 1:
return "Error connecting to PAM";
case 32 + 3:
return "Username okey but group problem";
default:
g_snprintf(text, text_bytes, "Not defined PAM error:%d", pamError);
return text;
#elif defined(OPENPAM)
case PAM_SUCCESS: /* 0 */
return "Success";
case PAM_OPEN_ERR:
return "dlopen() failure";
case PAM_SYMBOL_ERR:
return "Symbol not found";
case PAM_SERVICE_ERR:
return "Error in service module";
case PAM_SYSTEM_ERR:
return "System error";
case PAM_BUF_ERR:
return "Memory buffer error";
case PAM_CONV_ERR:
return "Conversation error";
case PAM_PERM_DENIED:
return "Permission denied";
case PAM_MAXTRIES:
return "Have exhausted maximum number of retries for service.";
case PAM_AUTH_ERR:
return "Authentication failure";
case PAM_NEW_AUTHTOK_REQD: /* 10 */
return "Authentication token is no longer valid; new one required.";
case PAM_CRED_INSUFFICIENT:
return "Insufficient credentials to access authentication data";
case PAM_AUTHINFO_UNAVAIL:
return "Authentication service cannot retrieve authentication info.";
case PAM_USER_UNKNOWN:
return "User not known to the underlying authentication module";
case PAM_CRED_UNAVAIL:
return "Authentication service cannot retrieve user credentials";
case PAM_CRED_EXPIRED:
return "User credentials expired";
case PAM_CRED_ERR:
return "Failure setting user credentials";
case PAM_ACCT_EXPIRED:
return "User account has expired";
case PAM_AUTHTOK_EXPIRED:
return "Authentication token expired";
case PAM_SESSION_ERR:
return "Session failure";
case PAM_AUTHTOK_ERR: /* 20 */
return "Authentication token manipulation error";
case PAM_AUTHTOK_RECOVERY_ERR:
return "Failed to recover old authentication token";
case PAM_AUTHTOK_LOCK_BUSY:
return "Authentication token lock busy";
case PAM_AUTHTOK_DISABLE_AGING:
return "Authentication token aging disabled";
case PAM_NO_MODULE_DATA:
return "No module specific data is present";
case PAM_IGNORE:
return "Please ignore underlying account module";
case PAM_ABORT:
return "General failure";
case PAM_TRY_AGAIN:
return "Failed preliminary check by password service";
case PAM_MODULE_UNKNOWN:
return "Module is unknown";
case PAM_DOMAIN_UNKNOWN: /* 29 */
return "Unknown authentication domain";
default:
g_snprintf(text, text_bytes, "Not defined PAM error:%d", pamError);
return text;
#endif
}
}
static const char *
getPAMAdditionalErrorInfo(const int pamError, struct xrdp_mm *self)
{
switch (pamError)
{
#if defined(LINUXPAM)
case PAM_SUCCESS:
return NULL;
case PAM_OPEN_ERR:
case PAM_SYMBOL_ERR:
case PAM_SERVICE_ERR:
case PAM_SYSTEM_ERR:
case PAM_BUF_ERR:
case PAM_PERM_DENIED:
case PAM_AUTH_ERR:
case PAM_CRED_INSUFFICIENT:
case PAM_AUTHINFO_UNAVAIL:
case PAM_USER_UNKNOWN:
case PAM_CRED_UNAVAIL:
case PAM_CRED_ERR:
case PAM_NO_MODULE_DATA:
case PAM_BAD_ITEM:
case PAM_CONV_ERR:
case PAM_AUTHTOK_ERR:
case PAM_AUTHTOK_LOCK_BUSY:
case PAM_AUTHTOK_DISABLE_AGING:
case PAM_TRY_AGAIN:
case PAM_IGNORE:
case PAM_MODULE_UNKNOWN:
case PAM_CONV_AGAIN:
case PAM_INCOMPLETE:
case _PAM_RETURN_VALUES + 1:
case _PAM_RETURN_VALUES + 3:
return NULL;
case PAM_MAXTRIES:
case PAM_NEW_AUTHTOK_REQD:
case PAM_ACCT_EXPIRED:
case PAM_CRED_EXPIRED:
case PAM_AUTHTOK_EXPIRED:
if (self->wm->pamerrortxt[0])
{
return self->wm->pamerrortxt;
}
else
{
return "Authentication error - Verify that user/password is valid";
}
default:
return "No expected error";
#elif defined(OPENPAM)
case PAM_SUCCESS: /* 0 */
return NULL;
case PAM_OPEN_ERR:
case PAM_SYMBOL_ERR:
case PAM_SERVICE_ERR:
case PAM_SYSTEM_ERR:
case PAM_BUF_ERR:
case PAM_CONV_ERR:
case PAM_PERM_DENIED:
case PAM_MAXTRIES:
case PAM_AUTH_ERR:
case PAM_NEW_AUTHTOK_REQD: /* 10 */
case PAM_CRED_INSUFFICIENT:
case PAM_AUTHINFO_UNAVAIL:
case PAM_USER_UNKNOWN:
case PAM_CRED_UNAVAIL:
case PAM_CRED_EXPIRED:
case PAM_CRED_ERR:
case PAM_ACCT_EXPIRED:
case PAM_AUTHTOK_EXPIRED:
case PAM_SESSION_ERR:
case PAM_AUTHTOK_ERR: /* 20 */
case PAM_AUTHTOK_RECOVERY_ERR:
case PAM_AUTHTOK_LOCK_BUSY:
case PAM_AUTHTOK_DISABLE_AGING:
case PAM_NO_MODULE_DATA:
case PAM_IGNORE:
case PAM_ABORT:
case PAM_TRY_AGAIN:
case PAM_MODULE_UNKNOWN:
case PAM_DOMAIN_UNKNOWN: /* 29 */
if (self->wm->pamerrortxt[0])
{
return self->wm->pamerrortxt;
}
else
{
return "Authentication error - Verify that user/password is valid";
}
default:
return "No expected error";
#endif
}
}
#endif
/*****************************************************************************/
int
xrdp_mm_connect(struct xrdp_mm *self)
{
struct list *names;
struct list *values;
int index;
int count;
int ok;
int rv;
char *name;
char *value;
char ip[256];
char port[8];
char chansrvport[256];
#ifndef USE_NOPAM
int use_pam_auth = 0;
char pam_auth_sessionIP[256];
char pam_auth_password[256];
char pam_auth_username[256];
#endif
char username[256];
char password[256];
username[0] = 0;
password[0] = 0;
/* make sure we start in correct state */
cleanup_states(self);
g_memset(ip, 0, sizeof(ip));
g_memset(port, 0, sizeof(port));
g_memset(chansrvport, 0, sizeof(chansrvport));
rv = 0; /* success */
names = self->login_names;
values = self->login_values;
count = names->count;
for (index = 0; index < count; index++)
{
name = (char *)list_get_item(names, index);
value = (char *)list_get_item(values, index);
if (g_strcasecmp(name, "ip") == 0)
{
g_strncpy(ip, value, 255);
}
else if (g_strcasecmp(name, "port") == 0)
{
if (g_strcasecmp(value, "-1") == 0)
{
self->sesman_controlled = 1;
}
}
#ifndef USE_NOPAM
else if (g_strcasecmp(name, "pamusername") == 0)
{
use_pam_auth = 1;
g_strncpy(pam_auth_username, value, 255);
}
else if (g_strcasecmp(name, "pamsessionmng") == 0)
{
g_strncpy(pam_auth_sessionIP, value, 255);
}
else if (g_strcasecmp(name, "pampassword") == 0)
{
g_strncpy(pam_auth_password, value, 255);
}
#endif
else if (g_strcasecmp(name, "password") == 0)
{
g_strncpy(password, value, 255);
}
else if (g_strcasecmp(name, "username") == 0)
{
g_strncpy(username, value, 255);
}
else if (g_strcasecmp(name, "chansrvport") == 0)
{
g_strncpy(chansrvport, value, 255);
self->usechansrv = 1;
}
}
#ifndef USE_NOPAM
if (use_pam_auth)
{
int reply;
char pam_error[128];
const char *additionalError;
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"Please wait, we now perform access control...");
/* g_writeln("we use pam modules to check if we can approve this user"); */
if (!g_strncmp(pam_auth_username, "same", 255))
{
log_message(LOG_LEVEL_DEBUG, "pamusername copied from username - same: %s", username);
g_strncpy(pam_auth_username, username, 255);
}
if (!g_strncmp(pam_auth_password, "same", 255))
{
log_message(LOG_LEVEL_DEBUG, "pam_auth_password copied from username - same: %s", password);
g_strncpy(pam_auth_password, password, 255);
}
/* access_control return 0 on success */
reply = access_control(pam_auth_username, pam_auth_password, pam_auth_sessionIP);
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Reply from access control: %s",
getPAMError(reply, pam_error, 127));
additionalError = getPAMAdditionalErrorInfo(reply, self);
if (additionalError && additionalError[0])
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s", additionalError);
}
if (reply != 0)
{
rv = 1;
return rv;
}
}
#endif
if (self->sesman_controlled)
{
ok = 0;
trans_delete(self->sesman_trans);
self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192);
self->sesman_trans->is_term = g_is_term;
xrdp_mm_get_sesman_port(port, sizeof(port));
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"connecting to sesman ip %s port %s", ip, port);
/* xrdp_mm_sesman_data_in is the callback that is called when data arrives */
self->sesman_trans->trans_data_in = xrdp_mm_sesman_data_in;
self->sesman_trans->header_size = 8;
self->sesman_trans->callback_data = self;
/* try to connect up to 4 times */
for (index = 0; index < 4; index++)
{
if (trans_connect(self->sesman_trans, ip, port, 3000) == 0)
{
self->sesman_trans_up = 1;
ok = 1;
break;
}
g_sleep(1000);
g_writeln("xrdp_mm_connect: connect failed "
"trying again...");
}
if (ok)
{
/* fully connect */
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "sesman connect ok");
self->connected_state = 1;
rv = xrdp_mm_send_login(self);
}
else
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Error connecting to sesman: %s port: %s",
ip, port);
trans_delete(self->sesman_trans);
self->sesman_trans = 0;
self->sesman_trans_up = 0;
rv = 1;
}
}
else /* no sesman */
{
if (xrdp_mm_setup_mod1(self) == 0)
{
if (xrdp_mm_setup_mod2(self, 0) == 0)
{
xrdp_wm_set_login_mode(self->wm, 10);
rv = 0; /*success*/
}
else
{
/* connect error */
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Error connecting to: %s", ip);
rv = 1; /* failure */
}
}
else
{
log_message(LOG_LEVEL_ERROR,"Failure setting up module");
}
if (self->wm->login_mode != 10)
{
xrdp_wm_set_login_mode(self->wm, 11);
xrdp_mm_module_cleanup(self);
rv = 1; /* failure */
}
}
if ((self->wm->login_mode == 10) && (self->sesman_controlled == 0) &&
(self->usechansrv != 0))
{
/* if sesman controlled, this will connect later */
xrdp_mm_connect_chansrv(self, "", chansrvport);
}
log_message(LOG_LEVEL_DEBUG,"return value from xrdp_mm_connect %d", rv);
return rv;
}
/*****************************************************************************/
int
xrdp_mm_get_wait_objs(struct xrdp_mm *self,
tbus *read_objs, int *rcount,
tbus *write_objs, int *wcount, int *timeout)
{
int rv = 0;
if (self == 0)
{
return 0;
}
rv = 0;
if ((self->sesman_trans != 0) && self->sesman_trans_up)
{
trans_get_wait_objs(self->sesman_trans, read_objs, rcount);
}
if ((self->chan_trans != 0) && self->chan_trans_up)
{
trans_get_wait_objs_rw(self->chan_trans, read_objs, rcount,
write_objs, wcount, timeout);
}
if (self->mod != 0)
{
if (self->mod->mod_get_wait_objs != 0)
{
rv = self->mod->mod_get_wait_objs(self->mod, read_objs, rcount,
write_objs, wcount, timeout);
}
}
if (self->encoder != 0)
{
read_objs[(*rcount)++] = self->encoder->xrdp_encoder_event_processed;
}
return rv;
}
#define DUMP_JPEG 0
#if DUMP_JPEG
/*****************************************************************************/
static int
xrdp_mm_dump_jpeg(struct xrdp_mm *self, XRDP_ENC_DATA_DONE *enc_done)
{
static tbus ii;
static int jj;
struct _header
{
char tag[4];
int width;
int height;
int bytes_follow;
} header;
tui16 *pheader_bytes;
int cx;
int cy;
pheader_bytes = (tui16 *) (enc_done->comp_pad_data + enc_done->pad_bytes);
cx = enc_done->enc->crects[enc_done->index * 4 + 2];
cy = enc_done->enc->crects[enc_done->index * 4 + 3];
header.tag[0] = 'B';
header.tag[1] = 'E';
header.tag[2] = 'E';
header.tag[3] = 'F';
header.width = cx;
header.height = cy;
header.bytes_follow = enc_done->comp_bytes - (2 + pheader_bytes[0]);
if (ii == 0)
{
ii = g_file_open("/tmp/jpeg.beef.bin");
if (ii == -1)
{
ii = 0;
}
}
if (ii != 0)
{
g_file_write(ii, (char*)&header, sizeof(header));
g_file_write(ii, enc_done->comp_pad_data +
enc_done->pad_bytes + 2 + pheader_bytes[0],
enc_done->comp_bytes - (2 + pheader_bytes[0]));
jj++;
g_writeln("dumping jpeg index %d", jj);
}
return 0;
}
#endif
/*****************************************************************************/
int
xrdp_mm_check_chan(struct xrdp_mm *self)
{
//g_writeln("xrdp_mm_check_chan:");
if ((self->chan_trans != 0) && self->chan_trans_up)
{
if (trans_check_wait_objs(self->chan_trans) != 0)
{
self->delete_chan_trans = 1;
}
}
if (self->delete_chan_trans)
{
trans_delete(self->chan_trans);
self->chan_trans = 0;
self->chan_trans_up = 0;
self->delete_chan_trans = 0;
}
return 0;
}
/*****************************************************************************/
static int
xrdp_mm_update_module_frame_ack(struct xrdp_mm *self)
{
int fif;
struct xrdp_encoder *encoder;
encoder = self->encoder;
fif = encoder->frames_in_flight;
if (encoder->frame_id_client + fif > encoder->frame_id_server)
{
if (encoder->frame_id_server > encoder->frame_id_server_sent)
{
LLOGLN(10, ("xrdp_mm_update_module_ack: frame_id_server %d",
encoder->frame_id_server));
encoder->frame_id_server_sent = encoder->frame_id_server;
self->mod->mod_frame_ack(self->mod, 0, encoder->frame_id_server);
}
}
return 0;
}
/*****************************************************************************/
static int
xrdp_mm_process_enc_done(struct xrdp_mm *self)
{
XRDP_ENC_DATA_DONE *enc_done;
int x;
int y;
int cx;
int cy;
while (1)
{
tc_mutex_lock(self->encoder->mutex);
enc_done = (XRDP_ENC_DATA_DONE *)
fifo_remove_item(self->encoder->fifo_processed);
tc_mutex_unlock(self->encoder->mutex);
if (enc_done == NULL)
{
break;
}
/* do something with msg */
LLOGLN(10, ("xrdp_mm_process_enc_done: message back bytes %d",
enc_done->comp_bytes));
x = enc_done->x;
y = enc_done->y;
cx = enc_done->cx;
cy = enc_done->cy;
if (enc_done->comp_bytes > 0)
{
libxrdp_fastpath_send_frame_marker(self->wm->session, 0,
enc_done->enc->frame_id);
libxrdp_fastpath_send_surface(self->wm->session,
enc_done->comp_pad_data,
enc_done->pad_bytes,
enc_done->comp_bytes,
x, y, x + cx, y + cy,
32, self->encoder->codec_id,
cx, cy);
libxrdp_fastpath_send_frame_marker(self->wm->session, 1,
enc_done->enc->frame_id);
}
/* free enc_done */
if (enc_done->last)
{
LLOGLN(10, ("xrdp_mm_process_enc_done: last set"));
if (self->wm->client_info->use_frame_acks == 0)
{
self->mod->mod_frame_ack(self->mod,
enc_done->enc->flags,
enc_done->enc->frame_id);
}
else
{
self->encoder->frame_id_server = enc_done->enc->frame_id;
xrdp_mm_update_module_frame_ack(self);
}
g_free(enc_done->enc->drects);
g_free(enc_done->enc->crects);
g_free(enc_done->enc);
}
g_free(enc_done->comp_pad_data);
g_free(enc_done);
}
return 0;
}
/*****************************************************************************/
int
xrdp_mm_check_wait_objs(struct xrdp_mm *self)
{
int rv;
if (self == 0)
{
return 0;
}
rv = 0;
if ((self->sesman_trans != NULL) && self->sesman_trans_up)
{
if (trans_check_wait_objs(self->sesman_trans) != 0)
{
self->delete_sesman_trans = 1;
if (self->wm->hide_log_window)
{
/* if hide_log_window, this is fatal */
rv = 1;
}
}
}
if ((self->chan_trans != NULL) && self->chan_trans_up)
{
if (trans_check_wait_objs(self->chan_trans) != 0)
{
self->delete_chan_trans = 1;
}
}
if (self->mod != NULL)
{
if (self->mod->mod_check_wait_objs != NULL)
{
rv = self->mod->mod_check_wait_objs(self->mod);
}
}
if (self->delete_sesman_trans)
{
trans_delete(self->sesman_trans);
self->sesman_trans = NULL;
self->sesman_trans_up = 0;
self->delete_sesman_trans = 0;
}
if (self->delete_chan_trans)
{
trans_delete(self->chan_trans);
self->chan_trans = NULL;
self->chan_trans_up = 0;
self->delete_chan_trans = 0;
}
if (self->encoder != NULL)
{
if (g_is_wait_obj_set(self->encoder->xrdp_encoder_event_processed))
{
g_reset_wait_obj(self->encoder->xrdp_encoder_event_processed);
xrdp_mm_process_enc_done(self);
}
}
return rv;
}
/*****************************************************************************/
/* frame ack from client */
int
xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id)
{
struct xrdp_encoder *encoder;
LLOGLN(10, ("xrdp_mm_frame_ack:"));
if (self->wm->client_info->use_frame_acks == 0)
{
return 1;
}
encoder = self->encoder;
LLOGLN(10, ("xrdp_mm_frame_ack: incoming %d, client %d, server %d",
frame_id, encoder->frame_id_client, encoder->frame_id_server));
if ((frame_id < 0) || (frame_id > encoder->frame_id_server))
{
/* if frame_id is negative or bigger then what server last sent
just ack all sent frames */
/* some clients can send big number just to clear all
pending frames */
encoder->frame_id_client = encoder->frame_id_server;
}
else
{
/* frame acks can come out of order so ignore older one */
encoder->frame_id_client = MAX(frame_id, encoder->frame_id_client);
}
xrdp_mm_update_module_frame_ack(self);
return 0;
}
#if 0
/*****************************************************************************/
struct xrdp_painter *
get_painter(struct xrdp_mod *mod)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
wm = (struct xrdp_wm *)(mod->wm);
p = xrdp_painter_create(wm, wm->session);
mod->painter = (tintptr)p;
}
return p;
}
#endif
/*****************************************************************************/
int
server_begin_update(struct xrdp_mod *mod)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
wm = (struct xrdp_wm *)(mod->wm);
p = xrdp_painter_create(wm, wm->session);
xrdp_painter_begin_update(p);
mod->painter = (long)p;
return 0;
}
/*****************************************************************************/
int
server_end_update(struct xrdp_mod *mod)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
xrdp_painter_end_update(p);
xrdp_painter_delete(p);
mod->painter = 0;
return 0;
}
/*****************************************************************************/
/* got bell signal... try to send to client */
int
server_bell_trigger(struct xrdp_mod *mod)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
xrdp_wm_send_bell(wm);
return 0;
}
/*****************************************************************************/
int
server_fill_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
xrdp_painter_fill_rect(p, wm->target_surface, x, y, cx, cy);
return 0;
}
/*****************************************************************************/
int
server_screen_blt(struct xrdp_mod *mod, int x, int y, int cx, int cy,
int srcx, int srcy)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
p->rop = 0xcc;
xrdp_painter_copy(p, wm->screen, wm->target_surface, x, y, cx, cy, srcx, srcy);
return 0;
}
/*****************************************************************************/
int
server_paint_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy,
char *data, int width, int height, int srcx, int srcy)
{
struct xrdp_wm *wm;
struct xrdp_bitmap *b;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp, data, wm);
xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy);
xrdp_bitmap_delete(b);
return 0;
}
/*****************************************************************************/
int
server_paint_rect_bpp(struct xrdp_mod* mod, int x, int y, int cx, int cy,
char* data, int width, int height, int srcx, int srcy,
int bpp)
{
struct xrdp_wm* wm;
struct xrdp_bitmap* b;
struct xrdp_painter* p;
p = (struct xrdp_painter*)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm*)(mod->wm);
b = xrdp_bitmap_create_with_data(width, height, bpp, data, wm);
xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy);
xrdp_bitmap_delete(b);
return 0;
}
/*****************************************************************************/
int
server_composite(struct xrdp_mod* mod, int srcidx, int srcformat,
int srcwidth, int srcrepeat, int* srctransform,
int mskflags, int mskidx, int mskformat, int mskwidth,
int mskrepeat, int op, int srcx, int srcy,
int mskx, int msky, int dstx, int dsty,
int width, int height, int dstformat)
{
struct xrdp_wm* wm;
struct xrdp_bitmap* b;
struct xrdp_bitmap* msk;
struct xrdp_painter* p;
struct xrdp_os_bitmap_item* bi;
p = (struct xrdp_painter*)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm*)(mod->wm);
b = 0;
msk = 0;
bi = xrdp_cache_get_os_bitmap(wm->cache, srcidx);
if (bi != 0)
{
b = bi->bitmap;
}
if (mskflags & 1)
{
bi = xrdp_cache_get_os_bitmap(wm->cache, mskidx);
if (bi != 0)
{
msk = bi->bitmap;
}
}
if (b != 0)
{
xrdp_painter_composite(p, b, srcformat, srcwidth, srcrepeat,
wm->target_surface, srctransform,
mskflags, msk, mskformat, mskwidth, mskrepeat,
op, srcx, srcy, mskx, msky, dstx, dsty,
width, height, dstformat);
}
else
{
g_writeln("server_composite: error finding id %d or %d", srcidx, mskidx);
}
return 0;
}
/*****************************************************************************/
int
server_paint_rects(struct xrdp_mod* mod, int num_drects, short *drects,
int num_crects, short *crects, char *data, int width,
int height, int flags, int frame_id)
{
struct xrdp_wm* wm;
struct xrdp_mm* mm;
struct xrdp_painter* p;
struct xrdp_bitmap *b;
short *s;
int index;
XRDP_ENC_DATA *enc_data;
wm = (struct xrdp_wm*)(mod->wm);
mm = wm->mm;
LLOGLN(10, ("server_paint_rects:"));
LLOGLN(10, ("server_paint_rects: %p", mm->encoder));
if (mm->encoder != 0)
{
/* copy formal params to XRDP_ENC_DATA */
enc_data = (XRDP_ENC_DATA *) g_malloc(sizeof(XRDP_ENC_DATA), 1);
if (enc_data == 0)
{
return 1;
}
enc_data->drects = (short *)
g_malloc(sizeof(short) * num_drects * 4, 0);
if (enc_data->drects == 0)
{
g_free(enc_data);
return 1;
}
enc_data->crects = (short *)
g_malloc(sizeof(short) * num_crects * 4, 0);
if (enc_data->crects == 0)
{
g_free(enc_data->drects);
g_free(enc_data);
return 1;
}
g_memcpy(enc_data->drects, drects, sizeof(short) * num_drects * 4);
g_memcpy(enc_data->crects, crects, sizeof(short) * num_crects * 4);
enc_data->mod = mod;
enc_data->num_drects = num_drects;
enc_data->num_crects = num_crects;
enc_data->data = data;
enc_data->width = width;
enc_data->height = height;
enc_data->flags = flags;
enc_data->frame_id = frame_id;
if (width == 0 || height == 0)
{
LLOGLN(10, ("server_paint_rects: error"));
}
/* insert into fifo for encoder thread to process */
tc_mutex_lock(mm->encoder->mutex);
fifo_add_item(mm->encoder->fifo_to_proc, (void *) enc_data);
tc_mutex_unlock(mm->encoder->mutex);
/* signal xrdp_encoder thread */
g_set_wait_obj(mm->encoder->xrdp_encoder_event_to_proc);
return 0;
}
//g_writeln("server_paint_rects:");
p = (struct xrdp_painter*)(mod->painter);
if (p == 0)
{
return 0;
}
b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp,
data, wm);
s = crects;
for (index = 0; index < num_crects; index++)
{
xrdp_painter_copy(p, b, wm->target_surface, s[0], s[1], s[2], s[3],
s[0], s[1]);
s += 4;
}
xrdp_bitmap_delete(b);
mm->mod->mod_frame_ack(mm->mod, flags, frame_id);
return 0;
}
/*****************************************************************************/
int
server_session_info(struct xrdp_mod *mod, const char *data, int data_bytes)
{
struct xrdp_wm *wm;
LLOGLN(10, ("server_session_info:"));
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_send_session_info(wm->session, data, data_bytes);
}
/*****************************************************************************/
int
server_set_pointer(struct xrdp_mod *mod, int x, int y,
char *data, char *mask)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
xrdp_wm_pointer(wm, data, mask, x, y, 0);
return 0;
}
/*****************************************************************************/
int
server_set_pointer_ex(struct xrdp_mod *mod, int x, int y,
char *data, char *mask, int bpp)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
xrdp_wm_pointer(wm, data, mask, x, y, bpp);
return 0;
}
/*****************************************************************************/
int
server_palette(struct xrdp_mod *mod, int *palette)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (g_memcmp(wm->palette, palette, 255 * sizeof(int)) != 0)
{
g_memcpy(wm->palette, palette, 256 * sizeof(int));
xrdp_wm_send_palette(wm);
}
return 0;
}
/*****************************************************************************/
int
server_msg(struct xrdp_mod *mod, char *msg, int code)
{
struct xrdp_wm *wm;
if (code == 1)
{
g_writeln("%s",msg);
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
return xrdp_wm_log_msg(wm, LOG_LEVEL_DEBUG, "%s", msg);
}
/*****************************************************************************/
int
server_is_term(struct xrdp_mod *mod)
{
return g_is_term();
}
/*****************************************************************************/
int
server_set_clip(struct xrdp_mod *mod, int x, int y, int cx, int cy)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
return xrdp_painter_set_clip(p, x, y, cx, cy);
}
/*****************************************************************************/
int
server_reset_clip(struct xrdp_mod *mod)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
return xrdp_painter_clr_clip(p);
}
/*****************************************************************************/
int
server_set_fgcolor(struct xrdp_mod *mod, int fgcolor)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->fg_color = fgcolor;
p->pen.color = p->fg_color;
return 0;
}
/*****************************************************************************/
int
server_set_bgcolor(struct xrdp_mod *mod, int bgcolor)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->bg_color = bgcolor;
return 0;
}
/*****************************************************************************/
int
server_set_opcode(struct xrdp_mod *mod, int opcode)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->rop = opcode;
return 0;
}
/*****************************************************************************/
int
server_set_mixmode(struct xrdp_mod *mod, int mixmode)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->mix_mode = mixmode;
return 0;
}
/*****************************************************************************/
int
server_set_brush(struct xrdp_mod *mod, int x_origin, int y_origin,
int style, char *pattern)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->brush.x_origin = x_origin;
p->brush.y_origin = y_origin;
p->brush.style = style;
g_memcpy(p->brush.pattern, pattern, 8);
return 0;
}
/*****************************************************************************/
int
server_set_pen(struct xrdp_mod *mod, int style, int width)
{
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
p->pen.style = style;
p->pen.width = width;
return 0;
}
/*****************************************************************************/
int
server_draw_line(struct xrdp_mod *mod, int x1, int y1, int x2, int y2)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
return xrdp_painter_line(p, wm->target_surface, x1, y1, x2, y2);
}
/*****************************************************************************/
int
server_add_char(struct xrdp_mod *mod, int font, int character,
int offset, int baseline,
int width, int height, char *data)
{
struct xrdp_font_char fi;
fi.offset = offset;
fi.baseline = baseline;
fi.width = width;
fi.height = height;
fi.incby = 0;
fi.data = data;
fi.bpp = 1;
return libxrdp_orders_send_font(((struct xrdp_wm *)mod->wm)->session,
&fi, font, character);
}
/*****************************************************************************/
int
server_draw_text(struct xrdp_mod *mod, int font,
int flags, int mixmode, int clip_left, int clip_top,
int clip_right, int clip_bottom,
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
return xrdp_painter_draw_text2(p, wm->target_surface, font, flags,
mixmode, clip_left, clip_top,
clip_right, clip_bottom,
box_left, box_top,
box_right, box_bottom,
x, y, data, data_len);
}
/*****************************************************************************/
int
server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (wm->client_info == 0)
{
return 1;
}
/* older client can't resize */
if (wm->client_info->build <= 419)
{
return 0;
}
/* if same, don't need to do anything */
if (wm->client_info->width == width &&
wm->client_info->height == height &&
wm->client_info->bpp == bpp)
{
return 0;
}
/* reset lib, client_info gets updated in libxrdp_reset */
if (libxrdp_reset(wm->session, width, height, bpp) != 0)
{
return 1;
}
/* reset cache */
xrdp_cache_reset(wm->cache, wm->client_info);
/* resize the main window */
xrdp_bitmap_resize(wm->screen, wm->client_info->width,
wm->client_info->height);
/* load some stuff */
xrdp_wm_load_static_colors_plus(wm, 0);
xrdp_wm_load_static_pointers(wm);
return 0;
}
/*****************************************************************************/
/*return 0 if the index is not found*/
int
server_query_channel(struct xrdp_mod *mod, int index, char *channel_name,
int *channel_flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (wm->mm->usechansrv)
{
return 1;
}
return libxrdp_query_channel(wm->session, index, channel_name,
channel_flags);
}
/*****************************************************************************/
/* returns -1 on error */
int
server_get_channel_id(struct xrdp_mod *mod, const char *name)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (wm->mm->usechansrv)
{
return -1;
}
return libxrdp_get_channel_id(wm->session, name);
}
/*****************************************************************************/
int
server_send_to_channel(struct xrdp_mod *mod, int channel_id,
char *data, int data_len,
int total_data_len, int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (wm->mm->usechansrv)
{
/*
* Xvnc backend reaches here
* should not return 1 as this case is not an error
*/
return 0;
}
/* vnc proxy mode reaches here */
return libxrdp_send_to_channel(wm->session, channel_id, data, data_len,
total_data_len, flags);
}
/*****************************************************************************/
int
server_create_os_surface(struct xrdp_mod *mod, int rdpindex,
int width, int height)
{
struct xrdp_wm *wm;
struct xrdp_bitmap *bitmap;
int error;
wm = (struct xrdp_wm *)(mod->wm);
bitmap = xrdp_bitmap_create(width, height, wm->screen->bpp,
WND_TYPE_OFFSCREEN, wm);
error = xrdp_cache_add_os_bitmap(wm->cache, bitmap, rdpindex);
if (error != 0)
{
log_message(LOG_LEVEL_ERROR,"server_create_os_surface: xrdp_cache_add_os_bitmap failed");
return 1;
}
bitmap->item_index = rdpindex;
bitmap->id = rdpindex;
return 0;
}
/*****************************************************************************/
int
server_create_os_surface_bpp(struct xrdp_mod* mod, int rdpindex,
int width, int height, int bpp)
{
struct xrdp_wm* wm;
struct xrdp_bitmap* bitmap;
int error;
wm = (struct xrdp_wm*)(mod->wm);
bitmap = xrdp_bitmap_create(width, height, bpp,
WND_TYPE_OFFSCREEN, wm);
error = xrdp_cache_add_os_bitmap(wm->cache, bitmap, rdpindex);
if (error != 0)
{
g_writeln("server_create_os_surface_bpp: xrdp_cache_add_os_bitmap failed");
return 1;
}
bitmap->item_index = rdpindex;
bitmap->id = rdpindex;
return 0;
}
/*****************************************************************************/
int
server_switch_os_surface(struct xrdp_mod *mod, int rdpindex)
{
struct xrdp_wm *wm;
struct xrdp_os_bitmap_item *bi;
struct xrdp_painter *p;
//g_writeln("server_switch_os_surface: id 0x%x", id);
wm = (struct xrdp_wm *)(mod->wm);
if (rdpindex == -1)
{
//g_writeln("server_switch_os_surface: setting target_surface to screen");
wm->target_surface = wm->screen;
p = (struct xrdp_painter *)(mod->painter);
if (p != 0)
{
//g_writeln("setting target");
wm_painter_set_target(p);
}
return 0;
}
bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex);
if ((bi != 0) && (bi->bitmap != 0))
{
//g_writeln("server_switch_os_surface: setting target_surface to rdpid %d", id);
wm->target_surface = bi->bitmap;
p = (struct xrdp_painter *)(mod->painter);
if (p != 0)
{
//g_writeln("setting target");
wm_painter_set_target(p);
}
}
else
{
log_message(LOG_LEVEL_ERROR,"server_switch_os_surface: error finding id %d", rdpindex);
}
return 0;
}
/*****************************************************************************/
int
server_delete_os_surface(struct xrdp_mod *mod, int rdpindex)
{
struct xrdp_wm *wm;
struct xrdp_painter *p;
//g_writeln("server_delete_os_surface: id 0x%x", id);
wm = (struct xrdp_wm *)(mod->wm);
if (wm->target_surface->type == WND_TYPE_OFFSCREEN)
{
if (wm->target_surface->id == rdpindex)
{
g_writeln("server_delete_os_surface: setting target_surface to screen");
wm->target_surface = wm->screen;
p = (struct xrdp_painter *)(mod->painter);
if (p != 0)
{
//g_writeln("setting target");
wm_painter_set_target(p);
}
}
}
xrdp_cache_remove_os_bitmap(wm->cache, rdpindex);
return 0;
}
/*****************************************************************************/
int
server_paint_rect_os(struct xrdp_mod *mod, int x, int y, int cx, int cy,
int rdpindex, int srcx, int srcy)
{
struct xrdp_wm *wm;
struct xrdp_bitmap *b;
struct xrdp_painter *p;
struct xrdp_os_bitmap_item *bi;
p = (struct xrdp_painter *)(mod->painter);
if (p == 0)
{
return 0;
}
wm = (struct xrdp_wm *)(mod->wm);
bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex);
if (bi != 0)
{
b = bi->bitmap;
xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy);
}
else
{
log_message(LOG_LEVEL_ERROR,"server_paint_rect_os: error finding id %d", rdpindex);
}
return 0;
}
/*****************************************************************************/
int
server_set_hints(struct xrdp_mod *mod, int hints, int mask)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
if (mask & 1)
{
if (hints & 1)
{
wm->hints |= 1;
}
else
{
wm->hints &= ~1;
}
}
return 0;
}
/*****************************************************************************/
int
server_window_new_update(struct xrdp_mod *mod, int window_id,
struct rail_window_state_order *window_state,
int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_window_new_update(wm->session, window_id,
window_state, flags);
}
/*****************************************************************************/
int
server_window_delete(struct xrdp_mod *mod, int window_id)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_window_delete(wm->session, window_id);
}
/*****************************************************************************/
int
server_window_icon(struct xrdp_mod *mod, int window_id, int cache_entry,
int cache_id, struct rail_icon_info *icon_info,
int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_window_icon(wm->session, window_id, cache_entry, cache_id,
icon_info, flags);
}
/*****************************************************************************/
int
server_window_cached_icon(struct xrdp_mod *mod,
int window_id, int cache_entry,
int cache_id, int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_window_cached_icon(wm->session, window_id, cache_entry,
cache_id, flags);
}
/*****************************************************************************/
int
server_notify_new_update(struct xrdp_mod *mod,
int window_id, int notify_id,
struct rail_notify_state_order *notify_state,
int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_notify_new_update(wm->session, window_id, notify_id,
notify_state, flags);
}
/*****************************************************************************/
int
server_notify_delete(struct xrdp_mod *mod, int window_id,
int notify_id)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_notify_delete(wm->session, window_id, notify_id);
}
/*****************************************************************************/
int
server_monitored_desktop(struct xrdp_mod *mod,
struct rail_monitored_desktop_order *mdo,
int flags)
{
struct xrdp_wm *wm;
wm = (struct xrdp_wm *)(mod->wm);
return libxrdp_monitored_desktop(wm->session, mdo, flags);
}
/*****************************************************************************/
int
server_add_char_alpha(struct xrdp_mod* mod, int font, int character,
int offset, int baseline,
int width, int height, char* data)
{
struct xrdp_font_char fi;
fi.offset = offset;
fi.baseline = baseline;
fi.width = width;
fi.height = height;
fi.incby = 0;
fi.data = data;
fi.bpp = 8;
return libxrdp_orders_send_font(((struct xrdp_wm*)mod->wm)->session,
&fi, font, character);
}