summaryrefslogtreecommitdiff
path: root/main/config.c
diff options
context:
space:
mode:
authorGeorge Joseph <gjoseph@digium.com>2016-04-24 21:51:16 -0600
committerGeorge Joseph <gjoseph@digium.com>2016-04-25 18:17:28 -0500
commit284bb814ac09a10e3bababa2e126d69d16fd93c4 (patch)
tree3bd2a372ba65c38c62274b3ca18730ff1103dd08 /main/config.c
parent99fcf2a791c2c78ae0ffffce2ac3e8db18ca5be0 (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/config.c')
-rw-r--r--main/config.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/main/config.c b/main/config.c
index dad3b668b..599270384 100644
--- a/main/config.c
+++ b/main/config.c
@@ -36,6 +36,9 @@ ASTERISK_REGISTER_FILE()
#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;
}