/** * xrdp: A Remote Desktop Protocol server. * * 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. * * This file implements the interface in chansrv_config.h */ #if defined(HAVE_CONFIG_H) #include #endif #include #include #include #include "arch.h" #include "list.h" #include "log.h" #include "file.h" #include "os_calls.h" #include "chansrv_common.h" #include "chansrv_config.h" #include "string_calls.h" /* Default settings */ #define DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD 0 #define DEFAULT_RESTRICT_INBOUND_CLIPBOARD 0 #define DEFAULT_ENABLE_FUSE_MOUNT 1 #define DEFAULT_FUSE_MOUNT_NAME "xrdp-client" #define DEFAULT_FILE_UMASK 077 #define DEFAULT_USE_NAUTILUS3_FLIST_FORMAT 0 /** * Type used for passing a logging function about */ typedef printflike(2, 3) enum logReturns (*log_func_t)(const enum logLevels lvl, const char *msg, ...); /* Map clipboard strings into bitmask values */ static const struct bitmask_string clip_restrict_map[] = { { CLIP_RESTRICT_TEXT, "text"}, { CLIP_RESTRICT_FILE, "file"}, { CLIP_RESTRICT_IMAGE, "image"}, { CLIP_RESTRICT_ALL, "all"}, { CLIP_RESTRICT_NONE, "none"}, /* Compatibility values */ { CLIP_RESTRICT_ALL, "true"}, { CLIP_RESTRICT_ALL, "yes"}, { CLIP_RESTRICT_NONE, "false"}, BITMASK_STRING_END_OF_LIST }; /***************************************************************************//** * @brief Error logging function to use to log to stdout * * Has the same signature as the log_message() function */ static enum logReturns log_to_stdout(const enum logLevels lvl, const char *msg, ...) { char buff[256]; va_list ap; va_start(ap, msg); vsnprintf(buff, sizeof(buff), msg, ap); va_end(ap); g_writeln("%s", buff); return LOG_STARTUP_OK; } /***************************************************************************//** * Reads the config values we need from the [Security] section * * @param logmsg Function to use to log messages * @param names List of definitions in the section * @params values List of corresponding values for the names * @params cfg Pointer to structure we're filling in * * @return 0 for success */ static int read_config_security(log_func_t logmsg, struct list *names, struct list *values, struct config_chansrv *cfg) { int error = 0; int index; for (index = 0; index < names->count; ++index) { const char *name = (const char *)list_get_item(names, index); const char *value = (const char *)list_get_item(values, index); char unrecognised[256]; if (g_strcasecmp(name, "RestrictOutboundClipboard") == 0) { cfg->restrict_outbound_clipboard = g_str_to_bitmask(value, clip_restrict_map, ",", unrecognised, sizeof(unrecognised)); if (unrecognised[0] != '\0') { LOG(LOG_LEVEL_WARNING, "Unrecognised tokens parsing 'RestrictOutboundClipboard' %s", unrecognised); } } if (g_strcasecmp(name, "RestrictInboundClipboard") == 0) { cfg->restrict_inbound_clipboard = g_str_to_bitmask(value, clip_restrict_map, ",", unrecognised, sizeof(unrecognised)); if (unrecognised[0] != '\0') { LOG(LOG_LEVEL_WARNING, "Unrecognised tokens parsing 'RestrictInboundClipboard' %s", unrecognised); } } } return error; } /***************************************************************************//** * Reads the config values we need from the [Chansrv] section * * @param logmsg Function to use to log messages * @param names List of definitions in the section * @params values List of corresponding values for the names * @params cfg Pointer to structure we're filling in * * @return 0 for success */ static int read_config_chansrv(log_func_t logmsg, struct list *names, struct list *values, struct config_chansrv *cfg) { int error = 0; int index; for (index = 0; index < names->count; ++index) { const char *name = (const char *)list_get_item(names, index); const char *value = (const char *)list_get_item(values, index); if (g_strcasecmp(name, "EnableFuseMount") == 0) { cfg->enable_fuse_mount = g_text2bool(value); } else if (g_strcasecmp(name, "FuseMountName") == 0) { g_free(cfg->fuse_mount_name); cfg->fuse_mount_name = g_strdup(value); if (cfg->fuse_mount_name == NULL) { logmsg(LOG_LEVEL_ERROR, "Can't alloc FuseMountName"); error = 1; break; } } else if (g_strcasecmp(name, "FileUmask") == 0) { cfg->file_umask = strtol(value, NULL, 0); } else if (g_strcasecmp(name, "UseNautilus3FlistFormat") == 0) { cfg->use_nautilus3_flist_format = g_text2bool(value); } } return error; } /***************************************************************************//** * @brief returns a config block with default values * * @return Block, or NULL for no memory */ static struct config_chansrv * new_config(void) { /* Do all the allocations at the beginning, then check them together */ struct config_chansrv *cfg = g_new0(struct config_chansrv, 1); char *fuse_mount_name = g_strdup(DEFAULT_FUSE_MOUNT_NAME); if (cfg == NULL || fuse_mount_name == NULL) { /* At least one memory allocation failed */ g_free(fuse_mount_name); g_free(cfg); cfg = NULL; } else { cfg->enable_fuse_mount = DEFAULT_ENABLE_FUSE_MOUNT; cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD; cfg->restrict_inbound_clipboard = DEFAULT_RESTRICT_INBOUND_CLIPBOARD; cfg->fuse_mount_name = fuse_mount_name; cfg->file_umask = DEFAULT_FILE_UMASK; cfg->use_nautilus3_flist_format = DEFAULT_USE_NAUTILUS3_FLIST_FORMAT; } return cfg; } /******************************************************************************/ struct config_chansrv * config_read(int use_logger, const char *sesman_ini) { int error = 0; struct config_chansrv *cfg = NULL; log_func_t logmsg = (use_logger) ? log_message : log_to_stdout; int fd; fd = g_file_open_ex(sesman_ini, 1, 0, 0, 0); if (fd < 0) { logmsg(LOG_LEVEL_ERROR, "Can't open config file %s", sesman_ini); error = 1; } else { if ((cfg = new_config()) == NULL) { logmsg(LOG_LEVEL_ERROR, "Can't alloc config block"); error = 1; } else { struct list *names = list_create(); struct list *values = list_create(); names->auto_free = 1; values->auto_free = 1; if (!error && file_read_section(fd, "Security", names, values) == 0) { error = read_config_security(logmsg, names, values, cfg); } if (!error && file_read_section(fd, "Chansrv", names, values) == 0) { error = read_config_chansrv(logmsg, names, values, cfg); } list_delete(names); list_delete(values); } g_file_close(fd); } if (error) { config_free(cfg); cfg = NULL; } return cfg; } /******************************************************************************/ void config_dump(struct config_chansrv *config) { g_writeln("Global configuration:"); char buf[256]; g_writeln("\nSecurity configuration:"); if (config->restrict_outbound_clipboard == CLIP_RESTRICT_NONE) { g_writeln(" RestrictOutboundClipboard: %s", "none"); } else if (config->restrict_outbound_clipboard == CLIP_RESTRICT_ALL) { g_writeln(" RestrictOutboundClipboard: %s", "all"); } else { g_bitmask_to_str(config->restrict_outbound_clipboard, clip_restrict_map, ',', buf, sizeof(buf)); g_writeln(" RestrictOutboundClipboard: %s", buf); } if (config->restrict_inbound_clipboard == CLIP_RESTRICT_NONE) { g_writeln(" RestrictInboundClipboard: %s", "none"); } else if (config->restrict_inbound_clipboard == CLIP_RESTRICT_ALL) { g_writeln(" RestrictInboundClipboard: %s", "all"); } else { g_bitmask_to_str(config->restrict_inbound_clipboard, clip_restrict_map, ',', buf, sizeof(buf)); g_writeln(" RestrictInboundClipboard: %s", buf); } g_writeln("\nChansrv configuration:"); g_writeln(" EnableFuseMount %s", g_bool2text(config->enable_fuse_mount)); g_writeln(" FuseMountName: %s", config->fuse_mount_name); g_writeln(" FileMask: 0%o", config->file_umask); g_writeln(" Nautilus 3 Flist Format: %s", g_bool2text(config->use_nautilus3_flist_format)); } /******************************************************************************/ void config_free(struct config_chansrv *cc) { if (cc != NULL) { g_free(cc->fuse_mount_name); g_free(cc); } }