X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Frda.c;h=fb3edac176f5a832bb0aa13924bb9fb0a72c2450;hb=31beb7972466a33a88770eacbce13490f2ddadc2;hp=06eff227e689d6c253e90cfe6da411f4b5bbc917;hpb=f1e894f37fb99398f7447220925a915bd031491a;p=exim.git diff --git a/src/src/rda.c b/src/src/rda.c index 06eff227e..fb3edac17 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/rda.c,v 1.8 2005/06/27 14:29:43 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ /* This module contains code for extracting addresses from a forwarding list @@ -327,6 +325,7 @@ Arguments: 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 generated where to hang generated addresses @@ -344,15 +343,16 @@ 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_useraddress, - uschar *sieve_subaddress, address_item **generated, uschar **error, - error_block **eblockp, int *filtertype) + 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) { uschar *data; if (rdata->isfile) { - int yield; + int yield = 0; data = rda_get_file_contents(rdata, options, error, &yield); if (data == NULL) return yield; } @@ -405,7 +405,8 @@ if (*filtertype != FILTER_FORWARD) return FF_ERROR; } frc = sieve_interpret(data, options, sieve_vacation_directory, - sieve_useraddress, sieve_subaddress, generated, error); + sieve_enotify_mailto_owner, sieve_useraddress, sieve_subaddress, + generated, error); } expand_forbid = old_expand_forbid; @@ -432,22 +433,24 @@ return parse_forward_list(data, * Write string down pipe * *************************************************/ -/* This function is used for tranferring a string down a pipe between +/* This function is used for transferring a string down a pipe between processes. If the pointer is NULL, a length of zero is written. Arguments: fd the pipe s the string -Returns: nothing +Returns: -1 on error, else 0 */ -static void -rda_write_string(int fd, uschar *s) +static int +rda_write_string(int fd, const uschar *s) { int len = (s == NULL)? 0 : Ustrlen(s) + 1; -(void)write(fd, &len, sizeof(int)); -if (s != NULL) (void)write(fd, s, len); +return ( write(fd, &len, sizeof(int)) != sizeof(int) + || (s != NULL && write(fd, s, len) != len) + ) + ? -1 : 0; } @@ -471,11 +474,12 @@ rda_read_string(int fd, uschar **sp) int len; if (read(fd, &len, sizeof(int)) != sizeof(int)) return FALSE; -if (len == 0) *sp = NULL; else - { - *sp = store_get(len); - if (read(fd, *sp, len) != len) return FALSE; - } +if (len == 0) + *sp = NULL; +else + /* We know we have enough memory so disable the error on "len" */ + /* coverity[tainted_data] */ + if (read(fd, *sp = store_get(len), len) != len) return FALSE; return TRUE; } @@ -511,7 +515,8 @@ 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_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 ugid uid/gid to run under - if NULL, no change @@ -540,9 +545,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_useraddress, - uschar *sieve_subaddress, ugid_block *ugid, address_item **generated, - uschar **error, error_block **eblockp, int *filtertype, uschar *rname) + 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) { int fd, rc, pfd[2]; int yield, status; @@ -586,8 +592,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, sieve_useraddress, sieve_subaddress, - generated, error, eblockp, filtertype); + sieve_vacation_directory, sieve_enotify_mailto_owner, sieve_useraddress, + sieve_subaddress, generated, error, eblockp, filtertype); } /* We need to run the processing code in a sub-process. However, if we can @@ -607,9 +613,13 @@ 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 */ @@ -626,21 +636,23 @@ if ((pid = fork()) == 0) { DEBUG(D_rewrite) debug_printf("turned off address rewrite logging (not " "root or exim in this process)\n"); - log_write_selector &= ~L_address_rewrite; + BIT_CLEAR(log_selector, log_selector_size, Li_address_rewrite); } /* Now do the business */ yield = rda_extract(rdata, options, include_directory, - sieve_vacation_directory, sieve_useraddress, sieve_subaddress, generated, - error, eblockp, filtertype); + sieve_vacation_directory, sieve_enotify_mailto_owner, 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. */ - (void)write(fd, filtertype, sizeof(int)); - (void)write(fd, &yield, sizeof(int)); - rda_write_string(fd, *error); + if ( write(fd, filtertype, sizeof(int)) != sizeof(int) + || write(fd, &yield, sizeof(int)) != sizeof(int) + || rda_write_string(fd, *error) != 0 + ) + goto bad; /* Pass back the contents of any syntax error blocks if we have a pointer */ @@ -648,11 +660,12 @@ if ((pid = fork()) == 0) { error_block *ep; for (ep = *eblockp; ep != NULL; ep = ep->next) - { - rda_write_string(fd, ep->text1); - rda_write_string(fd, ep->text2); - } - rda_write_string(fd, NULL); /* Indicates end of eblocks */ + if ( rda_write_string(fd, ep->text1) != 0 + || rda_write_string(fd, ep->text2) != 0 + ) + goto bad; + if (rda_write_string(fd, NULL) != 0) /* Indicates end of eblocks */ + goto bad; } /* If this is a system filter, we have to pass back the numbers of any @@ -664,27 +677,33 @@ if ((pid = fork()) == 0) int i = 0; header_line *h; for (h = header_list; h != waslast->next; i++, h = h->next) - { - if (h->type == htype_old) (void)write(fd, &i, sizeof(i)); - } + if ( h->type == htype_old + && write(fd, &i, sizeof(i)) != sizeof(i) + ) + goto bad; + i = -1; - (void)write(fd, &i, sizeof(i)); + if (write(fd, &i, sizeof(i)) != sizeof(i)) + goto bad; while (waslast != header_last) { waslast = waslast->next; if (waslast->type != htype_old) - { - rda_write_string(fd, waslast->text); - (void)write(fd, &(waslast->type), sizeof(waslast->type)); - } + if ( rda_write_string(fd, waslast->text) != 0 + || write(fd, &(waslast->type), sizeof(waslast->type)) + != sizeof(waslast->type) + ) + goto bad; } - rda_write_string(fd, NULL); /* Indicates end of added headers */ + if (rda_write_string(fd, NULL) != 0) /* Indicates end of added headers */ + goto bad; } /* Write the contents of the $n variables */ - (void)write(fd, filter_n, sizeof(filter_n)); + if (write(fd, filter_n, sizeof(filter_n)) != sizeof(filter_n)) + goto bad; /* If the result was DELIVERED or NOTDELIVERED, we pass back the generated addresses, and their associated information, through the pipe. This is @@ -696,54 +715,73 @@ if ((pid = fork()) == 0) yield == FF_FAIL || yield == FF_FREEZE) { address_item *addr; - for (addr = *generated; addr != NULL; addr = addr->next) + for (addr = *generated; addr; addr = addr->next) { int reply_options = 0; - rda_write_string(fd, addr->address); - (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 ( rda_write_string(fd, addr->address) != 0 + || write(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) + || write(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) + || rda_write_string(fd, addr->prop.errors_address) != 0 + ) + goto bad; - if (addr->pipe_expandn != NULL) + if (addr->pipe_expandn) { uschar **pp; - for (pp = addr->pipe_expandn; *pp != NULL; pp++) - rda_write_string(fd, *pp); + for (pp = addr->pipe_expandn; *pp; pp++) + if (rda_write_string(fd, *pp) != 0) + goto bad; } - rda_write_string(fd, NULL); - - if (addr->reply == NULL) - (void)write(fd, &reply_options, sizeof(int)); /* 0 means no reply */ + if (rda_write_string(fd, NULL) != 0) + goto bad; + + if (!addr->reply) + { + if (write(fd, &reply_options, sizeof(int)) != sizeof(int)) /* 0 means no reply */ + goto bad; + } else { reply_options |= REPLY_EXISTS; if (addr->reply->file_expand) reply_options |= REPLY_EXPAND; if (addr->reply->return_message) reply_options |= REPLY_RETURN; - (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); - rda_write_string(fd, addr->reply->from); - rda_write_string(fd, addr->reply->reply_to); - rda_write_string(fd, addr->reply->subject); - rda_write_string(fd, addr->reply->headers); - rda_write_string(fd, addr->reply->text); - rda_write_string(fd, addr->reply->file); - rda_write_string(fd, addr->reply->logfile); - rda_write_string(fd, addr->reply->oncelog); + if ( write(fd, &reply_options, sizeof(int)) != sizeof(int) + || write(fd, &(addr->reply->expand_forbid), sizeof(int)) + != sizeof(int) + || write(fd, &(addr->reply->once_repeat), sizeof(time_t)) + != sizeof(time_t) + || rda_write_string(fd, addr->reply->to) != 0 + || rda_write_string(fd, addr->reply->cc) != 0 + || rda_write_string(fd, addr->reply->bcc) != 0 + || rda_write_string(fd, addr->reply->from) != 0 + || rda_write_string(fd, addr->reply->reply_to) != 0 + || rda_write_string(fd, addr->reply->subject) != 0 + || rda_write_string(fd, addr->reply->headers) != 0 + || rda_write_string(fd, addr->reply->text) != 0 + || rda_write_string(fd, addr->reply->file) != 0 + || rda_write_string(fd, addr->reply->logfile) != 0 + || rda_write_string(fd, addr->reply->oncelog) != 0 + ) + goto bad; } } - rda_write_string(fd, NULL); /* Marks end of addresses */ + if (rda_write_string(fd, NULL) != 0) /* Marks end of addresses */ + goto bad; } - /* 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() !! */ +out: (void)close(fd); + search_tidyup(); _exit(0); + +bad: + DEBUG(D_rewrite) debug_printf("rda_interpret: failed write to pipe\n"); + goto out; } /* Back in the main process: panic if the fork did not succeed. */ @@ -764,27 +802,23 @@ 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) +if (eblockp) { - uschar *s; error_block *e; - error_block **p = eblockp; - for (;;) + error_block **p; + for (p = eblockp; ; p = &e->next) { + uschar *s; if (!rda_read_string(fd, &s)) goto DISASTER; - if (s == NULL) break; + if (!s) break; e = store_get(sizeof(error_block)); e->next = NULL; e->text1 = s; if (!rda_read_string(fd, &s)) goto DISASTER; e->text2 = s; *p = e; - p = &(e->next); } } @@ -804,8 +838,7 @@ if (system_filtering) while (hn < n) { hn++; - h = h->next; - if (h == NULL) goto DISASTER_NO_HEADER; + if (!(h = h->next)) goto DISASTER_NO_HEADER; } h->type = htype_old; } @@ -815,7 +848,7 @@ if (system_filtering) uschar *s; int type; if (!rda_read_string(fd, &s)) goto DISASTER; - if (s == NULL) break; + if (!s) break; if (read(fd, &type, sizeof(type)) != sizeof(type)) goto DISASTER; header_add(type, "%s", s); } @@ -854,9 +887,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || /* Next comes the mode and the flags fields */ - 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->p.errors_address))) goto DISASTER; + 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)) goto DISASTER; /* Next comes a possible setting for $thisaddress and any numerical variables for pipe expansion, terminated by a NULL string. The maximum @@ -875,7 +908,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED || if (i > 0) { - addr->pipe_expandn = store_get((i+1) * sizeof(uschar **)); + addr->pipe_expandn = store_get((i+1) * sizeof(uschar *)); addr->pipe_expandn[i] = NULL; while (--i >= 0) addr->pipe_expandn[i] = expandn[i]; } @@ -923,6 +956,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 "