diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-23 16:17:47 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-23 16:17:47 +0000 |
commit | 766d41f8bf91a6d209c66e8fd12dbd6688ce2739 (patch) | |
tree | 12552a0788d42ac73e7260b883aa84a8045e957a /src/config.c | |
parent | c7e791e9563b7805fc7a375bc7e616b4252a9c57 (diff) | |
download | wydawca-766d41f8bf91a6d209c66e8fd12dbd6688ce2739.tar.gz wydawca-766d41f8bf91a6d209c66e8fd12dbd6688ce2739.tar.bz2 |
Improve safety checks; implement symlink/rmsymlink/archive directives; Fix directive signature verification.
git-svn-id: file:///svnroot/wydawca/trunk@286 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
Diffstat (limited to 'src/config.c')
-rw-r--r-- | src/config.c | 54 |
1 files changed, 44 insertions, 10 deletions
diff --git a/src/config.c b/src/config.c index ae7c974..8c4afd1 100644 --- a/src/config.c +++ b/src/config.c @@ -1,4 +1,4 @@ -/* wydawca - FTP release synchronisation daemon +/* wydawca - FTP release synchronization daemon Copyright (C) 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ static struct access_method default_gpg_key_method; #define skip_ws(s) while (*(s) && isspace (*(s))) (s)++; #define skip_word(s) while (*(s) && !isspace (*(s))) (s)++; +/* Return a pointer to the next word from *PSTR. Advanse *PSTR to the beginning + of next word, or to the terminating \0, whichever comes first. */ static char * get_word (char **pstr) { @@ -49,6 +51,8 @@ get_word (char **pstr) return word; } +/* Convert a boolean from STR into its C representation. If STR is a valid + boolean, store the result in *PVAL and return 0. Otherwise, return 1 */ static int get_bool (char *str, int *pval) { @@ -77,6 +81,7 @@ get_bool (char *str, int *pval) /home/user/../smith --> /home/smith /home/user/../.. --> / + ../file --> NULL */ char * safe_file_name (char *file_name) @@ -96,32 +101,49 @@ safe_file_name (char *file_name) /* delete trailing delimiter if any */ if (len && file_name[len-1] == '/') file_name[len-1] = 0; - - /* Eliminate any /../ */ + + /* Eliminate any ./ and /../ */ for (p = strchr (file_name, '.'); p; p = strchr (p, '.')) { - if (p > file_name && p[-1] == '/') + if (p[1] == '/' && (p == file_name || p[-1] == '/')) { - if (p[1] == '.' && (p[2] == 0 || p[2] == '/')) + char *q, *s; + + s = p + 2; + q = p; + while ((*q++ = *s++)) + ; + continue; + } + else if (p[1] == '.' && (p[2] == 0 || p[2] == '/')) + { + if (p == file_name) + return NULL; + if (p[-1] == '/') /* found */ { char *q, *s; + s = p + 2; + /* Find previous delimiter */ for (q = p-2; *q != '/' && q >= file_name; q--) ; if (q < file_name) - break; + { + q = file_name; + s++; + } + /* Copy stuff */ - s = p + 2; p = q; while ((*q++ = *s++)) ; continue; } } - + p++; } @@ -134,10 +156,15 @@ safe_file_name (char *file_name) return file_name; } +/* Same as safe_file_name, but returns an allocated copy. */ char * safe_file_name_alloc (const char *file_name) { - return safe_file_name (xstrdup (file_name)); + char *s = xstrdup (file_name); + char *ns = safe_file_name (s); + if (!ns) + free (s); + return ns; } @@ -329,6 +356,13 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data) return; } dp->archive.name = safe_file_name (xstrdup (word)); + if (!dp->archive.name) + { + file->error_msg (file->file_name, file->line, + "invalid archive name: %s", word); + file->error_count++; + return; + } word = get_word (&val); @@ -544,7 +578,7 @@ cfg_tar_program (gsc_config_file_t *file, char *kw, char *val, void *unused) { char *word = safe_file_name (get_word (&val)); - if (word[0] != '/') + if (!word || word[0] != '/') { file->error_msg (file->file_name, file->line, "must be an absolute file name"); |