diff options
author | George Joseph <gjoseph@digium.com> | 2016-04-24 21:51:16 -0600 |
---|---|---|
committer | George Joseph <gjoseph@digium.com> | 2016-04-25 18:16:58 -0500 |
commit | b38f1146e54f295c89727de4fde150ed731d5b64 (patch) | |
tree | 0eae2d58aeac59b32c7d348bed3765e09991d2bc /main | |
parent | 13ee3402ed8e22fa9d4cfbe8750db3d0b4461935 (diff) |
config: Fix ast_config_text_file_save2 writability check for missing files
A patch I did back in 2014 modified ast_config_text_file_save2 to check the
writability of the main file and include files before truncating and re-writing
them. An unintended side-effect of this was that if a file doesn't exist,
the check fails and the write is aborted.
This patch causes ast_config_text_file_save2 to check the writability of the
parent directory of missing files instead of checking the file itself. This
allows missing files to be created again. A unit test was also added to
test_config to test saving of config files.
The regression was discovered when app_voicemail's passwordlocation=spooldir
feature stopped working.
ASTERISK-25917 #close
Reported-by: Jonathan Rose
Change-Id: Ic4dbe58c277a47b674679e49daed5fc6de349f80
Diffstat (limited to 'main')
-rw-r--r-- | main/config.c | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/main/config.c b/main/config.c index 2a6baa133..ffada0bf3 100644 --- a/main/config.c +++ b/main/config.c @@ -36,6 +36,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */ #include "asterisk/network.h" /* we do some sockaddr manipulation here */ + +#include <string.h> +#include <libgen.h> #include <time.h> #include <sys/stat.h> @@ -2512,6 +2515,25 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c return ast_config_text_file_save2(configfile, cfg, generator, CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT); } +static int is_writable(const char *fn) +{ + if (access(fn, F_OK)) { + char *dn = dirname(ast_strdupa(fn)); + + if (access(dn, R_OK | W_OK)) { + ast_log(LOG_ERROR, "Unable to write to directory %s (%s)\n", dn, strerror(errno)); + return 0; + } + } else { + if (access(fn, R_OK | W_OK)) { + ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + return 0; + } + } + + return 1; +} + int ast_config_text_file_save2(const char *configfile, const struct ast_config *cfg, const char *generator, uint32_t flags) { FILE *f; @@ -2534,20 +2556,20 @@ int ast_config_text_file_save2(const char *configfile, const struct ast_config * for (incl = cfg->includes; incl; incl = incl->next) { /* reset all the output flags in case this isn't our first time saving this data */ incl->output = 0; - /* now make sure we have write access */ + if (!incl->exec) { + /* now make sure we have write access to the include file or its parent directory */ make_fn(fn, sizeof(fn), incl->included_file, configfile); - if (access(fn, R_OK | W_OK)) { - ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + /* If the file itself doesn't exist, make sure we have write access to the directory */ + if (!is_writable(fn)) { return -1; } } } - /* now make sure we have write access to the main config file */ + /* now make sure we have write access to the main config file or its parent directory */ make_fn(fn, sizeof(fn), 0, configfile); - if (access(fn, R_OK | W_OK)) { - ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno)); + if (!is_writable(fn)) { return -1; } |