diff options
-rw-r--r-- | driver.c | 154 | ||||
-rw-r--r-- | fetchmail.c | 14 | ||||
-rw-r--r-- | fetchmail.h | 6 |
3 files changed, 101 insertions, 73 deletions
@@ -417,8 +417,7 @@ struct hostrec *queryctl; /* query control record */ char fromBuf[MSGBUFSIZE+1]; char *bufp, *headers, *unixfrom, *fromhdr, *tohdr, *cchdr, *bcchdr; int n, oldlen; - int inheaders; - int lines,sizeticker; + int inheaders,lines,sizeticker; /* This keeps the retrieved message count for display purposes */ static int msgnum = 0; @@ -506,53 +505,89 @@ struct hostrec *queryctl; /* query control record */ goto skipwrite; } - else if (headers) + else if (headers) /* OK, we're at end of headers now */ { char *cp; + struct idlist *idp, *xmit_names; - if (!queryctl->mda[0]) + /* cons up a list of local recipients */ + xmit_names = (struct idlist *)NULL; +#ifdef HAVE_GETHOSTBYNAME + /* is this a multidrop box? */ + if (queryctl->localnames != (struct idlist *)NULL + && queryctl->localnames->next != (struct idlist *)NULL) + { + /* compute the local address list */ + find_server_names(tohdr, queryctl, &xmit_names); + find_server_names(cchdr, queryctl, &xmit_names); + find_server_names(bcchdr, queryctl, &xmit_names); + + /* if nothing supplied localnames, default appropriately */ + if (!xmit_names) + save_uid(&xmit_names, -1, dfltuser); + } + else /* it's a single-drop box, use first localname */ +#endif /* HAVE_GETHOSTBYNAME */ + { + if (queryctl->localnames) + save_uid(&xmit_names, -1, queryctl->localnames->id); + else + save_uid(&xmit_names, -1, dfltuser); + } + + /* time to address the message */ + if (queryctl->mda[0]) /* we have a declared MDA */ + { + int i, nlocals = 0; + char **sargv, **sp; + + /* + * We go through this in order to be able to handle very + * long lists of users. + */ + for (idp = xmit_names; idp; idp = idp->next) + nlocals++; + sp = sargv = (char **)alloca(queryctl->mda_argcount + nlocals); + for (i = 0; i < queryctl->mda_argcount; i++) + *sp++ = queryctl->mda_argv[i]; + for (idp = xmit_names; idp; idp = idp->next) + *sp++ = idp->id; + *sp = (char *)NULL; + +#ifdef HAVE_SETEUID + /* + * Arrange to run with user's permissions if we're root. + * This will initialize the ownership of any files the + * MDA creates properly. (The seteuid call is available + * under all BSDs and Linux) + */ + seteuid(queryctl->uid); +#endif /* HAVE_SETEUID */ + + mboxfd = openmailpipe(sargv); + +#ifdef HAVE_SETEUID + /* this will fail quietly if we didn't start as root */ + seteuid(0); +#endif /* HAVE_SETEUID */ + + if (mboxfd < 0) + return(PS_IOERR); + } + else { if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK) return(PS_SMTP); -#ifdef HAVE_GETHOSTBYNAME - /* is this a multidrop box? */ - if (queryctl->localnames != (struct idlist *)NULL - && queryctl->localnames->next != (struct idlist *)NULL) - { - struct idlist *idp, *xmit_names; - - /* compute the local address list */ - xmit_names = (struct idlist *)NULL; - find_server_names(tohdr, queryctl, &xmit_names); - find_server_names(cchdr, queryctl, &xmit_names); - find_server_names(bcchdr, queryctl, &xmit_names); - - /* if nothing supplied localnames, default appropriately */ - if (!xmit_names) - save_uid(&xmit_names, -1, dfltuser); - - for (idp = xmit_names; idp; idp = idp->next) - if (SMTP_rcpt(mboxfd, idp->id) != SM_OK) - return(PS_SMTP); - free_uid_list(&xmit_names); - } - else /* it's a single-drop box, use first localname */ -#endif /* HAVE_GETHOSTBYNAME */ - { - if (queryctl->localnames) - cp = queryctl->localnames->id; - else - cp = dfltuser; - - if (SMTP_rcpt(mboxfd, cp) != SM_OK) + for (idp = xmit_names; idp; idp = idp->next) + if (SMTP_rcpt(mboxfd, idp->id) != SM_OK) return(PS_SMTP); - } SMTP_data(mboxfd); if (outlevel == O_VERBOSE) fputs("SMTP> ", stderr); } + free_uid_list(&xmit_names); /* change continuation markers back to regular newlines */ for (cp = headers; cp < headers + oldlen; cp++) @@ -614,10 +649,20 @@ struct hostrec *queryctl; /* query control record */ if (alarmed) return (0); - /* write message terminator */ - if (!queryctl->mda[0]) + + if (queryctl->mda[0]) + { + /* close the delivery pipe, we'll reopen before next message */ + if (closemailpipe(mboxfd)) + return(PS_IOERR); + } + else + { + /* write message terminator */ if (SMTP_eom(mboxfd) != SM_OK) return(PS_SMTP); + } + return(0); } @@ -821,27 +866,13 @@ struct method *proto; /* protocol method table */ fputc(' ', stderr); } - /* open the delivery pipe now if we're using an MDA */ - if (queryctl->mda[0]) - { -#ifdef HAVE_SETEUID - /* - * Arrange to run with user's permissions if we're root. - * This will initialize the ownership of any files the - * MDA creates properly. (The seteuid call is available - * under all BSDs and Linux) - */ - seteuid(queryctl->uid); -#endif /* HAVE_SETEUID */ - mboxfd = openmailpipe(queryctl); -#ifdef HAVE_SETEUID - /* this will fail quietly if we didn't start as root */ - seteuid(0); -#endif /* HAVE_SETEUID */ - - if (mboxfd < 0) - goto cleanUp; - } + /* + * If we're forwarding via SMTP, mboxfd is initialized + * at this point (it was set at start of retrieval). + * If we're using an MDA it's not set -- gen_readmsg() + * may have to parse message headers to know what + * delivery addresses should be passed to the MDA + */ /* read the message and ship it to the output sink */ ok = gen_readmsg(socket, mboxfd, @@ -849,11 +880,6 @@ struct method *proto; /* protocol method table */ protocol->delimited, queryctl); - /* close the delivery pipe, we'll reopen before next message */ - if (queryctl->mda[0]) - if ((ok = closemailpipe(mboxfd)) != 0 || alarmed) - goto cleanUp; - /* tell the server we got it OK and resynchronize */ if (protocol->trail) (protocol->trail)(socket, queryctl, num); diff --git a/fetchmail.c b/fetchmail.c index bbef5002..c585bd03 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -228,20 +228,20 @@ char **argv; /* expand MDA commands */ if (!check_only && hostp->mda[0]) { - int argi; char *argp; /* punch nulls into the delimiting whitespace in the args */ - for (argp = hostp->mdabuf, argi = 1; *argp != '\0'; argi++) + hostp->mda_argcount = 0; + for (argp = hostp->mdabuf, hostp->mda_argcount = 1; *argp != '\0'; hostp->mda_argcount++) { - hostp->mda_argv[argi] = argp; + hostp->mda_argv[hostp->mda_argcount] = argp; while (!(*argp == '\0' || isspace(*argp))) argp++; if (*argp != '\0') *(argp++) = '\0'; } - hostp->mda_argv[argi] = (char *)NULL; + hostp->mda_argv[hostp->mda_argcount] = (char *)NULL; hostp->mda_argv[0] = hostp->mda_argv[1]; if ((argp = strrchr(hostp->mda_argv[1], '/')) != (char *)NULL) @@ -658,9 +658,9 @@ struct hostrec *queryctl; /* query parameter block */ } } -int openmailpipe (queryctl) +int openmailpipe (argv) /* open a one-way pipe to a mail delivery agent */ -struct hostrec *queryctl; /* query control block */ +char *argv[]; { int pipefd [2]; int childpid; @@ -683,7 +683,7 @@ struct hostrec *queryctl; /* query control block */ exit(1); } - execv(queryctl->mda_argv[0], queryctl->mda_argv + 1); + execv(argv[0], argv + 1); /* if we got here, an error occurred */ perror("fetchmail: openmailpipe: exec"); diff --git a/fetchmail.h b/fetchmail.h index baaa6f88..3bfd5811 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -53,6 +53,7 @@ #define O_VERBOSE 2 /* excessive */ #define SIZETICKER 1024 /* print 1 dot per this many bytes */ +#define MDA_MAXARGS 32 /* max arguments per MDA call */ struct idlist { @@ -81,7 +82,8 @@ struct hostrec int timeout; /* MDA arguments */ - char *mda_argv[32]; + int mda_argcount; + char *mda_argv[MDA_MAXARGS]; char mdabuf[MDALEN+1]; /* control flags */ @@ -179,7 +181,7 @@ struct hostrec *hostalloc(struct hostrec *); int parsecmdline (int, char **, struct hostrec *); void optmerge(struct hostrec *, struct hostrec *); char *MD5Digest (char *); -int openmailpipe (struct hostrec *); +int openmailpipe (char **); int daemonize(const char *, void (*)(int)); void escapes(const char *, char *); |