diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 7c6282a57..8b5f71623 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -356,246 +356,6 @@ hex_str_to_bin(char *in, char *out, int out_len) } } -/*****************************************************************************/ -static void -xrdp_load_keyboard_layout(struct xrdp_client_info *client_info) -{ - int fd; - int index = 0; - int bytes; - struct list *names = (struct list *)NULL; - struct list *items = (struct list *)NULL; - struct list *values = (struct list *)NULL; - char *item = (char *)NULL; - char *value = (char *)NULL; - char *q = (char *)NULL; - char keyboard_cfg_file[256] = { 0 }; - char rdp_layout[256] = { 0 }; - - const struct xrdp_keyboard_overrides *ko = - &client_info->xrdp_keyboard_overrides; - - LOG(LOG_LEVEL_INFO, "xrdp_load_keyboard_layout: Keyboard information sent" - " by the RDP client, keyboard_type:[0x%02X], keyboard_subtype:[0x%02X]," - " keylayout:[0x%08X]", - client_info->keyboard_type, client_info->keyboard_subtype, - client_info->keylayout); - - if (ko->type != -1) - { - LOG(LOG_LEVEL_INFO, "overrode keyboard_type 0x%02X" - " with 0x%02X", client_info->keyboard_type, ko->type); - client_info->keyboard_type = ko->type; - } - if (ko->subtype != -1) - { - LOG(LOG_LEVEL_INFO, "overrode keyboard_subtype 0x%02X" - " with 0x%02X", client_info->keyboard_subtype, - ko->subtype); - client_info->keyboard_subtype = ko->subtype; - } - if (ko->layout != -1) - { - LOG(LOG_LEVEL_INFO, "overrode keylayout 0x%08X" - " with 0x%08X", client_info->keylayout, ko->layout); - client_info->keylayout = ko->layout; - } - /* infer model/variant */ - /* TODO specify different X11 keyboard models/variants */ - g_memset(client_info->model, 0, sizeof(client_info->model)); - g_memset(client_info->variant, 0, sizeof(client_info->variant)); - g_strncpy(client_info->layout, "us", sizeof(client_info->layout) - 1); - if (client_info->keyboard_subtype == 3) - { - /* macintosh keyboard */ - bytes = sizeof(client_info->variant); - g_strncpy(client_info->variant, "mac", bytes - 1); - } - else if (client_info->keyboard_subtype == 0) - { - /* default - standard subtype */ - client_info->keyboard_subtype = 1; - } - - g_snprintf(keyboard_cfg_file, 255, "%s/xrdp_keyboard.ini", XRDP_CFG_PATH); - LOG(LOG_LEVEL_DEBUG, "keyboard_cfg_file %s", keyboard_cfg_file); - - fd = g_file_open_ro(keyboard_cfg_file); - - if (fd >= 0) - { - int section_found = -1; - char section_rdp_layouts[256] = { 0 }; - char section_layouts_map[256] = { 0 }; - - names = list_create(); - names->auto_free = 1; - items = list_create(); - items->auto_free = 1; - values = list_create(); - values->auto_free = 1; - - file_read_sections(fd, names); - for (index = 0; index < names->count; index++) - { - q = (char *)list_get_item(names, index); - if (g_strncasecmp("default", q, 8) != 0) - { - int i; - - file_read_section(fd, q, items, values); - - for (i = 0; i < items->count; i++) - { - item = (char *)list_get_item(items, i); - value = (char *)list_get_item(values, i); - LOG(LOG_LEVEL_DEBUG, "xrdp_load_keyboard_layout: item %s value %s", - item, value); - if (g_strcasecmp(item, "keyboard_type") == 0) - { - int v = g_atoi(value); - if (v == client_info->keyboard_type) - { - section_found = index; - } - } - else if (g_strcasecmp(item, "keyboard_subtype") == 0) - { - int v = g_atoi(value); - if (v != client_info->keyboard_subtype && - section_found == index) - { - section_found = -1; - break; - } - } - else if (g_strcasecmp(item, "rdp_layouts") == 0) - { - if (section_found != -1 && section_found == index) - { - g_strncpy(section_rdp_layouts, value, 255); - } - } - else if (g_strcasecmp(item, "layouts_map") == 0) - { - if (section_found != -1 && section_found == index) - { - g_strncpy(section_layouts_map, value, 255); - } - } - else if (g_strcasecmp(item, "model") == 0) - { - if (section_found != -1 && section_found == index) - { - bytes = sizeof(client_info->model); - g_memset(client_info->model, 0, bytes); - g_strncpy(client_info->model, value, bytes - 1); - } - } - else if (g_strcasecmp(item, "variant") == 0) - { - if (section_found != -1 && section_found == index) - { - bytes = sizeof(client_info->variant); - g_memset(client_info->variant, 0, bytes); - g_strncpy(client_info->variant, value, bytes - 1); - } - } - else if (g_strcasecmp(item, "options") == 0) - { - if (section_found != -1 && section_found == index) - { - bytes = sizeof(client_info->options); - g_memset(client_info->options, 0, bytes); - g_strncpy(client_info->options, value, bytes - 1); - } - } - else - { - /* - * mixing items from different sections will result in - * skipping over current section. - */ - LOG(LOG_LEVEL_DEBUG, "xrdp_load_keyboard_layout: skipping " - "configuration item - %s, continuing to next " - "section", item); - break; - } - } - - list_clear(items); - list_clear(values); - } - } - - if (section_found == -1) - { - g_memset(section_rdp_layouts, 0, sizeof(char) * 256); - g_memset(section_layouts_map, 0, sizeof(char) * 256); - // read default section - file_read_section(fd, "default", items, values); - for (index = 0; index < items->count; index++) - { - item = (char *)list_get_item(items, index); - value = (char *)list_get_item(values, index); - if (g_strcasecmp(item, "rdp_layouts") == 0) - { - g_strncpy(section_rdp_layouts, value, 255); - } - else if (g_strcasecmp(item, "layouts_map") == 0) - { - g_strncpy(section_layouts_map, value, 255); - } - } - list_clear(items); - list_clear(values); - } - - /* load the map */ - file_read_section(fd, section_rdp_layouts, items, values); - for (index = 0; index < items->count; index++) - { - int rdp_layout_id; - item = (char *)list_get_item(items, index); - value = (char *)list_get_item(values, index); - rdp_layout_id = g_htoi(value); - if (rdp_layout_id == client_info->keylayout) - { - g_strncpy(rdp_layout, item, 255); - break; - } - } - list_clear(items); - list_clear(values); - file_read_section(fd, section_layouts_map, items, values); - for (index = 0; index < items->count; index++) - { - item = (char *)list_get_item(items, index); - value = (char *)list_get_item(values, index); - if (g_strcasecmp(item, rdp_layout) == 0) - { - bytes = sizeof(client_info->layout); - g_strncpy(client_info->layout, value, bytes - 1); - break; - } - } - - list_delete(names); - list_delete(items); - list_delete(values); - - LOG(LOG_LEVEL_INFO, "xrdp_load_keyboard_layout: model [%s] variant [%s] " - "layout [%s] options [%s]", client_info->model, - client_info->variant, client_info->layout, client_info->options); - g_file_close(fd); - } - else - { - LOG(LOG_LEVEL_ERROR, "xrdp_load_keyboard_layout: error opening %s", - keyboard_cfg_file); - } -} - /*****************************************************************************/ struct xrdp_sec * xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans) @@ -2753,7 +2513,6 @@ xrdp_sec_in_mcs_data(struct xrdp_sec *self) client_info->keyboard_type, client_info->keyboard_subtype); - xrdp_load_keyboard_layout(client_info); s->p = s->data; return 0; diff --git a/mc/mc.h b/mc/mc.h index 6aaf441d9..f15e3f9a1 100644 --- a/mc/mc.h +++ b/mc/mc.h @@ -30,6 +30,7 @@ #define CURRENT_MOD_VER 3 struct source_info; +struct xrdp_client_info; /* Defined in xrdp_client_info.h */ struct monitor_info; @@ -98,7 +99,9 @@ struct mod int total_data_len, int flags); int (*server_bell_trigger)(struct mod *v); int (*server_chansrv_in_use)(struct mod *v); - tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server + void (*server_init_xkb_layout)(struct mod *v, + struct xrdp_client_info *client_info); + tintptr server_dumby[100 - 29]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as long */ diff --git a/neutrinordp/xrdp-neutrinordp.h b/neutrinordp/xrdp-neutrinordp.h index d5dc78a24..a616dca31 100644 --- a/neutrinordp/xrdp-neutrinordp.h +++ b/neutrinordp/xrdp-neutrinordp.h @@ -143,6 +143,8 @@ struct mod int total_data_len, int flags); int (*server_bell_trigger)(struct mod *v); int (*server_chansrv_in_use)(struct mod *v); + void (*server_init_xkb_layout)(struct mod *v, + struct xrdp_client_info *client_info); /* off screen bitmaps */ int (*server_create_os_surface)(struct mod *v, int rdpindex, int width, int height); @@ -197,7 +199,7 @@ struct mod int flags, int frame_id); int (*server_session_info)(struct mod *v, const char *data, int data_bytes); - tintptr server_dumby[100 - 47]; /* align, 100 minus the number of server + tintptr server_dumby[100 - 48]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as long */ diff --git a/vnc/vnc.h b/vnc/vnc.h index 85e943f71..a69c2690b 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -69,6 +69,7 @@ enum vnc_resize_support_status }; struct source_info; +struct xrdp_client_info; /* Defined in vnc_clip.c */ struct vnc_clipboard_data; @@ -151,7 +152,9 @@ struct vnc int total_data_len, int flags); int (*server_bell_trigger)(struct vnc *v); int (*server_chansrv_in_use)(struct vnc *v); - tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server + void (*server_init_xkb_layout)(struct vnc *v, + struct xrdp_client_info *client_info); + tintptr server_dumby[100 - 29]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as long */ diff --git a/xrdp/lang.c b/xrdp/lang.c index 6a3f8acc6..e36f688ef 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -414,3 +414,243 @@ km_load_file(const char *filename, struct xrdp_keymap *keymap) return rv; } + +/*****************************************************************************/ +void +xrdp_init_xkb_layout(struct xrdp_client_info *client_info) +{ + int fd; + int index = 0; + int bytes; + struct list *names = (struct list *)NULL; + struct list *items = (struct list *)NULL; + struct list *values = (struct list *)NULL; + char *item = (char *)NULL; + char *value = (char *)NULL; + char *q = (char *)NULL; + char keyboard_cfg_file[256] = { 0 }; + char rdp_layout[256] = { 0 }; + + const struct xrdp_keyboard_overrides *ko = + &client_info->xrdp_keyboard_overrides; + + LOG(LOG_LEVEL_INFO, "xrdp_init_xkb_layout: Keyboard information sent" + " by the RDP client, keyboard_type:[0x%02X], keyboard_subtype:[0x%02X]," + " keylayout:[0x%08X]", + client_info->keyboard_type, client_info->keyboard_subtype, + client_info->keylayout); + + if (ko->type != -1) + { + LOG(LOG_LEVEL_INFO, "overrode keyboard_type 0x%02X" + " with 0x%02X", client_info->keyboard_type, ko->type); + client_info->keyboard_type = ko->type; + } + if (ko->subtype != -1) + { + LOG(LOG_LEVEL_INFO, "overrode keyboard_subtype 0x%02X" + " with 0x%02X", client_info->keyboard_subtype, + ko->subtype); + client_info->keyboard_subtype = ko->subtype; + } + if (ko->layout != -1) + { + LOG(LOG_LEVEL_INFO, "overrode keylayout 0x%08X" + " with 0x%08X", client_info->keylayout, ko->layout); + client_info->keylayout = ko->layout; + } + /* infer model/variant */ + /* TODO specify different X11 keyboard models/variants */ + g_memset(client_info->model, 0, sizeof(client_info->model)); + g_memset(client_info->variant, 0, sizeof(client_info->variant)); + g_strncpy(client_info->layout, "us", sizeof(client_info->layout) - 1); + if (client_info->keyboard_subtype == 3) + { + /* macintosh keyboard */ + bytes = sizeof(client_info->variant); + g_strncpy(client_info->variant, "mac", bytes - 1); + } + else if (client_info->keyboard_subtype == 0) + { + /* default - standard subtype */ + client_info->keyboard_subtype = 1; + } + + g_snprintf(keyboard_cfg_file, 255, "%s/xrdp_keyboard.ini", XRDP_CFG_PATH); + LOG(LOG_LEVEL_DEBUG, "keyboard_cfg_file %s", keyboard_cfg_file); + + fd = g_file_open_ro(keyboard_cfg_file); + + if (fd >= 0) + { + int section_found = -1; + char section_rdp_layouts[256] = { 0 }; + char section_layouts_map[256] = { 0 }; + + names = list_create(); + names->auto_free = 1; + items = list_create(); + items->auto_free = 1; + values = list_create(); + values->auto_free = 1; + + file_read_sections(fd, names); + for (index = 0; index < names->count; index++) + { + q = (char *)list_get_item(names, index); + if (g_strncasecmp("default", q, 8) != 0) + { + int i; + + file_read_section(fd, q, items, values); + + for (i = 0; i < items->count; i++) + { + item = (char *)list_get_item(items, i); + value = (char *)list_get_item(values, i); + LOG(LOG_LEVEL_DEBUG, "xrdp_init_xkb_layout: item %s value %s", + item, value); + if (g_strcasecmp(item, "keyboard_type") == 0) + { + int v = g_atoi(value); + if (v == client_info->keyboard_type) + { + section_found = index; + } + } + else if (g_strcasecmp(item, "keyboard_subtype") == 0) + { + int v = g_atoi(value); + if (v != client_info->keyboard_subtype && + section_found == index) + { + section_found = -1; + break; + } + } + else if (g_strcasecmp(item, "rdp_layouts") == 0) + { + if (section_found != -1 && section_found == index) + { + g_strncpy(section_rdp_layouts, value, 255); + } + } + else if (g_strcasecmp(item, "layouts_map") == 0) + { + if (section_found != -1 && section_found == index) + { + g_strncpy(section_layouts_map, value, 255); + } + } + else if (g_strcasecmp(item, "model") == 0) + { + if (section_found != -1 && section_found == index) + { + bytes = sizeof(client_info->model); + g_memset(client_info->model, 0, bytes); + g_strncpy(client_info->model, value, bytes - 1); + } + } + else if (g_strcasecmp(item, "variant") == 0) + { + if (section_found != -1 && section_found == index) + { + bytes = sizeof(client_info->variant); + g_memset(client_info->variant, 0, bytes); + g_strncpy(client_info->variant, value, bytes - 1); + } + } + else if (g_strcasecmp(item, "options") == 0) + { + if (section_found != -1 && section_found == index) + { + bytes = sizeof(client_info->options); + g_memset(client_info->options, 0, bytes); + g_strncpy(client_info->options, value, bytes - 1); + } + } + else + { + /* + * mixing items from different sections will result in + * skipping over current section. + */ + LOG(LOG_LEVEL_DEBUG, "xrdp_init_xkb_layout: skipping " + "configuration item - %s, continuing to next " + "section", item); + break; + } + } + + list_clear(items); + list_clear(values); + } + } + + if (section_found == -1) + { + g_memset(section_rdp_layouts, 0, sizeof(char) * 256); + g_memset(section_layouts_map, 0, sizeof(char) * 256); + // read default section + file_read_section(fd, "default", items, values); + for (index = 0; index < items->count; index++) + { + item = (char *)list_get_item(items, index); + value = (char *)list_get_item(values, index); + if (g_strcasecmp(item, "rdp_layouts") == 0) + { + g_strncpy(section_rdp_layouts, value, 255); + } + else if (g_strcasecmp(item, "layouts_map") == 0) + { + g_strncpy(section_layouts_map, value, 255); + } + } + list_clear(items); + list_clear(values); + } + + /* load the map */ + file_read_section(fd, section_rdp_layouts, items, values); + for (index = 0; index < items->count; index++) + { + int rdp_layout_id; + item = (char *)list_get_item(items, index); + value = (char *)list_get_item(values, index); + rdp_layout_id = g_htoi(value); + if (rdp_layout_id == client_info->keylayout) + { + g_strncpy(rdp_layout, item, 255); + break; + } + } + list_clear(items); + list_clear(values); + file_read_section(fd, section_layouts_map, items, values); + for (index = 0; index < items->count; index++) + { + item = (char *)list_get_item(items, index); + value = (char *)list_get_item(values, index); + if (g_strcasecmp(item, rdp_layout) == 0) + { + bytes = sizeof(client_info->layout); + g_strncpy(client_info->layout, value, bytes - 1); + break; + } + } + + list_delete(names); + list_delete(items); + list_delete(values); + + LOG(LOG_LEVEL_INFO, "xrdp_init_xkb_layout: model [%s] variant [%s] " + "layout [%s] options [%s]", client_info->model, + client_info->variant, client_info->layout, client_info->options); + g_file_close(fd); + } + else + { + LOG(LOG_LEVEL_ERROR, "xrdp_init_xkb_layout: error opening %s", + keyboard_cfg_file); + } +} diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 810f24493..db8fedf44 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -446,6 +446,19 @@ get_keymaps(int keylayout, struct xrdp_keymap *keymap); int km_load_file(const char *filename, struct xrdp_keymap *keymap); +/** + * initialise the XKB layout + * + * Not all backends need to use XKB for keyboard mapping. This + * call is used by those modules that do need an XKB mapping. + * + * Other modules and the login screen use other routines in + * lang.c to interpret incoming RDP scancodes + * @param client_info Client info struct to initialise + */ +void +xrdp_init_xkb_layout(struct xrdp_client_info *client_info); + /* xrdp_login_wnd.c */ /** * Gets the DPI of the login (primary) monitor @@ -527,6 +540,9 @@ int server_bell_trigger(struct xrdp_mod *mod); int server_chansrv_in_use(struct xrdp_mod *mod); +void +server_init_xkb_layout(struct xrdp_mod *mod, + struct xrdp_client_info *client_info); int server_fill_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy); int diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 5bca3094c..080226ddb 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -384,6 +384,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) self->mod->server_end_update = server_end_update; self->mod->server_bell_trigger = server_bell_trigger; self->mod->server_chansrv_in_use = server_chansrv_in_use; + self->mod->server_init_xkb_layout = server_init_xkb_layout; self->mod->server_fill_rect = server_fill_rect; self->mod->server_screen_blt = server_screen_blt; self->mod->server_paint_rect = server_paint_rect; @@ -3978,6 +3979,15 @@ server_chansrv_in_use(struct xrdp_mod *mod) return wm->mm->use_chansrv; } +/*****************************************************************************/ +/* Init the XKB layout */ +void +server_init_xkb_layout(struct xrdp_mod *mod, + struct xrdp_client_info *client_info) +{ + xrdp_init_xkb_layout(client_info); +} + /*****************************************************************************/ int diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 4b5749394..5a014f883 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -124,6 +124,8 @@ struct xrdp_mod int total_data_len, int flags); int (*server_bell_trigger)(struct xrdp_mod *v); int (*server_chansrv_in_use)(struct xrdp_mod *v); + void (*server_init_xkb_layout)(struct xrdp_mod *v, + struct xrdp_client_info *client_info); /* off screen bitmaps */ int (*server_create_os_surface)(struct xrdp_mod *v, int rdpindex, int width, int height); @@ -192,7 +194,7 @@ struct xrdp_mod int (*server_egfx_cmd)(struct xrdp_mod *v, char *cmd, int cmd_bytes, char *data, int data_bytes); - tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server + tintptr server_dumby[100 - 51]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as int */ diff --git a/xup/xup.c b/xup/xup.c index 317ddeaf6..645eaa526 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -171,6 +171,12 @@ lib_mod_connect(struct mod *mod) return 1; } + // This is a good place to finalise any parameters that need to + // be set. + // + // Load the XKB layout + mod->server_init_xkb_layout(mod, &(mod->client_info)); + make_stream(s); g_sprintf(con_port, "%s", mod->port); diff --git a/xup/xup.h b/xup/xup.h index 3b95124d9..05f747e72 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -34,6 +34,7 @@ #define CURRENT_MOD_VER 4 struct source_info; +struct xrdp_client_info; struct mod { @@ -111,6 +112,8 @@ struct mod int total_data_len, int flags); int (*server_bell_trigger)(struct mod *v); int (*server_chansrv_in_use)(struct mod *v); + void (*server_init_xkb_layout)(struct mod *v, + struct xrdp_client_info *client_info); /* off screen bitmaps */ int (*server_create_os_surface)(struct mod *v, int rdpindex, int width, int height); @@ -176,7 +179,7 @@ struct mod int (*server_egfx_cmd)(struct mod *v, char *cmd, int cmd_bytes, char *data, int data_bytes); - tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server + tintptr server_dumby[100 - 51]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as long */