X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/20395676aba7fa5eb9a2c5e0b9f582ec2b3e71e4..HEAD:/src/src/rda.c diff --git a/src/src/rda.c b/src/src/rda.c index a12e5de29..405e4646a 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* This module contains code for extracting addresses from a forwarding list (from an alias or forward file) or by running the filter interpreter. It may do @@ -166,7 +167,7 @@ Returns: pointer to string in store; NULL on error */ static uschar * -rda_get_file_contents(redirect_block *rdata, int options, uschar **error, +rda_get_file_contents(const redirect_block *rdata, int options, uschar **error, int *yield) { FILE *fwd; @@ -179,8 +180,10 @@ struct stat statbuf; /* Reading a file is a form of expansion; we wish to deny attackers the capability to specify the file name. */ -if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename))) +if (is_tainted(filename)) { + *error = string_sprintf("Tainted name '%s' for file read not permitted\n", + filename); *yield = FF_ERROR; return NULL; } @@ -282,7 +285,7 @@ if (statbuf.st_size > MAX_FILTER_SIZE) /* Read the file in one go in order to minimize the time we have it open. */ -filebuf = store_get(statbuf.st_size + 1, is_tainted(filename)); +filebuf = store_get(statbuf.st_size + 1, filename); if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size) { @@ -319,10 +322,7 @@ Arguments: rdata the redirection block options the options bits include_directory restrain to this directory - sieve_vacation_directory passed to sieve_interpret - sieve_enotify_mailto_owner passed to sieve_interpret - sieve_useraddress passed to sieve_interpret - sieve_subaddress passed to sieve_interpret + sieve passed to sieve_interpret generated where to hang generated addresses error for error messages eblockp for details of skipped syntax errors @@ -337,13 +337,12 @@ Returns: a suitable return for rda_interpret() */ static int -rda_extract(redirect_block *rdata, int options, uschar *include_directory, - uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner, - uschar *sieve_useraddress, uschar *sieve_subaddress, - address_item **generated, uschar **error, error_block **eblockp, - int *filtertype) +rda_extract(const redirect_block * rdata, int options, + const uschar * include_directory, const sieve_block * sieve, + address_item ** generated, uschar ** error, + error_block ** eblockp, int * filtertype) { -uschar *data; +const uschar * data; if (rdata->isfile) { @@ -384,23 +383,40 @@ if (*filtertype != FILTER_FORWARD) if (*filtertype == FILTER_EXIM) { - if ((options & RDO_EXIM_FILTER) != 0) + const misc_module_info * mi; + typedef int (*fn_t)(const uschar *, int, address_item **, uschar **); + + if (options & RDO_EXIM_FILTER) { *error = US"Exim filtering not enabled"; return FF_ERROR; } - frc = filter_interpret(data, options, generated, error); + if (!(mi = misc_mod_find(US"exim_filter", NULL))) + { + *error = US"Exim-filtering not available"; + return FF_ERROR; + } + frc = (((fn_t *) mi->functions)[EXIM_INTERPRET]) + (data, options, generated, error); } else { + const misc_module_info * mi; + typedef int (*fn_t)(const uschar *, int, const sieve_block *, + address_item **, uschar **); + if (options & RDO_SIEVE_FILTER) { *error = US"Sieve filtering not enabled"; return FF_ERROR; } - frc = sieve_interpret(data, options, sieve_vacation_directory, - sieve_enotify_mailto_owner, sieve_useraddress, sieve_subaddress, - generated, error); + if (!(mi = misc_mod_find(US"sieve_filter", NULL))) + { + *error = US"Sieve filtering not available"; + return FF_ERROR; + } + frc = (((fn_t *) mi->functions)[SIEVE_INTERPRET]) + (data, options, sieve, generated, error); } expand_forbid = old_expand_forbid; @@ -440,9 +456,9 @@ Returns: -1 on error, else 0 static int rda_write_string(int fd, const uschar *s) { -int len = (s == NULL)? 0 : Ustrlen(s) + 1; +int len = s ? Ustrlen(s) + 1 : 0; return ( write(fd, &len, sizeof(int)) != sizeof(int) - || (s != NULL && write(fd, s, len) != len) + || (s && write(fd, s, len) != len) ) ? -1 : 0; } @@ -463,7 +479,7 @@ Returns: FALSE if data missing */ static BOOL -rda_read_string(int fd, uschar **sp) +rda_read_string(int fd, uschar ** sp) { int len; @@ -474,7 +490,7 @@ else /* We know we have enough memory so disable the error on "len" */ /* coverity[tainted_data] */ /* We trust the data source, so untainted */ - if (read(fd, *sp = store_get(len, FALSE), len) != len) return FALSE; + if (read(fd, *sp = store_get(len, GET_UNTAINTED), len) != len) return FALSE; return TRUE; } @@ -510,10 +526,7 @@ Arguments: options options to pass to the extraction functions, plus ENOTDIR and EACCES handling bits include_directory restrain :include: to this directory - sieve_vacation_directory directory passed to sieve_interpret - sieve_enotify_mailto_owner passed to sieve_interpret - sieve_useraddress passed to sieve_interpret - sieve_subaddress passed to sieve_interpret + sieve passed to sieve_interpret ugid uid/gid to run under - if NULL, no change generated where to hang generated addresses, initially NULL error pointer for error message @@ -539,11 +552,10 @@ Returns: values from extraction function, or FF_NONEXIST: */ int -rda_interpret(redirect_block *rdata, int options, uschar *include_directory, - uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner, - uschar *sieve_useraddress, uschar *sieve_subaddress, ugid_block *ugid, - address_item **generated, uschar **error, error_block **eblockp, - int *filtertype, uschar *rname) +rda_interpret(redirect_block * rdata, int options, + const uschar * include_directory, const sieve_block * sieve, + const ugid_block * ugid, address_item ** generated, + uschar ** error, error_block ** eblockp, int * filtertype, const uschar * rname) { int fd, rc, pfd[2]; int yield, status; @@ -581,13 +593,13 @@ with #Exim filter or #Sieve filter, and does not contain :include:, do all the work in this process. Note that for a system filter, we always have a file, so the work is done in this process only if no user is supplied. */ -if (!ugid->uid_set || /* Either there's no uid, or */ - (!rdata->isfile && /* We've got the data, and */ - rda_is_filter(data) == FILTER_FORWARD && /* It's not a filter script, */ - Ustrstr(data, ":include:") == NULL)) /* and there's no :include: */ - return rda_extract(rdata, options, include_directory, - sieve_vacation_directory, sieve_enotify_mailto_owner, sieve_useraddress, - sieve_subaddress, generated, error, eblockp, filtertype); +if ( !ugid->uid_set /* Either there's no uid, or */ + || ( !rdata->isfile /* We've got the data, and */ + && rda_is_filter(data) == FILTER_FORWARD /* It's not a filter script, */ + && Ustrstr(data, ":include:") == NULL /* and there's no :include: */ + ) ) + return rda_extract(rdata, options, include_directory, sieve, + generated, error, eblockp, filtertype); /* We need to run the processing code in a sub-process. However, if we can determine the non-existence of a file first, we can decline without having to @@ -639,9 +651,8 @@ if ((pid = exim_fork(US"router-interpret")) == 0) /* Now do the business */ - yield = rda_extract(rdata, options, include_directory, - sieve_vacation_directory, sieve_enotify_mailto_owner, sieve_useraddress, - sieve_subaddress, generated, error, eblockp, filtertype); + yield = rda_extract(rdata, options, include_directory, sieve, + generated, error, eblockp, filtertype); /* Pass back whether it was a filter, and the return code and any overall error text via the pipe. */ @@ -806,7 +817,7 @@ if (eblockp) uschar *s; if (!rda_read_string(fd, &s)) goto DISASTER; if (!s) break; - e = store_get(sizeof(error_block), FALSE); + e = store_get(sizeof(error_block), GET_UNTAINTED); e->next = NULL; e->text1 = s; if (!rda_read_string(fd, &s)) goto DISASTER; @@ -863,9 +874,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || for (;;) { int i, reply_options; - address_item *addr; - uschar *recipient; - uschar *expandn[EXPAND_MAXN + 2]; + address_item * addr; + uschar * recipient, * s; + uschar * expandn[EXPAND_MAXN + 2]; /* First string is the address; NULL => end of addresses */ @@ -882,10 +893,11 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || if ( read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) || read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) - || !rda_read_string(fd, &addr->prop.errors_address) + || !rda_read_string(fd, &s) || read(fd, &i, sizeof(i)) != sizeof(i) ) goto DISASTER; + addr->prop.errors_address = s; addr->prop.ignore_error = (i != 0); /* Next comes a possible setting for $thisaddress and any numerical @@ -905,7 +917,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || if (i > 0) { - addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), FALSE); + addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), GET_UNTAINTED); addr->pipe_expandn[i] = NULL; while (--i >= 0) addr->pipe_expandn[i] = expandn[i]; } @@ -915,7 +927,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER; if ((reply_options & REPLY_EXISTS) != 0) { - addr->reply = store_get(sizeof(reply_item), FALSE); + addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED); addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0; addr->reply->return_message = (reply_options & REPLY_RETURN) != 0; @@ -959,16 +971,14 @@ if (had_disaster) *error = string_sprintf("internal problem in %s: failure to transfer " "data from subprocess: status=%04x%s%s%s", rname, status, readerror, - (*error == NULL)? US"" : US": error=", - (*error == NULL)? US"" : *error); + *error ? US": error=" : US"", + *error ? *error : US""); log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error); } else if (status != 0) - { log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status " "%04x from redirect subprocess (but data correctly received)", rname, status); - } FINAL_EXIT: (void)close(fd);