From 5887bd6f15f52f56bd18ad688056491fcfca2bb7 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Sun, 14 Apr 2019 13:34:37 -0700 Subject: [PATCH] Convert rfc1524_expand_command() implementation to use struct Buffer Add mutt_buffer_sanitize_filename() helper. Add a few end-of-buffer checks while iterating over command. Convert the parameter name, paramater value, and types to use struct Buffer instead of fixed size strings. --- mutt/file.c | 4 +- mutt/file.h | 1 + muttlib.c | 24 +++++++++++- muttlib.h | 1 + rfc1524.c | 106 +++++++++++++++++++++++++--------------------------- 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/mutt/file.c b/mutt/file.c index 76bd9fe25..620bd6fb3 100644 --- a/mutt/file.c +++ b/mutt/file.c @@ -54,7 +54,7 @@ char *C_Tmpdir; ///< Config: Directory for temporary files /* these characters must be escaped in regular expressions */ static const char rx_special_chars[] = "^.[$()|*+?{\\"; -static const char safe_chars[] = +const char filename_safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"; #define MAX_LOCK_ATTEMPTS 5 @@ -618,7 +618,7 @@ void mutt_file_sanitize_filename(char *path, bool slash) for (; *path; path++) { - if ((slash && (*path == '/')) || !strchr(safe_chars, *path)) + if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path)) *path = '_'; } } diff --git a/mutt/file.h b/mutt/file.h index 79acb5ae8..e9fdc6718 100644 --- a/mutt/file.h +++ b/mutt/file.h @@ -32,6 +32,7 @@ struct Buffer; struct stat; extern char *C_Tmpdir; +extern const char filename_safe_chars[]; /* Flags for mutt_file_read_line() */ #define MUTT_CONT (1 << 0) /**< \-continuation */ diff --git a/muttlib.c b/muttlib.c index 9e2348cd4..e8b873821 100644 --- a/muttlib.c +++ b/muttlib.c @@ -97,7 +97,7 @@ void mutt_adv_mktemp(struct Buffer *buf) { struct Buffer *prefix = mutt_buffer_pool_get(); mutt_buffer_strcpy(prefix, buf->data); - mutt_file_sanitize_filename(prefix->data, 1); + mutt_file_sanitize_filename(prefix->data, true); mutt_buffer_printf(buf, "%s/%s", NONULL(C_Tmpdir), mutt_b2s(prefix)); struct stat sb; @@ -1691,3 +1691,25 @@ int mutt_inbox_cmp(const char *a, const char *b) return 0; } + +/** + * mutt_buffer_sanitize_filename - Replace unsafe characters in a filename + * @param buf Buffer for the result + * @param path Filename to make safe + * @param slash Replace '/' characters too + */ +void mutt_buffer_sanitize_filename(struct Buffer *buf, const char *path, short slash) +{ + if (!buf || !path) + return; + + mutt_buffer_reset(buf); + + for (; *path; path++) + { + if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path)) + mutt_buffer_addch(buf, '_'); + else + mutt_buffer_addch(buf, *path); + } +} diff --git a/muttlib.h b/muttlib.h index ce09d711f..a6ec969d0 100644 --- a/muttlib.h +++ b/muttlib.h @@ -48,6 +48,7 @@ void mutt_buffer_mktemp_full(struct Buffer *buf, const char *prefix, cons void mutt_buffer_expand_path(struct Buffer *buf); void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex); void mutt_buffer_pretty_mailbox(struct Buffer *s); +void mutt_buffer_sanitize_filename (struct Buffer *buf, const char *path, short slash); int mutt_check_overwrite(const char *attname, const char *path, char *fname, size_t flen, enum SaveAttach *opt, char **directory); void mutt_encode_path(char *dest, size_t dlen, const char *src); void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags); diff --git a/rfc1524.c b/rfc1524.c index e6d934632..4c4dabc65 100644 --- a/rfc1524.c +++ b/rfc1524.c @@ -50,12 +50,11 @@ bool C_MailcapSanitize; ///< Config: Restrict the possible characters in mailcap expandos /** - * rfc1524_expand_command - Expand expandos in a command + * mutt_buffer_rfc1524_expand_command - Expand expandos in a command * @param a Email Body * @param filename File containing the email text * @param type Type, e.g. "text/plain" * @param command Buffer containing command - * @param clen Length of buffer * @retval 0 Command works on a file * @retval 1 Command works on a pipe * @@ -69,99 +68,94 @@ bool C_MailcapSanitize; ///< Config: Restrict the possible characters in mailcap * %n is the integer number of sub-parts in the multipart * %F is "content-type filename" repeated for each sub-part */ -int rfc1524_expand_command(struct Body *a, const char *filename, - const char *type, char *command, int clen) +int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, + const char *type, struct Buffer *command) { - int x = 0; int needspipe = true; - char type2[1024]; struct Buffer *buf = mutt_buffer_pool_get(); struct Buffer *quoted = mutt_buffer_pool_get(); + struct Buffer *param = NULL; + struct Buffer *type2 = NULL; - mutt_str_strfcpy(type2, type, sizeof(type2)); - - if (C_MailcapSanitize) - mutt_file_sanitize_filename(type2, false); - - while ((x < clen - 1) && command[x]) + const char *cptr = mutt_b2s(command); + while (*cptr) { - if (command[x] == '\\') + if (*cptr == '\\') { - x++; - mutt_buffer_addch(buf, command[x++]); + cptr++; + if (*cptr) + mutt_buffer_addch(buf, *cptr++); } - else if (command[x] == '%') + else if (*cptr == '%') { - x++; - if (command[x] == '{') + cptr++; + if (*cptr == '{') { - char param[256]; - char pvalue[256]; - char *pvalue2 = NULL; - int z = 0; + const char *pvalue2 = NULL; + + if (!param) + param = mutt_buffer_pool_get(); + else + mutt_buffer_reset(param); - x++; - while (command[x] && (command[x] != '}') && (z < sizeof(param) - 1)) - param[z++] = command[x++]; - param[z] = '\0'; + /* Copy parameter name into param buffer */ + cptr++; + while (*cptr && (*cptr != '}')) + mutt_buffer_addch(param, *cptr++); /* In send mode, use the current charset, since the message hasn't * been converted yet. If noconv is set, then we assume the * charset parameter has the correct value instead. */ - if ((mutt_str_strcasecmp(param, "charset") == 0) && a->charset && !a->noconv) + if ((mutt_str_strcasecmp(mutt_b2s(param), "charset") == 0) && a->charset && !a->noconv) pvalue2 = a->charset; else - pvalue2 = mutt_param_get(&a->parameter, param); - mutt_str_strfcpy(pvalue, pvalue2, sizeof(pvalue)); + pvalue2 = mutt_param_get(&a->parameter, mutt_b2s(param)); + + /* Now copy the parameter value into param buffer */ if (C_MailcapSanitize) - mutt_file_sanitize_filename(pvalue, false); + mutt_buffer_sanitize_filename(param, NONULL(pvalue2), false); + else + mutt_buffer_strcpy(param, NONULL(pvalue2)); - mutt_buffer_quote_filename(quoted, pvalue, true); + mutt_buffer_quote_filename(quoted, mutt_b2s(param), true); mutt_buffer_addstr(buf, mutt_b2s(quoted)); } - else if ((command[x] == 's') && filename) + else if ((*cptr == 's') && filename) { mutt_buffer_quote_filename(quoted, filename, true); mutt_buffer_addstr(buf, mutt_b2s(quoted)); needspipe = false; } - else if (command[x] == 't') + else if (*cptr == 't') { - mutt_buffer_quote_filename(quoted, type, true); + if (!type2) + { + type2 = mutt_buffer_pool_get(); + if (C_MailcapSanitize) + mutt_buffer_sanitize_filename(type2, type, false); + else + mutt_buffer_strcpy(type2, type); + } + mutt_buffer_quote_filename(quoted, mutt_b2s(type2), true); mutt_buffer_addstr(buf, mutt_b2s(quoted)); } - x++; + + if (*cptr) + cptr++; } else - mutt_buffer_addch(buf, command[x++]); + mutt_buffer_addch(buf, *cptr++); } - mutt_str_strfcpy(command, mutt_b2s(buf), clen); + mutt_buffer_strcpy(command, mutt_b2s(buf)); mutt_buffer_pool_release(&buf); mutt_buffer_pool_release("ed); + mutt_buffer_pool_release(¶m); + mutt_buffer_pool_release(&type2); return needspipe; } -/** - * mutt_buffer_rfc1524_expand_command - Expand expandos in a command - * @param a Email Body - * @param filename File containing the email text - * @param type Type, e.g. "text/plain" - * @param command Buffer containing command - * @retval 0 Command works on a file - * @retval 1 Command works on a pipe - */ -int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, - const char *type, struct Buffer *command) -{ - mutt_buffer_increase_size(command, PATH_MAX); - int rc = rfc1524_expand_command(a, filename, type, command->data, command->dsize); - mutt_buffer_fix_dptr(command); - - return rc; -} - /** * get_field - NUL terminate a RFC1524 field * @param s String to alter -- 2.40.0