X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b273058b341903372bdebe67d2960e4f8d2d8689..1241deaefb71c40436320af7d0bd04c7c9e54241:/src/src/string.c diff --git a/src/src/string.c b/src/src/string.c index 9f1aeb81d..27e030bd8 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ /* Miscellaneous string-handling functions. Some are not required for @@ -12,7 +13,6 @@ utilities and tests, and are cut out by the COMPILE_UTILITY macro. */ #include "exim.h" #include -static void gstring_rebuffer(gstring * g); #ifndef COMPILE_UTILITY /************************************************* @@ -281,17 +281,17 @@ return ch; /* This function is called for critical strings. It checks for any non-printing characters, and if any are found, it makes a new copy of the string with suitable escape sequences. It is most often called by the -macro string_printing(), which sets allow_tab TRUE. +macro string_printing(), which sets flags to 0. Arguments: s the input string - allow_tab TRUE to allow tab as a printing character + flags Bit 0: convert tabs. Bit 1: convert spaces. Returns: string with non-printers encoded as printing sequences */ const uschar * -string_printing2(const uschar *s, BOOL allow_tab) +string_printing2(const uschar *s, int flags) { int nonprintcount = 0; int length = 0; @@ -301,7 +301,10 @@ uschar *ss, *tt; while (*t != 0) { int c = *t++; - if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++; + if ( !mac_isprint(c) + || flags & SP_TAB && c == '\t' + || flags & SP_SPACE && c == ' ' + ) nonprintcount++; length++; } @@ -310,17 +313,19 @@ if (nonprintcount == 0) return s; /* Get a new block of store guaranteed big enough to hold the expanded string. */ -ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s)); +tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s)); /* Copy everything, escaping non printers. */ -t = s; -tt = ss; - -while (*t != 0) +for (t = s; *t; ) { int c = *t; - if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else + if ( mac_isprint(c) + && (!(flags & SP_TAB) || c != '\t') + && (!(flags & SP_SPACE) || c != ' ') + ) + *tt++ = *t++; + else { *tt++ = '\\'; switch (*t) @@ -575,18 +580,14 @@ uschar *ss = yield = store_get(Ustrlen(s) + 1, is_tainted(s)); while (*s != 0) { if (*s != '\\') - { *ss++ = *s++; - } else if (isdigit(s[1])) { *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0'; s += 4; } else if (*(++s) != 0) - { *ss++ = *s++; - } } *ss = 0; @@ -864,7 +865,8 @@ Returns: pointer to buffer, containing the next substring, */ uschar * -string_nextinlist(const uschar **listptr, int *separator, uschar *buffer, int buflen) +string_nextinlist_trc(const uschar **listptr, int *separator, uschar *buffer, int buflen, + const uschar * func, int line) { int sep = *separator; const uschar *s = *listptr; @@ -907,6 +909,8 @@ sep_is_special = iscntrl(sep); if (buffer) { int p = 0; + if (is_tainted(s) && !is_tainted(buffer)) + die_tainted(US"string_nextinlist", func, line); for (; *s; s++) { if (*s == sep && (*(++s) != sep || sep_is_special)) break; @@ -948,7 +952,10 @@ else s = ss; if (!*s || *++s != sep || sep_is_special) break; } - while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; + /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */ + while ( g->ptr > 0 && isspace(g->s[g->ptr-1]) + && (g->ptr == 1 || g->s[g->ptr-2] != '\\') ) + g->ptr--; buffer = string_from_gstring(g); gstring_release_unused(g); } @@ -1084,7 +1091,16 @@ existing length of the string. */ unsigned inc = oldsize < 4096 ? 127 : 1023; +if (g->ptr < 0 || g->ptr > g->size || g->size >= INT_MAX/2) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "internal error in gstring_grow (ptr %d size %d)", g->ptr, g->size); + if (count <= 0) return; + +if (count >= INT_MAX/2 - g->ptr) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "internal error in gstring_grow (ptr %d count %d)", g->ptr, count); + g->size = (p + count + inc + 1) & ~inc; /* one for a NUL */ /* Try to extend an existing allocation. If the result of calling @@ -1133,6 +1149,10 @@ string_catn(gstring * g, const uschar *s, int count) int p; BOOL srctaint = is_tainted(s); +if (count < 0) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "internal error in string_catn (count %d)", count); + if (!g) { unsigned inc = count < 4096 ? 127 : 1023; @@ -1142,8 +1162,12 @@ if (!g) else if (srctaint && !is_tainted(g->s)) gstring_rebuffer(g); +if (g->ptr < 0 || g->ptr > g->size) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, + "internal error in string_catn (ptr %d size %d)", g->ptr, g->size); + p = g->ptr; -if (p + count >= g->size) +if (count >= g->size - p) gstring_grow(g, count); /* Because we always specify the exact number of characters to copy, we can @@ -1243,16 +1267,6 @@ return !!gp; -/* Copy the content of a string to tainted memory */ -static void -gstring_rebuffer(gstring * g) -{ -uschar * s = store_get(g->size, TRUE); -memcpy(s, g->s, g->ptr); -g->s = s; -} - - /* Build or append to a growing-string, sprintf-style. @@ -1649,7 +1663,7 @@ doesn't seem much we can do about that. */ va_start(ap, format); (void) string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE, - 0, format, ap); + SVFMT_REBUFFER, format, ap); string_from_gstring(g); gstring_release_unused(g); va_end(ap);