From b4e81ca17240281fc802a662f5ce4e78a767c2b9 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Fri, 16 Dec 2022 01:26:25 -0700 Subject: context: add XKB_CONTEXT_NO_SECURE_GETENV flag (#312) This flag is useful for clients that may have relatively benign capabilities set, like CAP_SYS_NICE, that also want to use the xkb configuration from the environment and user configs in XDG_CONFIG_HOME. Fixes: https://github.com/xkbcommon/libxkbcommon/issues/308 Fixes: https://github.com/xkbcommon/libxkbcommon/issues/129 Signed-off-by: Ran Benita --- include/xkbcommon/xkbcommon.h | 10 +++++++++- include/xkbcommon/xkbregistry.h | 7 +++++++ src/compose/parser.c | 6 +++--- src/compose/paths.c | 37 +++++++++++++++++++------------------ src/compose/paths.h | 12 ++++++------ src/compose/table.c | 10 +++++----- src/context-priv.c | 22 ++++++++++++++++------ src/context.c | 17 +++++++++-------- src/context.h | 4 ++++ src/registry.c | 23 ++++++++++++++++++----- src/xkbcomp/rules.c | 2 +- 11 files changed, 97 insertions(+), 53 deletions(-) diff --git a/include/xkbcommon/xkbcommon.h b/include/xkbcommon/xkbcommon.h index c2b099f..7cb46f3 100644 --- a/include/xkbcommon/xkbcommon.h +++ b/include/xkbcommon/xkbcommon.h @@ -580,9 +580,17 @@ enum xkb_context_flags { XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0), /** * Don't take RMLVO names from the environment. + * * @since 0.3.0 */ - XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1) + XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1), + /** + * Disable the use of secure_getenv for this context, so that privileged + * processes can use environment variables. Client uses at their own risk. + * + * @since 1.5.0 + */ + XKB_CONTEXT_NO_SECURE_GETENV = (1 << 2) }; /** diff --git a/include/xkbcommon/xkbregistry.h b/include/xkbcommon/xkbregistry.h index 4e7e926..7be0c9b 100644 --- a/include/xkbcommon/xkbregistry.h +++ b/include/xkbcommon/xkbregistry.h @@ -163,6 +163,13 @@ enum rxkb_context_flags { * on the lookup behavior. */ RXKB_CONTEXT_LOAD_EXOTIC_RULES = (1 << 1), + /** + * Disable the use of secure_getenv for this context, so that privileged + * processes can use environment variables. Client uses at their own risk. + * + * @since 1.5.0 + */ + RXKB_CONTEXT_NO_SECURE_GETENV = (1 << 2) }; /** diff --git a/src/compose/parser.c b/src/compose/parser.c index 0bd4571..f84b314 100644 --- a/src/compose/parser.c +++ b/src/compose/parser.c @@ -262,7 +262,7 @@ lex_include_string(struct scanner *s, struct xkb_compose_table *table, scanner_buf_append(s, '%'); } else if (scanner_chr(s, 'H')) { - const char *home = secure_getenv("HOME"); + const char *home = xkb_context_getenv(table->ctx, "HOME"); if (!home) { scanner_err(s, "%%H was used in an include statement, but the HOME environment variable is not set"); return TOK_ERROR; @@ -273,7 +273,7 @@ lex_include_string(struct scanner *s, struct xkb_compose_table *table, } } else if (scanner_chr(s, 'L')) { - char *path = get_locale_compose_file_path(table->locale); + char *path = get_locale_compose_file_path(table->ctx, table->locale); if (!path) { scanner_err(s, "failed to expand %%L to the locale Compose file"); return TOK_ERROR; @@ -286,7 +286,7 @@ lex_include_string(struct scanner *s, struct xkb_compose_table *table, free(path); } else if (scanner_chr(s, 'S')) { - const char *xlocaledir = get_xlocaledir_path(); + const char *xlocaledir = get_xlocaledir_path(table->ctx); if (!scanner_buf_appends(s, xlocaledir)) { scanner_err(s, "include path after expanding %%S is too long"); return TOK_ERROR; diff --git a/src/compose/paths.c b/src/compose/paths.c index dab71ac..fd88623 100644 --- a/src/compose/paths.c +++ b/src/compose/paths.c @@ -23,9 +23,10 @@ #include "config.h" +#include "xkbcommon/xkbcommon.h" #include "utils.h" +#include "context.h" #include "paths.h" -#include "utils.h" enum resolve_name_direction { LEFT_TO_RIGHT, @@ -33,9 +34,9 @@ enum resolve_name_direction { }; const char * -get_xlocaledir_path(void) +get_xlocaledir_path(struct xkb_context *ctx) { - const char *dir = secure_getenv("XLOCALEDIR"); + const char *dir = xkb_context_getenv(ctx, "XLOCALEDIR"); if (!dir) dir = XLOCALEDIR; return dir; @@ -47,8 +48,8 @@ get_xlocaledir_path(void) * @filename is relative to the xlocaledir. */ static char * -resolve_name(const char *filename, enum resolve_name_direction direction, - const char *name) +resolve_name(struct xkb_context *ctx, const char *filename, + enum resolve_name_direction direction, const char *name) { int ret; bool ok; @@ -62,7 +63,7 @@ resolve_name(const char *filename, enum resolve_name_direction direction, char *match; size_t left_len, right_len, name_len; - xlocaledir = get_xlocaledir_path(); + xlocaledir = get_xlocaledir_path(ctx); ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename); if (ret < 0 || (size_t) ret >= sizeof(path)) @@ -137,27 +138,27 @@ resolve_name(const char *filename, enum resolve_name_direction direction, } char * -resolve_locale(const char *locale) +resolve_locale(struct xkb_context *ctx, const char *locale) { - char *alias = resolve_name("locale.alias", LEFT_TO_RIGHT, locale); + char *alias = resolve_name(ctx, "locale.alias", LEFT_TO_RIGHT, locale); return alias ? alias : strdup(locale); } char * -get_xcomposefile_path(void) +get_xcomposefile_path(struct xkb_context *ctx) { - return strdup_safe(secure_getenv("XCOMPOSEFILE")); + return strdup_safe(xkb_context_getenv(ctx, "XCOMPOSEFILE")); } char * -get_xdg_xcompose_file_path(void) +get_xdg_xcompose_file_path(struct xkb_context *ctx) { const char *xdg_config_home; const char *home; - xdg_config_home = secure_getenv("XDG_CONFIG_HOME"); + xdg_config_home = xkb_context_getenv(ctx, "XDG_CONFIG_HOME"); if (!xdg_config_home || xdg_config_home[0] != '/') { - home = secure_getenv("HOME"); + home = xkb_context_getenv(ctx, "HOME"); if (!home) return NULL; return asprintf_safe("%s/.config/XCompose", home); @@ -167,11 +168,11 @@ get_xdg_xcompose_file_path(void) } char * -get_home_xcompose_file_path(void) +get_home_xcompose_file_path(struct xkb_context *ctx) { const char *home; - home = secure_getenv("HOME"); + home = xkb_context_getenv(ctx, "HOME"); if (!home) return NULL; @@ -179,7 +180,7 @@ get_home_xcompose_file_path(void) } char * -get_locale_compose_file_path(const char *locale) +get_locale_compose_file_path(struct xkb_context *ctx, const char *locale) { char *resolved; char *path; @@ -198,7 +199,7 @@ get_locale_compose_file_path(const char *locale) if (streq(locale, "C")) locale = "en_US.UTF-8"; - resolved = resolve_name("compose.dir", RIGHT_TO_LEFT, locale); + resolved = resolve_name(ctx, "compose.dir", RIGHT_TO_LEFT, locale); if (!resolved) return NULL; @@ -206,7 +207,7 @@ get_locale_compose_file_path(const char *locale) path = resolved; } else { - const char *xlocaledir = get_xlocaledir_path(); + const char *xlocaledir = get_xlocaledir_path(ctx); path = asprintf_safe("%s/%s", xlocaledir, resolved); free(resolved); } diff --git a/src/compose/paths.h b/src/compose/paths.h index bc5150f..8170aef 100644 --- a/src/compose/paths.h +++ b/src/compose/paths.h @@ -25,21 +25,21 @@ #define COMPOSE_RESOLVE_H char * -resolve_locale(const char *locale); +resolve_locale(struct xkb_context *ctx, const char *locale); const char * -get_xlocaledir_path(void); +get_xlocaledir_path(struct xkb_context *ctx); char * -get_xcomposefile_path(void); +get_xcomposefile_path(struct xkb_context *ctx); char * -get_xdg_xcompose_file_path(void); +get_xdg_xcompose_file_path(struct xkb_context *ctx); char * -get_home_xcompose_file_path(void); +get_home_xcompose_file_path(struct xkb_context *ctx); char * -get_locale_compose_file_path(const char *locale); +get_locale_compose_file_path(struct xkb_context *ctx, const char *locale); #endif diff --git a/src/compose/table.c b/src/compose/table.c index 8a8d11f..ea5e45a 100644 --- a/src/compose/table.c +++ b/src/compose/table.c @@ -38,7 +38,7 @@ xkb_compose_table_new(struct xkb_context *ctx, struct xkb_compose_table *table; struct compose_node dummy; - resolved_locale = resolve_locale(locale); + resolved_locale = resolve_locale(ctx, locale); if (!resolved_locale) return NULL; @@ -174,7 +174,7 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx, if (!table) return NULL; - path = get_xcomposefile_path(); + path = get_xcomposefile_path(ctx); if (path) { file = fopen(path, "rb"); if (file) @@ -182,7 +182,7 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx, } free(path); - path = get_xdg_xcompose_file_path(); + path = get_xdg_xcompose_file_path(ctx); if (path) { file = fopen(path, "rb"); if (file) @@ -190,7 +190,7 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx, } free(path); - path = get_home_xcompose_file_path(); + path = get_home_xcompose_file_path(ctx); if (path) { file = fopen(path, "rb"); if (file) @@ -198,7 +198,7 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx, } free(path); - path = get_locale_compose_file_path(table->locale); + path = get_locale_compose_file_path(ctx, table->locale); if (path) { file = fopen(path, "rb"); if (file) diff --git a/src/context-priv.c b/src/context-priv.c index 8eaa579..e94385f 100644 --- a/src/context-priv.c +++ b/src/context-priv.c @@ -34,6 +34,16 @@ #include "utils.h" #include "context.h" +char * +xkb_context_getenv(struct xkb_context *ctx, const char *name) +{ + if (ctx->use_secure_getenv) { + return secure_getenv(name); + } else { + return getenv(name); + } +} + unsigned int xkb_context_num_failed_include_paths(struct xkb_context *ctx) { @@ -105,7 +115,7 @@ xkb_context_get_default_rules(struct xkb_context *ctx) const char *env = NULL; if (ctx->use_environment_names) - env = secure_getenv("XKB_DEFAULT_RULES"); + env = xkb_context_getenv(ctx, "XKB_DEFAULT_RULES"); return env ? env : DEFAULT_XKB_RULES; } @@ -116,7 +126,7 @@ xkb_context_get_default_model(struct xkb_context *ctx) const char *env = NULL; if (ctx->use_environment_names) - env = secure_getenv("XKB_DEFAULT_MODEL"); + env = xkb_context_getenv(ctx, "XKB_DEFAULT_MODEL"); return env ? env : DEFAULT_XKB_MODEL; } @@ -127,7 +137,7 @@ xkb_context_get_default_layout(struct xkb_context *ctx) const char *env = NULL; if (ctx->use_environment_names) - env = secure_getenv("XKB_DEFAULT_LAYOUT"); + env = xkb_context_getenv(ctx, "XKB_DEFAULT_LAYOUT"); return env ? env : DEFAULT_XKB_LAYOUT; } @@ -136,12 +146,12 @@ static const char * xkb_context_get_default_variant(struct xkb_context *ctx) { const char *env = NULL; - const char *layout = secure_getenv("XKB_DEFAULT_LAYOUT"); + const char *layout = xkb_context_getenv(ctx, "XKB_DEFAULT_LAYOUT"); /* We don't want to inherit the variant if they haven't also set a * layout, since they're so closely paired. */ if (layout && ctx->use_environment_names) - env = secure_getenv("XKB_DEFAULT_VARIANT"); + env = xkb_context_getenv(ctx, "XKB_DEFAULT_VARIANT"); return env ? env : DEFAULT_XKB_VARIANT; } @@ -152,7 +162,7 @@ xkb_context_get_default_options(struct xkb_context *ctx) const char *env = NULL; if (ctx->use_environment_names) - env = secure_getenv("XKB_DEFAULT_OPTIONS"); + env = xkb_context_getenv(ctx, "XKB_DEFAULT_OPTIONS"); return env ? env : DEFAULT_XKB_OPTIONS; } diff --git a/src/context.c b/src/context.c index 5701a74..b8b214b 100644 --- a/src/context.c +++ b/src/context.c @@ -34,6 +34,7 @@ #include "utils.h" #include "context.h" + /** * Append one directory to the context's include path. */ @@ -77,14 +78,14 @@ err: const char * xkb_context_include_path_get_extra_path(struct xkb_context *ctx) { - const char *extra = secure_getenv("XKB_CONFIG_EXTRA_PATH"); + const char *extra = xkb_context_getenv(ctx, "XKB_CONFIG_EXTRA_PATH"); return extra ? extra : DFLT_XKB_CONFIG_EXTRA_PATH; } const char * xkb_context_include_path_get_system_path(struct xkb_context *ctx) { - const char *root = secure_getenv("XKB_CONFIG_ROOT"); + const char *root = xkb_context_getenv(ctx, "XKB_CONFIG_ROOT"); return root ? root : DFLT_XKB_CONFIG_ROOT; } @@ -98,9 +99,9 @@ xkb_context_include_path_append_default(struct xkb_context *ctx) char *user_path; int ret = 0; - home = secure_getenv("HOME"); + home = xkb_context_getenv(ctx, "HOME"); - xdg = secure_getenv("XDG_CONFIG_HOME"); + xdg = xkb_context_getenv(ctx, "XDG_CONFIG_HOME"); if (xdg != NULL) { user_path = asprintf_safe("%s/xkb", xdg); if (user_path) { @@ -289,13 +290,15 @@ xkb_context_new(enum xkb_context_flags flags) ctx->log_fn = default_log_fn; ctx->log_level = XKB_LOG_LEVEL_ERROR; ctx->log_verbosity = 0; + ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + ctx->use_secure_getenv = !(flags & XKB_CONTEXT_NO_SECURE_GETENV); /* Environment overwrites defaults. */ - env = secure_getenv("XKB_LOG_LEVEL"); + env = xkb_context_getenv(ctx, "XKB_LOG_LEVEL"); if (env) xkb_context_set_log_level(ctx, log_level(env)); - env = secure_getenv("XKB_LOG_VERBOSITY"); + env = xkb_context_getenv(ctx, "XKB_LOG_VERBOSITY"); if (env) xkb_context_set_log_verbosity(ctx, log_verbosity(env)); @@ -307,8 +310,6 @@ xkb_context_new(enum xkb_context_flags flags) return NULL; } - ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES); - ctx->atom_table = atom_table_new(); if (!ctx->atom_table) { xkb_context_unref(ctx); diff --git a/src/context.h b/src/context.h index 44367cc..488bfad 100644 --- a/src/context.h +++ b/src/context.h @@ -53,8 +53,12 @@ struct xkb_context { size_t text_next; unsigned int use_environment_names : 1; + unsigned int use_secure_getenv : 1; }; +char * +xkb_context_getenv(struct xkb_context *ctx, const char *name); + unsigned int xkb_context_num_failed_include_paths(struct xkb_context *ctx); diff --git a/src/registry.c b/src/registry.c index dbaac2a..0c42a3b 100644 --- a/src/registry.c +++ b/src/registry.c @@ -72,6 +72,7 @@ struct rxkb_context { enum context_state context_state; bool load_extra_rules_files; + bool use_secure_getenv; struct list models; /* list of struct rxkb_models */ struct list layouts; /* list of struct rxkb_layouts */ @@ -437,6 +438,17 @@ DECLARE_REF_UNREF_FOR_TYPE(rxkb_context); DECLARE_CREATE_FOR_TYPE(rxkb_context); DECLARE_TYPED_GETTER_FOR_TYPE(rxkb_context, log_level, enum rxkb_log_level); +static char * +rxkb_context_getenv(struct rxkb_context *ctx, const char *name) +{ + if (ctx->use_secure_getenv) { + return secure_getenv(name); + } else { + return getenv(name); + } +} + + XKB_EXPORT void rxkb_context_set_log_level(struct rxkb_context *ctx, enum rxkb_log_level level) @@ -508,11 +520,12 @@ rxkb_context_new(enum rxkb_context_flags flags) ctx->context_state = CONTEXT_NEW; ctx->load_extra_rules_files = flags & RXKB_CONTEXT_LOAD_EXOTIC_RULES; + ctx->use_secure_getenv = !(flags & RXKB_CONTEXT_NO_SECURE_GETENV); ctx->log_fn = default_log_fn; ctx->log_level = RXKB_LOG_LEVEL_ERROR; /* Environment overwrites defaults. */ - env = secure_getenv("RXKB_LOG_LEVEL"); + env = rxkb_context_getenv(ctx, "RXKB_LOG_LEVEL"); if (env) rxkb_context_set_log_level(ctx, log_level(env)); @@ -593,9 +606,9 @@ rxkb_context_include_path_append_default(struct rxkb_context *ctx) return false; } - home = secure_getenv("HOME"); + home = rxkb_context_getenv(ctx, "HOME"); - xdg = secure_getenv("XDG_CONFIG_HOME"); + xdg = rxkb_context_getenv(ctx, "XDG_CONFIG_HOME"); if (xdg != NULL) { user_path = asprintf_safe("%s/xkb", xdg); if (user_path) { @@ -619,13 +632,13 @@ rxkb_context_include_path_append_default(struct rxkb_context *ctx) } } - extra = secure_getenv("XKB_CONFIG_EXTRA_PATH"); + extra = rxkb_context_getenv(ctx, "XKB_CONFIG_EXTRA_PATH"); if (extra != NULL) ret |= rxkb_context_include_path_append(ctx, extra); else ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_EXTRA_PATH); - root = secure_getenv("XKB_CONFIG_ROOT"); + root = rxkb_context_getenv(ctx, "XKB_CONFIG_ROOT"); if (root != NULL) ret |= rxkb_context_include_path_append(ctx, root); else diff --git a/src/xkbcomp/rules.c b/src/xkbcomp/rules.c index 2d3d9d8..8029682 100644 --- a/src/xkbcomp/rules.c +++ b/src/xkbcomp/rules.c @@ -382,7 +382,7 @@ matcher_include(struct matcher *m, struct scanner *parent_scanner, scanner_buf_append(&s, '%'); } else if (scanner_chr(&s, 'H')) { - const char *home = secure_getenv("HOME"); + const char *home = xkb_context_getenv(m->ctx, "HOME"); if (!home) { scanner_err(&s, "%%H was used in an include statement, but the HOME environment variable is not set"); return; -- cgit v1.2.1