X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/059ec3d9952740285fb1ebf47961b8aca2eb1b4a..184e88237dea64ce48076cdd0184612d057cbafd:/src/src/rda.c diff --git a/src/src/rda.c b/src/src/rda.c index 66fd8745d..13701dca4 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/rda.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */ +/* $Cambridge: exim/src/src/rda.c,v 1.14 2007/01/08 10:50:18 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2007 */ /* See the file NOTICE for conditions of use and distribution. */ /* This module contains code for extracting addresses from a forwarding list @@ -299,23 +299,17 @@ if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size) } filebuf[statbuf.st_size] = 0; -/* Don't pass statbuf.st_size directly to debug_printf. On some systems it -is a long, which may not be the same as an int. */ - DEBUG(D_route) - { - int size = (int)statbuf.st_size; - debug_printf("%d bytes read from %s\n", size, filename); - } + debug_printf(OFF_T_FMT " bytes read from %s\n", statbuf.st_size, filename); -fclose(fwd); +(void)fclose(fwd); return filebuf; /* Return an error: the string is already set up. */ ERROR_RETURN: *yield = FF_ERROR; -fclose(fwd); +(void)fclose(fwd); return NULL; } @@ -333,6 +327,8 @@ Arguments: options the options bits include_directory restrain to this directory sieve_vacation_directory passed to sieve_interpret + sieve_useraddress passed to sieve_interpret + sieve_subaddress passed to sieve_interpret generated where to hang generated addresses error for error messages eblockp for details of skipped syntax errors @@ -348,14 +344,15 @@ Returns: a suitable return for rda_interpret() static int rda_extract(redirect_block *rdata, int options, uschar *include_directory, - uschar *sieve_vacation_directory, address_item **generated, uschar **error, + uschar *sieve_vacation_directory, uschar *sieve_useraddress, + uschar *sieve_subaddress, address_item **generated, uschar **error, error_block **eblockp, int *filtertype) { uschar *data; if (rdata->isfile) { - int yield; + int yield = 0; data = rda_get_file_contents(rdata, options, error, &yield); if (data == NULL) return yield; } @@ -374,23 +371,42 @@ if (*filtertype != FILTER_FORWARD) int frc; int old_expand_forbid = expand_forbid; + DEBUG(D_route) debug_printf("data is %s filter program\n", + (*filtertype == FILTER_EXIM)? "an Exim" : "a Sieve"); + + /* RDO_FILTER is an "allow" bit */ + if ((options & RDO_FILTER) == 0) { *error = US"filtering not enabled"; return FF_ERROR; } - DEBUG(D_route) debug_printf("data is %s filter program\n", - (*filtertype == FILTER_EXIM)? "an Exim" : "a Sieve"); - expand_forbid = (expand_forbid & ~RDO_FILTER_EXPANSIONS) | (options & RDO_FILTER_EXPANSIONS); - frc = (*filtertype == FILTER_EXIM)? - filter_interpret(data, options, generated, error) - : - sieve_interpret(data, options, sieve_vacation_directory, generated, error); + /* RDO_{EXIM,SIEVE}_FILTER are forbid bits */ + + if (*filtertype == FILTER_EXIM) + { + if ((options & RDO_EXIM_FILTER) != 0) + { + *error = US"Exim filtering not enabled"; + return FF_ERROR; + } + frc = filter_interpret(data, options, generated, error); + } + else + { + if ((options & RDO_SIEVE_FILTER) != 0) + { + *error = US"Sieve filtering not enabled"; + return FF_ERROR; + } + frc = sieve_interpret(data, options, sieve_vacation_directory, + sieve_useraddress, sieve_subaddress, generated, error); + } expand_forbid = old_expand_forbid; return frc; @@ -430,8 +446,8 @@ static void rda_write_string(int fd, uschar *s) { int len = (s == NULL)? 0 : Ustrlen(s) + 1; -write(fd, &len, sizeof(int)); -if (s != NULL) write(fd, s, len); +(void)write(fd, &len, sizeof(int)); +if (s != NULL) (void)write(fd, s, len); } @@ -496,6 +512,8 @@ Arguments: plus ENOTDIR and EACCES handling bits include_directory restrain :include: to this directory sieve_vacation_directory directory passed to sieve_interpret() + sieve_useraddress passed to sieve_interpret + sieve_subaddress 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 @@ -522,7 +540,8 @@ Returns: values from extraction function, or FF_NONEXIST: int rda_interpret(redirect_block *rdata, int options, uschar *include_directory, - uschar *sieve_vacation_directory, ugid_block *ugid, address_item **generated, + uschar *sieve_vacation_directory, uschar *sieve_useraddress, + uschar *sieve_subaddress, ugid_block *ugid, address_item **generated, uschar **error, error_block **eblockp, int *filtertype, uschar *rname) { int fd, rc, pfd[2]; @@ -567,7 +586,8 @@ if (!ugid->uid_set || /* Either there's no uid, or */ Ustrstr(data, ":include:") == NULL)) /* and there's no :include: */ { return rda_extract(rdata, options, include_directory, - sieve_vacation_directory, generated, error, eblockp, filtertype); + sieve_vacation_directory, sieve_useraddress, sieve_subaddress, + generated, error, eblockp, filtertype); } /* We need to run the processing code in a sub-process. However, if we can @@ -587,15 +607,19 @@ if (pipe(pfd) != 0) /* Ensure that SIGCHLD is set to SIG_DFL before forking, so that the child process can be waited for. We sometimes get here with it set otherwise. Save -the old state for resetting on the wait. */ +the old state for resetting on the wait. Ensure that all cached resources are +freed so that the subprocess starts with a clean slate and doesn't interfere +with the parent process. */ oldsignal = signal(SIGCHLD, SIG_DFL); +search_tidyup(); + if ((pid = fork()) == 0) { header_line *waslast = header_last; /* Save last header */ fd = pfd[pipe_write]; - close(pfd[pipe_read]); + (void)close(pfd[pipe_read]); exim_setugid(ugid->uid, ugid->gid, FALSE, rname); /* Addresses can get rewritten in filters; if we are not root or the exim @@ -612,13 +636,14 @@ if ((pid = fork()) == 0) /* Now do the business */ yield = rda_extract(rdata, options, include_directory, - sieve_vacation_directory, generated, error, eblockp, filtertype); + sieve_vacation_directory, sieve_useraddress, sieve_subaddress, generated, + error, eblockp, filtertype); /* Pass back whether it was a filter, and the return code and any overall error text via the pipe. */ - write(fd, filtertype, sizeof(int)); - write(fd, &yield, sizeof(int)); + (void)write(fd, filtertype, sizeof(int)); + (void)write(fd, &yield, sizeof(int)); rda_write_string(fd, *error); /* Pass back the contents of any syntax error blocks if we have a pointer */ @@ -644,10 +669,10 @@ if ((pid = fork()) == 0) header_line *h; for (h = header_list; h != waslast->next; i++, h = h->next) { - if (h->type == htype_old) write(fd, &i, sizeof(i)); + if (h->type == htype_old) (void)write(fd, &i, sizeof(i)); } i = -1; - write(fd, &i, sizeof(i)); + (void)write(fd, &i, sizeof(i)); while (waslast != header_last) { @@ -655,7 +680,7 @@ if ((pid = fork()) == 0) if (waslast->type != htype_old) { rda_write_string(fd, waslast->text); - write(fd, &(waslast->type), sizeof(waslast->type)); + (void)write(fd, &(waslast->type), sizeof(waslast->type)); } } rda_write_string(fd, NULL); /* Indicates end of added headers */ @@ -663,7 +688,7 @@ if ((pid = fork()) == 0) /* Write the contents of the $n variables */ - write(fd, filter_n, sizeof(filter_n)); + (void)write(fd, filter_n, sizeof(filter_n)); /* If the result was DELIVERED or NOTDELIVERED, we pass back the generated addresses, and their associated information, through the pipe. This is @@ -680,8 +705,8 @@ if ((pid = fork()) == 0) int reply_options = 0; rda_write_string(fd, addr->address); - write(fd, &(addr->mode), sizeof(addr->mode)); - write(fd, &(addr->flags), sizeof(addr->flags)); + (void)write(fd, &(addr->mode), sizeof(addr->mode)); + (void)write(fd, &(addr->flags), sizeof(addr->flags)); rda_write_string(fd, addr->p.errors_address); if (addr->pipe_expandn != NULL) @@ -693,15 +718,15 @@ if ((pid = fork()) == 0) rda_write_string(fd, NULL); if (addr->reply == NULL) - write(fd, &reply_options, sizeof(int)); /* 0 means no reply */ + (void)write(fd, &reply_options, sizeof(int)); /* 0 means no reply */ else { reply_options |= REPLY_EXISTS; if (addr->reply->file_expand) reply_options |= REPLY_EXPAND; if (addr->reply->return_message) reply_options |= REPLY_RETURN; - write(fd, &reply_options, sizeof(int)); - write(fd, &(addr->reply->expand_forbid), sizeof(int)); - write(fd, &(addr->reply->once_repeat), sizeof(time_t)); + (void)write(fd, &reply_options, sizeof(int)); + (void)write(fd, &(addr->reply->expand_forbid), sizeof(int)); + (void)write(fd, &(addr->reply->once_repeat), sizeof(time_t)); rda_write_string(fd, addr->reply->to); rda_write_string(fd, addr->reply->cc); rda_write_string(fd, addr->reply->bcc); @@ -719,9 +744,11 @@ if ((pid = fork()) == 0) rda_write_string(fd, NULL); /* Marks end of addresses */ } - /* OK, this process is now done. Must use _exit() and not exit() !! */ + /* OK, this process is now done. Free any cached resources. Must use _exit() + and not exit() !! */ - close(fd); + (void)close(fd); + search_tidyup(); _exit(0); } @@ -734,7 +761,7 @@ if (pid < 0) writing end must be closed first, as otherwise read() won't return zero on an empty pipe. Afterwards, close the reading end. */ -close(pfd[pipe_write]); +(void)close(pfd[pipe_write]); /* Read initial data, including yield and contents of *error */ @@ -743,9 +770,6 @@ if (read(fd, filtertype, sizeof(int)) != sizeof(int) || read(fd, &yield, sizeof(int)) != sizeof(int) || !rda_read_string(fd, error)) goto DISASTER; -DEBUG(D_route) - debug_printf("rda_interpret: subprocess yield=%d error=%s\n", yield, *error); - /* Read the contents of any syntax error blocks if we have a pointer */ if (eblockp != NULL) @@ -902,6 +926,9 @@ while ((rc = wait(&status)) != pid) } } +DEBUG(D_route) + debug_printf("rda_interpret: subprocess yield=%d error=%s\n", yield, *error); + if (had_disaster) { *error = string_sprintf("internal problem in %s: failure to transfer " @@ -919,7 +946,7 @@ else if (status != 0) } FINAL_EXIT: -close(fd); +(void)close(fd); signal(SIGCHLD, oldsignal); /* restore */ return yield;