* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004, 2015
+/*
+ * Copyright (c) The Exim Maintainers 2015 - 2022
+ * Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2015
* License: GPL
- * Copyright (c) The Exim Maintainers 2016
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "exim.h"
uschar *mime_current_boundary = NULL;
static mime_header mime_header_list[] = {
+ /* name namelen value */
{ US"content-type:", 13, &mime_content_type },
{ US"content-disposition:", 20, &mime_content_disposition },
{ US"content-transfer-encoding:", 26, &mime_content_transfer_encoding },
static int mime_header_list_size = nelem(mime_header_list);
static mime_parameter mime_parameter_list[] = {
+ /* name namelen value */
{ US"name=", 5, &mime_filename },
{ US"filename=", 9, &mime_filename },
{ US"charset=", 8, &mime_charset },
static ssize_t
mime_decode_asis(FILE* in, FILE* out, uschar* boundary)
{
- ssize_t len, size = 0;
- uschar buffer[MIME_MAX_LINE_LENGTH];
+ssize_t len, size = 0;
+uschar buffer[MIME_MAX_LINE_LENGTH];
- while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL)
- {
- if (boundary != NULL
- && Ustrncmp(buffer, "--", 2) == 0
- && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0
- )
- break;
+while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL)
+ {
+ if (boundary != NULL
+ && Ustrncmp(buffer, "--", 2) == 0
+ && Ustrncmp((buffer+2), boundary, Ustrlen(boundary)) == 0
+ )
+ break;
- len = Ustrlen(buffer);
- if (fwrite(buffer, 1, (size_t)len, out) < len)
- return -1;
- size += len;
- } /* while */
- return size;
+ len = Ustrlen(buffer);
+ if (fwrite(buffer, 1, (size_t)len, out) < len)
+ return -1;
+ size += len;
+ } /* while */
+return size;
}
{
/* Error from decoder. ipos is unchanged. */
mime_set_anomaly(MIME_ANOMALY_BROKEN_QP);
- *opos = '=';
- ++opos;
+ *opos++ = '=';
++ipos;
}
else if (decode_qp_result == -1)
break;
else if (decode_qp_result >= 0)
- {
- *opos = decode_qp_result;
- ++opos;
- }
+ *opos++ = decode_qp_result;
}
else
- {
- *opos = *ipos;
- ++opos;
- ++ipos;
- }
+ *opos++ = *ipos++;
}
/* something to write? */
len = opos - obuf;
{
int sep = 0;
const uschar *list = *listptr;
-uschar *option;
-uschar option_buffer[1024];
-uschar decode_path[1024];
+uschar * option;
+uschar * decode_path;
FILE *decode_file = NULL;
long f_pos = 0;
ssize_t size_counter = 0;
return FAIL;
/* build default decode path (will exist since MBOX must be spooled up) */
-(void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id);
+decode_path = string_sprintf("%s/scan/%s", spool_directory, message_id);
/* try to find 1st option */
-if ((option = string_nextinlist(&list, &sep,
- option_buffer,
- sizeof(option_buffer))) != NULL)
+if ((option = string_nextinlist(&list, &sep, NULL, 0)))
{
/* parse 1st option */
if ((Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0))
if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) )
continue;
- /* we have hit a non-whitespace char, start copying value data */
- header_value_mode = 2;
+ /* we have hit a non-whitespace char, start copying value data */
+ header_value_mode = 2;
- if (c == '"') /* flip "quoted" mode */
- header_value_mode = header_value_mode==2 ? 3 : 2;
+ if (c == '"') /* flip "quoted" mode */
+ header_value_mode = header_value_mode==2 ? 3 : 2;
- /* leave value mode on unquoted ';' */
- if (header_value_mode == 2 && c == ';') {
- header_value_mode = 0;
- };
- /* -------------------------------- */
+ /* leave value mode on unquoted ';' */
+ if (header_value_mode == 2 && c == ';')
+ header_value_mode = 0;
+ /* -------------------------------- */
}
else
{
header[num_copied] = '\0';
/* return 0 for EOF or empty line */
-if ((c == EOF) || (num_copied == 1))
- return 0;
-else
- return 1;
+return c == EOF || num_copied == 1 ? 0 : 1;
}
+/* reset all per-part mime variables */
static void
mime_vars_reset(void)
{
mime_param_val(uschar ** sp)
{
uschar * s = *sp;
-uschar * val = NULL;
-int size = 0, ptr = 0;
+gstring * val = NULL;
/* debug_printf_indent(" considering paramval '%s'\n", s); */
{
s++; /* skip opening " */
while (*s && *s != '"') /* " protects ; */
- val = string_catn(val, &size, &ptr, s++, 1);
+ val = string_catn(val, s++, 1);
if (*s) s++; /* skip closing " */
}
else
- val = string_catn(val, &size, &ptr, s++, 1);
-if (val) val[ptr] = '\0';
+ val = string_catn(val, s++, 1);
*sp = s;
-return val;
+return string_from_gstring(val);
}
static uschar *
static uschar *
rfc2231_to_2047(const uschar * fname, const uschar * charset, int * len)
{
-int size = 0, ptr = 0;
-uschar * val = string_catn(NULL, &size, &ptr, US"=?", 2);
+gstring * val = string_catn(NULL, US"=?", 2);
uschar c;
if (charset)
- val = string_cat(val, &size, &ptr, charset);
-val = string_catn(val, &size, &ptr, US"?Q?", 3);
+ val = string_cat(val, charset);
+val = string_catn(val, US"?Q?", 3);
while ((c = *fname))
if (c == '%' && isxdigit(fname[1]) && isxdigit(fname[2]))
{
- val = string_catn(val, &size, &ptr, US"=", 1);
- val = string_catn(val, &size, &ptr, ++fname, 2);
+ val = string_catn(val, US"=", 1);
+ val = string_catn(val, ++fname, 2);
fname += 2;
}
else
- val = string_catn(val, &size, &ptr, fname++, 1);
+ val = string_catn(val, fname++, 1);
-val = string_catn(val, &size, &ptr, US"?=", 2);
-val[*len = ptr] = '\0';
-return val;
+val = string_catn(val, US"?=", 2);
+*len = gstring_length(val);
+return string_from_gstring(val);
}
uschar * header = NULL;
struct mime_boundary_context nested_context;
-/* reserve a line buffer to work in */
-header = store_get(MIME_MAX_HEADER_SIZE+1);
+/* reserve a line buffer to work in. Assume tainted data. */
+header = store_get(MIME_MAX_HEADER_SIZE+1, GET_TAINTED);
/* Not actually used at the moment, but will be vital to fixing
* some RFC 2046 nonconformance later... */
/* parse headers, set up expansion variables */
while (mime_get_header(f, header))
- {
- struct mime_header * mh;
/* look for interesting headers */
- for (mh = mime_header_list;
+ for (struct mime_header * mh = mime_header_list;
mh < mime_header_list + mime_header_list_size;
mh++) if (strncmpic(mh->name, header, mh->namelen) == 0)
{
while (*p)
{
- mime_parameter * mp;
-
DEBUG(D_acl) debug_printf_indent("MIME: considering paramlist '%s'\n", p);
if ( !mime_filename
NULL, &err_msg);
DEBUG(D_acl) debug_printf_indent("MIME: plain-name %s\n", temp_string);
- size = Ustrlen(temp_string);
-
- if (size == slen)
+ if (!temp_string || (size = Ustrlen(temp_string)) == slen)
decoding_failed = TRUE;
else
/* build up a decoded filename over successive
else
/* look for interesting parameters */
- for (mp = mime_parameter_list;
+ for (mime_parameter * mp = mime_parameter_list;
mp < mime_parameter_list + nelem(mime_parameter_list);
mp++
) if (strncmpic(mp->name, p, mp->namelen) == 0)
}
}
}
- }
/* set additional flag variables (easier access) */
if ( mime_content_type
if (rc != OK) break;
/* If we have a multipart entity and a boundary, go recursive */
- if ( (mime_content_type != NULL) &&
- (nested_context.boundary != NULL) &&
- (Ustrncmp(mime_content_type,"multipart",9) == 0) )
+ if ( mime_content_type && nested_context.boundary
+ && Ustrncmp(mime_content_type,"multipart",9) == 0)
{
DEBUG(D_acl)
debug_printf_indent("MIME: Entering multipart recursion, boundary '%s'\n",
rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr);
if (rc != OK) break;
}
- else if ( (mime_content_type != NULL) &&
- (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) )
+ else if ( mime_content_type
+ && Ustrncmp(mime_content_type,"message/rfc822",14) == 0)
{
- const uschar *rfc822name = NULL;
- uschar filename[2048];
+ const uschar * rfc822name = NULL;
+ uschar * filename;
int file_nr = 0;
int result = 0;
/* must find first free sequential filename */
- do
+ for (gstring * g = string_get(64); result != -1; gstring_reset(g))
{
struct stat mystat;
- (void)string_format(filename, 2048,
+ g = string_fmt_append(g,
"%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr++);
/* security break */
if (file_nr >= 128)
goto NO_RFC822;
- result = stat(CS filename,&mystat);
- } while (result != -1);
+ result = stat(CS (filename = string_from_gstring(g)), &mystat);
+ }
rfc822name = filename;