diff options
author | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
---|---|---|
committer | gshapiro <gshapiro@FreeBSD.org> | 2000-08-12 21:55:49 +0000 |
commit | c3cd75415d60bc002b20182ffd3383ea9e901a80 (patch) | |
tree | 211dfd0f771f89d6abe14fa94cab53985a9d0116 /contrib/sendmail/src/main.c | |
parent | 231592eb7942ebd4becae24ea8e018acea3742a9 (diff) | |
parent | 4332139a9a11f773ffe5109bed871561e3c290a1 (diff) | |
download | FreeBSD-src-c3cd75415d60bc002b20182ffd3383ea9e901a80.zip FreeBSD-src-c3cd75415d60bc002b20182ffd3383ea9e901a80.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r64562,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/sendmail/src/main.c')
-rw-r--r-- | contrib/sendmail/src/main.c | 1198 |
1 files changed, 800 insertions, 398 deletions
diff --git a/contrib/sendmail/src/main.c b/contrib/sendmail/src/main.c index cb6fd57..7b66e0c 100644 --- a/contrib/sendmail/src/main.c +++ b/contrib/sendmail/src/main.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -12,24 +13,29 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1998 Sendmail, Inc. All rights reserved.\n\ +"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ +#endif /* ! lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998"; -#endif /* not lint */ +static char id[] = "@(#)$Id: main.c,v 8.485.4.19 2000/06/29 01:31:02 gshapiro Exp $"; +#endif /* ! lint */ #define _DEFINE -#include "sendmail.h" -#include <arpa/inet.h> -#include <grp.h> -#if NAMED_BIND -#include <resolv.h> -#endif +#include <sendmail.h> + + +#if NETINET || NETINET6 +# include <arpa/inet.h> +#endif /* NETINET || NETINET6 */ + +static void dump_class __P((STAB *, int)); +static void obsolete __P((char **)); +static void testmodeline __P((char *, ENVELOPE *)); /* ** SENDMAIL -- Post mail to a set of destinations. @@ -39,7 +45,7 @@ static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998"; ** turn calls a bunch of mail servers that do the real work of ** delivering the mail. ** -** Sendmail is driven by settings read in from /etc/sendmail.cf +** Sendmail is driven by settings read in from /etc/mail/sendmail.cf ** (read by readcf.c). ** ** Usage: @@ -65,30 +71,37 @@ static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998"; int NextMailer; /* "free" index into Mailer struct */ char *FullName; /* sender's full name */ ENVELOPE BlankEnvelope; /* a "blank" envelope */ -ENVELOPE MainEnvelope; /* the envelope around the basic letter */ +static ENVELOPE MainEnvelope; /* the envelope around the basic letter */ ADDRESS NullAddress = /* a null address */ { "", "", NULL, "" }; char *CommandLineArgs; /* command line args for pid file */ bool Warn_Q_option = FALSE; /* warn about Q option use */ char **SaveArgv; /* argument vector for re-execing */ -int MissingFds = 0; /* bit map of fds missing on startup */ +static int MissingFds = 0; /* bit map of fds missing on startup */ #ifdef NGROUPS_MAX GIDSET_T InitialGidSet[NGROUPS_MAX]; -#endif - -static void obsolete __P((char **)); -extern void printmailer __P((MAILER *)); -extern void tTflag __P((char *)); +#endif /* NGROUPS_MAX */ #if DAEMON && !SMTP ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR #endif /* DAEMON && !SMTP */ #if SMTP && !QUEUE ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR -#endif /* DAEMON && !SMTP */ +#endif /* SMTP && !QUEUE */ -#define MAXCONFIGLEVEL 8 /* highest config version level known */ +#define MAXCONFIGLEVEL 9 /* highest config version level known */ + +#if SASL +static sasl_callback_t srvcallbacks[] = +{ + { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, + { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, + { SASL_CB_LIST_END, NULL, NULL } +}; +#endif /* SASL */ + +int SubmitMode; int main(argc, argv, envp) @@ -103,16 +116,21 @@ main(argc, argv, envp) STAB *st; register int i; int j; - bool queuemode = FALSE; /* process queue requests */ + int dp; bool safecf = TRUE; + BITMAP256 *p_flags = NULL; /* daemon flags */ bool warn_C_flag = FALSE; + bool auth = TRUE; /* whether to set e_auth_param */ char warn_f_flag = '\0'; bool run_in_foreground = FALSE; /* -bD mode */ static bool reenter = FALSE; struct passwd *pw; struct hostent *hp; char *nullserver = NULL; + char *authinfo = NULL; + char *sysloglabel = NULL; /* label for syslog */ bool forged; + struct stat traf_st; /* for TrafficLog FIFO check */ char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ static char rnamebuf[MAXNAME]; /* holds RealUserName */ char *emptyenviron[1]; @@ -122,31 +140,6 @@ main(argc, argv, envp) extern int opterr; extern char *optarg; extern char **environ; - extern time_t convtime __P((char *, char)); - extern SIGFUNC_DECL intsig __P((int)); - extern struct hostent *myhostname __P((char *, int)); - extern char *getauthinfo __P((int, bool *)); - extern char *getcfname __P((void)); - extern SIGFUNC_DECL sigusr1 __P((int)); - extern SIGFUNC_DECL sighup __P((int)); - extern SIGFUNC_DECL quiesce __P((int)); - extern void initmacros __P((ENVELOPE *)); - extern void init_md __P((int, char **)); - extern int getdtsize __P((void)); - extern void tTsetup __P((u_char *, int, char *)); - extern void setdefaults __P((ENVELOPE *)); - extern void initsetproctitle __P((int, char **, char **)); - extern void init_vendor_macros __P((ENVELOPE *)); - extern void load_if_names __P((void)); - extern void vendor_pre_defaults __P((ENVELOPE *)); - extern void vendor_post_defaults __P((ENVELOPE *)); - extern void readcf __P((char *, bool, ENVELOPE *)); - extern void printqueue __P((void)); - extern void sendtoargv __P((char **, ENVELOPE *)); - extern void resetlimits __P((void)); -#ifndef HASUNSETENV - extern void unsetenv __P((char *)); -#endif /* ** Check to see if we reentered. @@ -167,6 +160,7 @@ main(argc, argv, envp) /* do machine-dependent initializations */ init_md(argc, argv); + /* in 4.4BSD, the table can be huge; impose a reasonable limit */ DtableSize = getdtsize(); if (DtableSize > 256) @@ -190,12 +184,12 @@ main(argc, argv, envp) errno = 0; #if LOG -# ifdef LOG_MAIL +# ifdef LOG_MAIL openlog("sendmail", LOG_PID, LOG_MAIL); -# else +# else /* LOG_MAIL */ openlog("sendmail", LOG_PID); -# endif -#endif +# endif /* LOG_MAIL */ +#endif /* LOG */ if (MissingFds != 0) { @@ -203,11 +197,11 @@ main(argc, argv, envp) mbuf[0] = '\0'; if (bitset(1 << STDIN_FILENO, MissingFds)) - strcat(mbuf, ", stdin"); + (void) strlcat(mbuf, ", stdin", sizeof mbuf); if (bitset(1 << STDOUT_FILENO, MissingFds)) - strcat(mbuf, ", stdout"); + (void) strlcat(mbuf, ", stdout", sizeof mbuf); if (bitset(1 << STDERR_FILENO, MissingFds)) - strcat(mbuf, ", stderr"); + (void) strlcat(mbuf, ", stderr", sizeof mbuf); syserr("File descriptors missing on startup: %s", &mbuf[2]); } @@ -215,9 +209,18 @@ main(argc, argv, envp) Errors = 0; ExitStat = EX_OK; + SubmitMode = SUBMIT_UNKNOWN; #if XDEBUG checkfd012("after openlog"); -#endif +#endif /* XDEBUG */ + + /* + ** Seed the random number generator. + ** Used for queue file names, picking a queue directory, and + ** MX randomization. + */ + + seed_random(); tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); @@ -228,15 +231,16 @@ main(argc, argv, envp) InitialGidSet[0] = (GID_T) -1; while (i < NGROUPS_MAX) InitialGidSet[i++] = InitialGidSet[0]; -#endif +#endif /* NGROUPS_MAX */ /* drop group id privileges (RunAsUser not yet set) */ - (void) drop_privileges(FALSE); + dp = drop_privileges(FALSE); + setstat(dp); -#ifdef SIGUSR1 +# ifdef SIGUSR1 /* arrange to dump state on user-1 signal */ - setsignal(SIGUSR1, sigusr1); -#endif + (void) setsignal(SIGUSR1, sigusr1); +# endif /* SIGUSR1 */ /* initialize for setproctitle */ initsetproctitle(argc, argv, envp); @@ -248,15 +252,16 @@ main(argc, argv, envp) ** Do a quick prescan of the argument list. */ + #if defined(__osf__) || defined(_AIX3) -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x" -#endif +# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x" +#endif /* defined(__osf__) || defined(_AIX3) */ #if defined(sony_news) -# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:" -#endif +# define OPTIONS "B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif /* defined(sony_news) */ #ifndef OPTIONS -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:" -#endif +# define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif /* ! OPTIONS */ opterr = 0; while ((j = getopt(argc, argv, OPTIONS)) != -1) { @@ -273,10 +278,37 @@ main(argc, argv, envp) tTflag(optarg); setbuf(stdout, (char *) NULL); break; + + case 'G': /* relay (gateway) submission */ + SubmitMode |= SUBMIT_MTA; + break; + + case 'L': + j = min(strlen(optarg), 24) + 1; + sysloglabel = xalloc(j); + (void) strlcpy(sysloglabel, optarg, j); + break; + + case 'U': /* initial (user) submission */ + SubmitMode |= SUBMIT_MSA; + break; } } opterr = 1; + if (sysloglabel != NULL) + { +#if LOG + closelog(); +# ifdef LOG_MAIL + openlog(sysloglabel, LOG_PID, LOG_MAIL); +# else /* LOG_MAIL */ + openlog(sysloglabel, LOG_PID); +# endif /* LOG_MAIL */ +#endif /* LOG */ + } + + /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; BlankEnvelope.e_putbody = putbody; @@ -299,12 +331,14 @@ main(argc, argv, envp) if (pw != NULL) (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); else - (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", RealUid); + (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", + (int) RealUid); + RealUserName = rnamebuf; if (tTd(0, 101)) { - printf("Version %s\n", Version); + dprintf("Version %s\n", Version); finis(FALSE, EX_OK); } @@ -315,7 +349,7 @@ main(argc, argv, envp) if (RealUid != 0 && geteuid() == RealUid) { if (tTd(47, 1)) - printf("Non-setuid binary: RunAsUid = RealUid = %d\n", + dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n", (int)RealUid); RunAsUid = RealUid; } @@ -327,25 +361,31 @@ main(argc, argv, envp) if (tTd(47, 5)) { - printf("main: e/ruid = %d/%d e/rgid = %d/%d\n", - (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); - printf("main: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); + dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", + (int)geteuid(), (int)getuid(), + (int)getegid(), (int)getgid()); + dprintf("main: RunAsUser = %d:%d\n", + (int)RunAsUid, (int)RunAsGid); } /* save command line arguments */ - i = 0; + j = 0; for (av = argv; *av != NULL; ) - i += strlen(*av++) + 1; + j += strlen(*av++) + 1; SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); - CommandLineArgs = xalloc(i); + CommandLineArgs = xalloc(j); p = CommandLineArgs; for (av = argv, i = 0; *av != NULL; ) { + int h; + SaveArgv[i++] = newstr(*av); if (av != argv) *p++ = ' '; - strcpy(p, *av++); - p += strlen(p); + (void) strlcpy(p, *av++, j); + h = strlen(p); + p += h; + j -= h + 1; } SaveArgv[i] = NULL; @@ -354,59 +394,53 @@ main(argc, argv, envp) int ll; extern char *CompileOptions[]; - printf("Version %s\n Compiled with:", Version); + dprintf("Version %s\n Compiled with:", Version); av = CompileOptions; ll = 7; while (*av != NULL) { if (ll + strlen(*av) > 63) { - putchar('\n'); + dprintf("\n"); ll = 0; } if (ll == 0) - { - putchar('\t'); - putchar('\t'); - } + dprintf("\t\t"); else - putchar(' '); - printf("%s", *av); + dprintf(" "); + dprintf("%s", *av); ll += strlen(*av++) + 1; } - putchar('\n'); + dprintf("\n"); } if (tTd(0, 10)) { int ll; extern char *OsCompileOptions[]; - printf(" OS Defines:"); + dprintf(" OS Defines:"); av = OsCompileOptions; ll = 7; while (*av != NULL) { if (ll + strlen(*av) > 63) { - putchar('\n'); + dprintf("\n"); ll = 0; } if (ll == 0) - { - putchar('\t'); - putchar('\t'); - } + dprintf("\t\t"); else - putchar(' '); - printf("%s", *av); + dprintf(" "); + dprintf("%s", *av); ll += strlen(*av++) + 1; } - putchar('\n'); + dprintf("\n"); #ifdef _PATH_UNIX - printf("Kernel symbols:\t%s\n", _PATH_UNIX); -#endif - printf(" Def Conf file:\t%s\n", getcfname()); - printf(" Pid file:\t%s\n", PidFile); + dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); +#endif /* _PATH_UNIX */ + dprintf(" Def Conf file:\t%s\n", getcfname()); + dprintf(" Def Pid file:\t%s\n", PidFile); } InChannel = stdin; @@ -428,8 +462,8 @@ main(argc, argv, envp) tzlen = strlen(p) + 4; tz = xalloc(tzlen); - snprintf(tz, tzlen, "TZ=%s", p); - putenv(tz); + (void) snprintf(tz, tzlen, "TZ=%s", p); + (void) putenv(tz); } /* prime the child environment */ @@ -449,15 +483,30 @@ main(argc, argv, envp) #if NAMED_BIND if (!bitset(RES_INIT, _res.options)) - res_init(); + (void) res_init(); + + /* + ** hack to avoid crashes when debugging for the resolver is + ** turned on and sfio is used + */ if (tTd(8, 8)) +# if !SFIO || SFIO_STDIO_COMPAT _res.options |= RES_DEBUG; +# else /* !SFIO || SFIO_STDIO_COMPAT */ + dprintf("RES_DEBUG not available due to SFIO\n"); +# endif /* !SFIO || SFIO_STDIO_COMPAT */ else _res.options &= ~RES_DEBUG; # ifdef RES_NOALIASES _res.options |= RES_NOALIASES; -# endif -#endif +# endif /* RES_NOALIASES */ + TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; + TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; + TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; + TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; + TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; + TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; +#endif /* NAMED_BIND */ errno = 0; from = NULL; @@ -476,7 +525,7 @@ main(argc, argv, envp) struct utsname utsname; if (tTd(0, 4)) - printf("canonical name: %s\n", jbuf); + dprintf("canonical name: %s\n", jbuf); define('w', newstr(jbuf), CurEnv); /* must be new string */ define('j', newstr(jbuf), CurEnv); setclass('w', jbuf); @@ -492,7 +541,7 @@ main(argc, argv, envp) { *p = '\0'; if (tTd(0, 4)) - printf("\ta.k.a.: %s\n", jbuf); + dprintf("\ta.k.a.: %s\n", jbuf); setclass('w', jbuf); *p++ = '.'; p = strchr(p, '.'); @@ -504,12 +553,13 @@ main(argc, argv, envp) else { if (tTd(0, 22)) - printf("uname failed (%s)\n", errstring(errno)); + dprintf("uname failed (%s)\n", + errstring(errno)); makelower(jbuf); p = jbuf; } if (tTd(0, 4)) - printf(" UUCP nodename: %s\n", p); + dprintf(" UUCP nodename: %s\n", p); p = newstr(p); define('k', p, CurEnv); setclass('k', p); @@ -520,28 +570,63 @@ main(argc, argv, envp) for (av = hp->h_aliases; av != NULL && *av != NULL; av++) { if (tTd(0, 4)) - printf("\ta.k.a.: %s\n", *av); + dprintf("\ta.k.a.: %s\n", *av); setclass('w', *av); } -#if NETINET - if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ) +#if NETINET || NETINET6 + for (i = 0; hp->h_addr_list[i] != NULL; i++) { - for (i = 0; hp->h_addr_list[i] != NULL; i++) +# if NETINET6 + char *addr; + char buf6[INET6_ADDRSTRLEN]; + struct in6_addr ia6; +# endif /* NETINET6 */ +# if NETINET + struct in_addr ia; +# endif /* NETINET */ + char ipbuf[103]; + + ipbuf[0] = '\0'; + switch (hp->h_addrtype) { - char ipbuf[103]; +# if NETINET + case AF_INET: + if (hp->h_length != INADDRSZ) + break; - snprintf(ipbuf, sizeof ipbuf, "[%.100s]", - inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); - if (tTd(0, 4)) - printf("\ta.k.a.: %s\n", ipbuf); - setclass('w', ipbuf); + memmove(&ia, hp->h_addr_list[i], INADDRSZ); + (void) snprintf(ipbuf, sizeof ipbuf, + "[%.100s]", inet_ntoa(ia)); + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + if (hp->h_length != IN6ADDRSZ) + break; + + memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); + addr = anynet_ntop(&ia6, buf6, sizeof buf6); + if (addr != NULL) + (void) snprintf(ipbuf, sizeof ipbuf, + "[%.100s]", addr); + break; +# endif /* NETINET6 */ } + if (ipbuf[0] == '\0') + break; + + if (tTd(0, 4)) + dprintf("\ta.k.a.: %s\n", ipbuf); + setclass('w', ipbuf); } -#endif +#endif /* NETINET || NETINET6 */ } /* current time */ define('b', arpadate((char *) NULL), CurEnv); + /* current load average */ + CurrentLA = sm_getla(CurEnv); QueueLimitRecipient = (QUEUE_CHAR *) NULL; QueueLimitSender = (QUEUE_CHAR *) NULL; @@ -576,17 +661,17 @@ main(argc, argv, envp) { case MD_DAEMON: case MD_FGDAEMON: -# if !DAEMON +#if !DAEMON usrerr("Daemon mode not implemented"); ExitStat = EX_USAGE; break; -# endif /* DAEMON */ +#endif /* !DAEMON */ case MD_SMTP: -# if !SMTP +#if !SMTP usrerr("I don't speak SMTP"); ExitStat = EX_USAGE; break; -# endif /* SMTP */ +#endif /* !SMTP */ case MD_INITALIAS: case MD_DELIVER: @@ -619,7 +704,8 @@ main(argc, argv, envp) if (RealUid != 0) warn_C_flag = TRUE; ConfFile = optarg; - (void) drop_privileges(TRUE); + dp = drop_privileges(TRUE); + setstat(dp); safecf = FALSE; break; @@ -643,21 +729,31 @@ main(argc, argv, envp) FullName = newstr(optarg); break; + case 'G': /* relay (gateway) submission */ + /* already set */ + break; + case 'h': /* hop count */ - CurEnv->e_hopcount = strtol(optarg, &ep, 10); + CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10); if (*ep) { usrerr("Bad hop count (%s)", optarg); ExitStat = EX_USAGE; } break; - + + case 'L': /* program label */ + /* already set */ + break; + case 'n': /* don't alias */ NoAlias = TRUE; break; case 'N': /* delivery status notifications */ DefaultNotify |= QHASNOTIFY; + define(macid("{dsn_notify}", NULL), + newstr(optarg), CurEnv); if (strcasecmp(optarg, "never") == 0) break; for (p = optarg; p != NULL; optarg = p) @@ -708,43 +804,61 @@ main(argc, argv, envp) break; case 'q': /* run queue files at intervals */ -# if QUEUE +#if QUEUE + /* sanity check */ + if (OpMode != MD_DELIVER && + OpMode != MD_DAEMON && + OpMode != MD_FGDAEMON && + OpMode != MD_PRINT && + OpMode != MD_QUEUERUN) + { + usrerr("Can not use -q with -b%c", OpMode); + ExitStat = EX_USAGE; + break; + } + + /* don't override -bd, -bD or -bp */ + if (OpMode == MD_DELIVER) + OpMode = MD_QUEUERUN; + FullName = NULL; - queuemode = TRUE; + switch (optarg[0]) { case 'I': - if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) - syserr("!Out of memory!!"); + new = (QUEUE_CHAR *) xalloc(sizeof *new); new->queue_match = newstr(&optarg[1]); new->queue_next = QueueLimitId; QueueLimitId = new; break; case 'R': - if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) - syserr("!Out of memory!!"); + new = (QUEUE_CHAR *) xalloc(sizeof *new); new->queue_match = newstr(&optarg[1]); new->queue_next = QueueLimitRecipient; QueueLimitRecipient = new; break; case 'S': - if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) - syserr("!Out of memory!!"); + new = (QUEUE_CHAR *) xalloc(sizeof *new); new->queue_match = newstr(&optarg[1]); new->queue_next = QueueLimitSender; QueueLimitSender = new; break; default: + i = Errors; QueueIntvl = convtime(optarg, 'm'); + + /* check for bad conversion */ + if (i < Errors) + ExitStat = EX_USAGE; break; } -# else /* QUEUE */ +#else /* QUEUE */ usrerr("I don't know about queues"); ExitStat = EX_USAGE; -# endif /* QUEUE */ +#endif /* QUEUE */ break; case 'R': /* DSN RET: what to return */ @@ -762,6 +876,8 @@ main(argc, argv, envp) usrerr("Invalid -R value"); ExitStat = EX_USAGE; } + define(macid("{dsn_ret}", NULL), + newstr(optarg), CurEnv); break; case 't': /* read recipients from message */ @@ -769,7 +885,7 @@ main(argc, argv, envp) break; case 'U': /* initial (user) submission */ - UserSubmission = TRUE; + /* already set */ break; case 'V': /* DSN ENVID: set "original" envelope id */ @@ -779,23 +895,32 @@ main(argc, argv, envp) ExitStat = EX_USAGE; } else + { CurEnv->e_envid = newstr(optarg); + define(macid("{dsn_envid}", NULL), + newstr(optarg), CurEnv); + } break; case 'X': /* traffic log file */ - (void) drop_privileges(TRUE); - TrafficLogFile = fopen(optarg, "a"); + dp = drop_privileges(TRUE); + setstat(dp); + if (stat(optarg, &traf_st) == 0 && + S_ISFIFO(traf_st.st_mode)) + TrafficLogFile = fopen(optarg, "w"); + else + TrafficLogFile = fopen(optarg, "a"); if (TrafficLogFile == NULL) { syserr("cannot open %s", optarg); ExitStat = EX_CANTCREAT; break; } -#ifdef HASSETVBUF - setvbuf(TrafficLogFile, NULL, _IOLBF, 0); -#else - setlinebuf(TrafficLogFile); -#endif +#if HASSETVBUF + (void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0); +#else /* HASSETVBUF */ + (void) setlinebuf(TrafficLogFile); +#endif /* HASSETVBUF */ break; /* compatibility flags */ @@ -816,22 +941,22 @@ main(argc, argv, envp) setoption('f', "T", FALSE, TRUE, CurEnv); break; -# ifdef DBM +#ifdef DBM case 'I': /* initialize alias DBM file */ OpMode = MD_INITALIAS; break; -# endif /* DBM */ +#endif /* DBM */ -# if defined(__osf__) || defined(_AIX3) +#if defined(__osf__) || defined(_AIX3) case 'x': /* random flag that OSF/1 & AIX mailx passes */ break; -# endif -# if defined(sony_news) +#endif /* defined(__osf__) || defined(_AIX3) */ +#if defined(sony_news) case 'E': case 'J': /* ignore flags for Japanese code conversion - impremented on Sony NEWS */ + implemented on Sony NEWS */ break; -# endif +#endif /* defined(sony_news) */ default: finis(TRUE, EX_USAGE); @@ -840,6 +965,35 @@ main(argc, argv, envp) } av += optind; + if (bitset(SUBMIT_MTA, SubmitMode) && + bitset(SUBMIT_MSA, SubmitMode)) + { + /* sanity check */ + errno = 0; /* reset to avoid bogus error messages */ + syserr("Cannot use both -G and -U together"); + } + else if (bitset(SUBMIT_MTA, SubmitMode)) + define(macid("{daemon_flags}", NULL), "CC f", CurEnv); + else if (bitset(SUBMIT_MSA, SubmitMode)) + { + define(macid("{daemon_flags}", NULL), "c u", CurEnv); + + /* check for wrong OpMode */ + if (OpMode != MD_DELIVER && OpMode != MD_SMTP) + { + errno = 0; /* reset to avoid bogus error msgs */ + syserr("Cannot use -U and -b%c", OpMode); + } + } + else + { +#if _FFR_DEFAULT_SUBMIT_TO_MSA + define(macid("{daemon_flags}", NULL), "c u", CurEnv); +#else /* _FFR_DEFAULT_SUBMIT_TO_MSA */ + /* EMPTY */ +#endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */ + } + /* ** Do basic initialization. ** Read system control file. @@ -857,8 +1011,9 @@ main(argc, argv, envp) #if XDEBUG checkfd012("before readcf"); -#endif +#endif /* XDEBUG */ vendor_pre_defaults(CurEnv); + readcf(getcfname(), safecf, CurEnv); ConfigFileRead = TRUE; vendor_post_defaults(CurEnv); @@ -878,15 +1033,21 @@ main(argc, argv, envp) if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) { /* drop privileges -- daemon mode done after socket/bind */ - (void) drop_privileges(FALSE); + dp = drop_privileges(FALSE); + setstat(dp); } +#if NAMED_BIND + _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; + _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; +#endif /* NAMED_BIND */ + /* ** Find our real host name for future logging. */ - p = getauthinfo(STDIN_FILENO, &forged); - define('_', p, CurEnv); + authinfo = getauthinfo(STDIN_FILENO, &forged); + define('_', authinfo, CurEnv); /* suppress error printing if errors mailed back or whatever */ if (CurEnv->e_errormode != EM_PRINT) @@ -902,16 +1063,16 @@ main(argc, argv, envp) if (tTd(0, 1)) { - printf("\n============ SYSTEM IDENTITY (after readcf) ============"); - printf("\n (short domain name) $w = "); + dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); + dprintf("\n (short domain name) $w = "); xputs(macvalue('w', CurEnv)); - printf("\n (canonical domain name) $j = "); + dprintf("\n (canonical domain name) $j = "); xputs(macvalue('j', CurEnv)); - printf("\n (subdomain name) $m = "); + dprintf("\n (subdomain name) $m = "); xputs(macvalue('m', CurEnv)); - printf("\n (node name) $k = "); + dprintf("\n (node name) $k = "); xputs(macvalue('k', CurEnv)); - printf("\n========================================================\n\n"); + dprintf("\n========================================================\n\n"); } /* @@ -923,11 +1084,12 @@ main(argc, argv, envp) if (warn_C_flag) auth_warning(CurEnv, "Processed by %s with -C %s", RealUserName, ConfFile); - if (Warn_Q_option) + if (Warn_Q_option && !wordinclass(RealUserName, 't')) auth_warning(CurEnv, "Processed from queue %s", QueueDir); /* check body type for legality */ if (CurEnv->e_bodytype == NULL) + /* EMPTY */ /* nothing */ ; else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0) SevenBitInput = TRUE; @@ -944,7 +1106,7 @@ main(argc, argv, envp) DefaultNotify = QPINGONFAILURE|QPINGONDELAY; /* be sure we don't pick up bogus HOSTALIASES environment variable */ - if (queuemode && RealUid != 0) + if (OpMode == MD_QUEUERUN && RealUid != 0) (void) unsetenv("HOSTALIASES"); /* check for sane configuration level */ @@ -977,10 +1139,10 @@ main(argc, argv, envp) { if (LogLevel > 1) sm_syslog(LOG_ALERT, NOQID, - "user %d attempted to %s", - RealUid, - OpMode != MD_PURGESTAT ? "run daemon" - : "purge host status"); + "user %d attempted to %s", + RealUid, + OpMode != MD_PURGESTAT ? "run daemon" + : "purge host status"); usrerr("Permission denied"); finis(FALSE, EX_USAGE); } @@ -993,9 +1155,9 @@ main(argc, argv, envp) sm_syslog(LOG_ALERT, NOQID, "user %d attempted to rebuild the alias map", RealUid); - usrerr("Permission denied"); - finis(FALSE, EX_USAGE); - } + usrerr("Permission denied"); + finis(FALSE, EX_USAGE); + } if (MeToo) BlankEnvelope.e_flags |= EF_METOO; @@ -1016,13 +1178,13 @@ main(argc, argv, envp) HoldErrs = FALSE; /* arrange to exit cleanly on hangup signal */ if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) - setsignal(SIGHUP, intsig); + (void) setsignal(SIGHUP, intsig); break; case MD_FGDAEMON: run_in_foreground = TRUE; OpMode = MD_DAEMON; - /* fall through ... */ + /* FALLTHROUGH */ case MD_DAEMON: vendor_daemon_setup(CurEnv); @@ -1034,28 +1196,23 @@ main(argc, argv, envp) /* arrange to restart on hangup signal */ if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') sm_syslog(LOG_WARNING, NOQID, - "daemon invoked without full pathname; kill -1 won't work"); - setsignal(SIGHUP, sighup); + "daemon invoked without full pathname; kill -1 won't work"); + (void) setsignal(SIGHUP, sighup); /* workaround: can't seem to release the signal in the parent */ - releasesignal(SIGHUP); + (void) releasesignal(SIGHUP); break; case MD_INITALIAS: Verbose = 2; CurEnv->e_errormode = EM_PRINT; HoldErrs = FALSE; - /* fall through... */ - - case MD_PRINT: - /* to handle sendmail -bp -qSfoobar properly */ - queuemode = FALSE; - /* fall through... */ + /* FALLTHROUGH */ default: /* arrange to exit cleanly on hangup signal */ if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) - setsignal(SIGHUP, intsig); + (void) setsignal(SIGHUP, intsig); break; } @@ -1063,18 +1220,15 @@ main(argc, argv, envp) if (FullName != NULL) { char *full = NULL; - extern bool rfc822_string __P((char *)); /* full names can't have newlines */ - if (strchr(FullName, '\n') != NULL) + if (strchr(FullName, '\n') != NULL) { FullName = full = newstr(denlstring(FullName, TRUE, TRUE)); } /* check for characters that may have to be quoted */ if (!rfc822_string(FullName)) { - extern char *addquotes __P((char *)); - /* ** Quote a full name with special characters ** as a comment so crackaddr() doesn't destroy @@ -1100,13 +1254,11 @@ main(argc, argv, envp) /* check for vendor mismatch */ if (VendorCode != VENDOR_CODE) { - extern char *getvendor __P((int)); - message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", getvendor(VENDOR_CODE), getvendor(VendorCode)); } -#endif - +#endif /* VENDOR_CODE */ + /* check for out of date configuration level */ if (ConfigLevel < MAXCONFIGLEVEL) { @@ -1115,9 +1267,7 @@ main(argc, argv, envp) } if (ConfigLevel < 3) - { UseErrorsTo = TRUE; - } /* set options that were previous macros */ if (SmtpGreeting == NULL) @@ -1134,6 +1284,7 @@ main(argc, argv, envp) else UnixFromLine = "From \201g \201d"; } + SmtpError[0] = '\0'; /* our name for SMTP codes */ expand("\201j", jbuf, sizeof jbuf, CurEnv); @@ -1221,9 +1372,8 @@ main(argc, argv, envp) setclass('b', "audio"); setclass('b', "video"); setclass('b', "application/octet-stream"); -#endif +#endif /* USE_B_CLASS */ -#if _FFR_MAX_MIME_HEADER_LENGTH /* MIME headers which have fields to check for overflow */ setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition"); setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type"); @@ -1237,7 +1387,14 @@ main(argc, argv, envp) setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding"); setclass(macid("{checkMIMEHeaders}", NULL), "content-type"); setclass(macid("{checkMIMEHeaders}", NULL), "mime-version"); -#endif + + /* Macros to save in the qf file -- don't remove any */ + setclass(macid("{persistentMacros}", NULL), "r"); + setclass(macid("{persistentMacros}", NULL), "s"); + setclass(macid("{persistentMacros}", NULL), "_"); + setclass(macid("{persistentMacros}", NULL), "{if_addr}"); + setclass(macid("{persistentMacros}", NULL), "{daemon_flags}"); + setclass(macid("{persistentMacros}", NULL), "{client_flags}"); /* operate in queue directory */ if (QueueDir == NULL) @@ -1250,13 +1407,14 @@ main(argc, argv, envp) } else { - /* test path to get warning messages */ - (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE); - if (OpMode != MD_TEST && chdir(QueueDir) < 0) - { - syserr("cannot chdir(%s)", QueueDir); - ExitStat = EX_CONFIG; - } + /* + ** If multiple queues wildcarded, use one for + ** the daemon's home. Note that this preconditions + ** a wildcarded QueueDir to a real pathname. + */ + + if (OpMode != MD_TEST) + multiqueue_cache(); } /* check host status directory for validity */ @@ -1264,13 +1422,14 @@ main(argc, argv, envp) { /* cannot use this value */ if (tTd(0, 2)) - printf("Cannot use HostStatusDirectory = %s: %s\n", + dprintf("Cannot use HostStatusDirectory = %s: %s\n", HostStatDir, errstring(errno)); HostStatDir = NULL; } -# if QUEUE - if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) +#if QUEUE + if (OpMode == MD_QUEUERUN && RealUid != 0 && + bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) { struct stat stbuf; @@ -1284,7 +1443,13 @@ main(argc, argv, envp) finis(FALSE, EX_NOPERM); } } -# endif /* QUEUE */ +#endif /* QUEUE */ + +#if _FFR_MILTER + /* sanity checks on milter filters */ + if (OpMode == MD_DAEMON || OpMode == MD_SMTP) + milter_parse_list(InputFilterList, InputFilters, MAXFILTERS); +#endif /* _FFR_MILTER */ /* if we've had errors so far, exit now */ if (ExitStat != EX_OK && OpMode != MD_TEST) @@ -1292,7 +1457,7 @@ main(argc, argv, envp) #if XDEBUG checkfd012("before main() initmaps"); -#endif +#endif /* XDEBUG */ /* ** Do operation-mode-dependent initialization. @@ -1304,29 +1469,29 @@ main(argc, argv, envp) /* print the queue */ #if QUEUE dropenvelope(CurEnv, TRUE); - signal(SIGPIPE, quiesce); + (void) setsignal(SIGPIPE, quiesce); printqueue(); finis(FALSE, EX_OK); #else /* QUEUE */ usrerr("No queue to print"); - finis(FALSE, ExitStat); + finis(FALSE, EX_UNAVAILABLE); #endif /* QUEUE */ break; case MD_HOSTSTAT: - signal(SIGPIPE, quiesce); - mci_traverse_persistent(mci_print_persistent, NULL); + (void) setsignal(SIGPIPE, quiesce); + (void) mci_traverse_persistent(mci_print_persistent, NULL); finis(FALSE, EX_OK); - break; + break; case MD_PURGESTAT: - mci_traverse_persistent(mci_purge_persistent, NULL); + (void) mci_traverse_persistent(mci_purge_persistent, NULL); finis(FALSE, EX_OK); - break; + break; case MD_INITALIAS: /* initialize maps */ - initmaps(TRUE, CurEnv); + initmaps(); finis(FALSE, ExitStat); break; @@ -1334,22 +1499,18 @@ main(argc, argv, envp) case MD_DAEMON: /* reset DSN parameters */ DefaultNotify = QPINGONFAILURE|QPINGONDELAY; + define(macid("{dsn_notify}", NULL), NULL, CurEnv); CurEnv->e_envid = NULL; + define(macid("{dsn_envid}", NULL), NULL, CurEnv); CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); + define(macid("{dsn_ret}", NULL), NULL, CurEnv); /* don't open maps for daemon -- done below in child */ break; - - default: - /* open the maps */ - initmaps(FALSE, CurEnv); - break; } if (tTd(0, 15)) { - extern void printrules __P((void)); - /* print configuration table (or at least part of it) */ if (tTd(0, 90)) printrules(); @@ -1374,7 +1535,6 @@ main(argc, argv, envp) if (OpMode == MD_TEST) { char buf[MAXLINE]; - SIGFUNC_DECL intindebug __P((int)); if (isatty(fileno(stdin))) Verbose = 2; @@ -1389,13 +1549,11 @@ main(argc, argv, envp) (void) setsignal(SIGINT, intindebug); for (;;) { - extern void testmodeline __P((char *, ENVELOPE *)); - if (Verbose == 2) printf("> "); (void) fflush(stdout); if (fgets(buf, sizeof buf, stdin) == NULL) - finis(TRUE, ExitStat); + testmodeline("/quit", CurEnv); p = strchr(buf, '\n'); if (p != NULL) *p = '\0'; @@ -1405,17 +1563,44 @@ main(argc, argv, envp) } } -# if QUEUE +#if SMTP +# if STARTTLS + /* + ** basic TLS initialization + ** ignore result for now + */ + SSL_library_init(); + SSL_load_error_strings(); +# if 0 + /* this is currently a macro for SSL_library_init */ + SSLeay_add_ssl_algorithms(); +# endif /* 0 */ + + /* initialize PRNG */ + tls_rand_init(RandFile, 7); + +# endif /* STARTTLS */ +#endif /* SMTP */ + +#if QUEUE /* ** If collecting stuff from the queue, go start doing that. */ - if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) + if (OpMode == MD_QUEUERUN && QueueIntvl == 0) { +# if SMTP +# if STARTTLS + { + /* init TLS for client, ignore result for now */ + (void) initclttls(); + } +# endif /* STARTTLS */ +# endif /* SMTP */ (void) runqueue(FALSE, Verbose); finis(TRUE, ExitStat); } -# endif /* QUEUE */ +#endif /* QUEUE */ /* ** If a daemon, wait for a request. @@ -1429,7 +1614,6 @@ main(argc, argv, envp) if (OpMode == MD_DAEMON || QueueIntvl != 0) { char dtype[200]; - extern void getrequests __P((ENVELOPE *)); if (!run_in_foreground && !tTd(99, 100)) { @@ -1446,40 +1630,55 @@ main(argc, argv, envp) dtype[0] = '\0'; if (OpMode == MD_DAEMON) - strcat(dtype, "+SMTP"); + (void) strlcat(dtype, "+SMTP", sizeof dtype); if (QueueIntvl != 0) { - strcat(dtype, "+queueing@"); - strcat(dtype, pintvl(QueueIntvl, TRUE)); + (void) strlcat(dtype, "+queueing@", sizeof dtype); + (void) strlcat(dtype, pintvl(QueueIntvl, TRUE), + sizeof dtype); } if (tTd(0, 1)) - strcat(dtype, "+debugging"); + (void) strlcat(dtype, "+debugging", sizeof dtype); sm_syslog(LOG_INFO, NOQID, - "starting daemon (%s): %s", Version, dtype + 1); + "starting daemon (%s): %s", Version, dtype + 1); #ifdef XLA xla_create_file(); -#endif +#endif /* XLA */ + + /* save daemon type in a macro for possible PidFile use */ + define(macid("{daemon_info}", NULL), + newstr(dtype + 1), &BlankEnvelope); -# if QUEUE - if (queuemode) + /* save queue interval in a macro for possible PidFile use */ + define(macid("{queue_interval}", NULL), + newstr(pintvl(QueueIntvl, TRUE)), CurEnv); + +#if QUEUE + if (QueueIntvl != 0) { (void) runqueue(TRUE, FALSE); if (OpMode != MD_DAEMON) { + /* write the pid to file */ + log_sendmail_pid(CurEnv); for (;;) { - pause(); + (void) pause(); if (DoQueueRun) (void) runqueue(TRUE, FALSE); } } } -# endif /* QUEUE */ +#endif /* QUEUE */ dropenvelope(CurEnv, TRUE); #if DAEMON - getrequests(CurEnv); +# if STARTTLS + /* init TLS for server, ignore result for now */ + (void) initsrvtls(); +# endif /* STARTTLS */ + p_flags = getrequests(CurEnv); /* drop privileges */ (void) drop_privileges(FALSE); @@ -1491,12 +1690,18 @@ main(argc, argv, envp) ** Get authentication data */ - p = getauthinfo(fileno(InChannel), &forged); - define('_', p, &BlankEnvelope); + authinfo = getauthinfo(fileno(InChannel), &forged); + define('_', authinfo, &BlankEnvelope); #endif /* DAEMON */ } -# if SMTP + if (LogLevel > 9) + { + /* log connection information */ + sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo); + } + +#if SMTP /* ** If running SMTP protocol, start collecting and executing ** commands. This will never return. @@ -1505,7 +1710,6 @@ main(argc, argv, envp) if (OpMode == MD_SMTP || OpMode == MD_DAEMON) { char pbuf[20]; - extern void smtp __P((char *, ENVELOPE *)); /* ** Save some macros for check_* rulesets. @@ -1515,24 +1719,46 @@ main(argc, argv, envp) { char ipbuf[103]; - snprintf(ipbuf, sizeof ipbuf, "[%.100s]", - inet_ntoa(RealHostAddr.sin.sin_addr)); - + (void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]", + anynet_ntoa(&RealHostAddr)); define(macid("{client_name}", NULL), newstr(ipbuf), &BlankEnvelope); + define(macid("{client_resolve}", NULL), + "FORGED", &BlankEnvelope); } else - define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope); + define(macid("{client_name}", NULL), RealHostName, + &BlankEnvelope); define(macid("{client_addr}", NULL), newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); - if (RealHostAddr.sa.sa_family == AF_INET) - snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port); - else - snprintf(pbuf, sizeof pbuf, "0"); - define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); + (void)sm_getla(&BlankEnvelope); + + switch(RealHostAddr.sa.sa_family) + { +# if NETINET + case AF_INET: + (void) snprintf(pbuf, sizeof pbuf, "%d", + RealHostAddr.sin.sin_port); + break; +# endif /* NETINET */ +# if NETINET6 + case AF_INET6: + (void) snprintf(pbuf, sizeof pbuf, "%d", + RealHostAddr.sin6.sin6_port); + break; +# endif /* NETINET6 */ + default: + (void) snprintf(pbuf, sizeof pbuf, "0"); + break; + } + define(macid("{client_port}", NULL), + newstr(pbuf), &BlankEnvelope); - /* initialize maps now for check_relay ruleset */ - initmaps(FALSE, CurEnv); +#if SASL + /* give a syserr or just disable AUTH ? */ + if (sasl_server_init(srvcallbacks, "Sendmail") != SASL_OK) + syserr("!sasl_server_init failed!"); +#endif /* SASL */ if (OpMode == MD_DAEMON) { @@ -1542,14 +1768,23 @@ main(argc, argv, envp) RealHostName, CurEnv); HoldErrs = FALSE; } - smtp(nullserver, CurEnv); + else if (p_flags == NULL) + { + p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); + clrbitmap(p_flags); + } +# if STARTTLS + if (OpMode == MD_SMTP) + (void) initsrvtls(); +# endif /* STARTTLS */ + smtp(nullserver, *p_flags, CurEnv); } -# endif /* SMTP */ +#endif /* SMTP */ clearenvelope(CurEnv, FALSE); if (OpMode == MD_VERIFY) { - CurEnv->e_sendmode = SM_VERIFY; + set_delivery_mode(SM_VERIFY, CurEnv); PostMasterCopy = NULL; } else @@ -1563,22 +1798,55 @@ main(argc, argv, envp) */ initsys(CurEnv); - if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't')) + define(macid("{ntries}", NULL), "0", CurEnv); + setsender(from, CurEnv, NULL, '\0', FALSE); + if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && + (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) || + strcmp(CurEnv->e_from.q_user, RealUserName) != 0)) + { auth_warning(CurEnv, "%s set sender to %s using -%c", RealUserName, from, warn_f_flag); - setsender(from, CurEnv, NULL, '\0', FALSE); +#if SASL + auth = FALSE; +#endif /* SASL */ + } + if (auth) + { + char *fv; + + /* set the initial sender for AUTH= to $f@$j */ + fv = macvalue('f', CurEnv); + if (fv == NULL || *fv == '\0') + CurEnv->e_auth_param = NULL; + else + { + if (strchr(fv, '@') == NULL) + { + i = strlen(fv) + strlen(macvalue('j', CurEnv)) + + 2; + p = xalloc(i); + (void) snprintf(p, i, "%s@%s", fv, + macvalue('j', CurEnv)); + } + else + p = newstr(fv); + CurEnv->e_auth_param = newstr(xtextify(p, NULL)); + } + } if (macvalue('s', CurEnv) == NULL) define('s', RealHostName, CurEnv); if (*av == NULL && !GrabTo) { + CurEnv->e_to = NULL; CurEnv->e_flags |= EF_GLOBALERRS; + HoldErrs = FALSE; usrerr("Recipient names must be specified"); /* collect body for UUCP return */ if (OpMode != MD_VERIFY) collect(InChannel, FALSE, NULL, CurEnv); - finis(TRUE, ExitStat); + finis(TRUE, EX_USAGE); } /* @@ -1600,11 +1868,11 @@ main(argc, argv, envp) if (GrabTo) { ADDRESS *q; - + for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) - q->q_flags |= QDONTSEND; + q->q_state = QS_REMOVED; } -#endif +#endif /* _FFR_FIX_DASHT */ /* ** Read the input mail. @@ -1613,40 +1881,77 @@ main(argc, argv, envp) CurEnv->e_to = NULL; if (OpMode != MD_VERIFY || GrabTo) { + int savederrors = Errors; long savedflags = CurEnv->e_flags & EF_FATALERRS; CurEnv->e_flags |= EF_GLOBALERRS; CurEnv->e_flags &= ~EF_FATALERRS; + Errors = 0; + buffer_errors(); collect(InChannel, FALSE, NULL, CurEnv); + /* header checks failed */ + if (Errors > 0) + { + /* Log who the mail would have gone to */ + if (LogLevel > 8 && CurEnv->e_message != NULL && + !GrabTo) + { + ADDRESS *a; + + for (a = CurEnv->e_sendqueue; + a != NULL; + a = a->q_next) + { + if (!QS_IS_UNDELIVERED(a->q_state)) + continue; + + CurEnv->e_to = a->q_paddr; + logdelivery(NULL, NULL, NULL, + CurEnv->e_message, + NULL, (time_t) 0, CurEnv); + } + CurEnv->e_to = NULL; + } + flush_errors(TRUE); + finis(TRUE, ExitStat); + /* NOTREACHED */ + return -1; + } + /* bail out if message too large */ if (bitset(EF_CLRQUEUE, CurEnv->e_flags)) { - finis(TRUE, ExitStat); - /*NOTREACHED*/ + finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR); + /* NOTREACHED */ return -1; } + Errors = savederrors; CurEnv->e_flags |= savedflags; } errno = 0; if (tTd(1, 1)) - printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); + dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); /* ** Actually send everything. ** If verifying, just ack. */ - CurEnv->e_from.q_flags |= QDONTSEND; + CurEnv->e_from.q_state = QS_SENDER; if (tTd(1, 5)) { - printf("main: QDONTSEND "); + dprintf("main: QS_SENDER "); printaddr(&CurEnv->e_from, FALSE); } CurEnv->e_to = NULL; - CurrentLA = getla(); + CurrentLA = sm_getla(CurEnv); GrabTo = FALSE; +#if NAMED_BIND + _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; + _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; +#endif /* NAMED_BIND */ sendall(CurEnv, SM_DEFAULT); /* @@ -1655,8 +1960,8 @@ main(argc, argv, envp) */ finis(TRUE, ExitStat); - /*NOTREACHED*/ - return -1; + /* NOTREACHED */ + return ExitStat; } /* ARGSUSED */ @@ -1664,6 +1969,7 @@ SIGFUNC_DECL quiesce(sig) int sig; { + clear_events(); finis(FALSE, EX_OK); } @@ -1675,8 +1981,6 @@ intindebug(sig) longjmp(TopFrame, 1); return SIGFUNC_RETURN; } - - /* ** FINIS -- Clean up and exit. ** @@ -1696,16 +2000,10 @@ finis(drop, exitstat) bool drop; volatile int exitstat; { - extern void closemaps __P((void)); -#ifdef USERDB - extern void _udbx_close __P((void)); -#endif if (tTd(2, 1)) { - extern void printenvflags __P((ENVELOPE *)); - - printf("\n====finis: stat %d e_id=%s e_flags=", + dprintf("\n====finis: stat %d e_id=%s e_flags=", exitstat, CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); printenvflags(CurEnv); @@ -1722,8 +2020,13 @@ finis(drop, exitstat) /* clean up temp files */ CurEnv->e_to = NULL; - if (drop && CurEnv->e_id != NULL) - dropenvelope(CurEnv, TRUE); + if (drop) + { + if (CurEnv->e_id != NULL) + dropenvelope(CurEnv, TRUE); + else + poststats(StatFile); + } /* flush any cached connections */ mci_flush(TRUE, NULL); @@ -1731,35 +2034,36 @@ finis(drop, exitstat) /* close maps belonging to this pid */ closemaps(); -#ifdef USERDB +#if USERDB /* close UserDatabase */ _udbx_close(); -#endif +#endif /* USERDB */ -# ifdef XLA +#ifdef XLA /* clean up extended load average stuff */ xla_all_end(); -# endif +#endif /* XLA */ /* and exit */ forceexit: if (LogLevel > 78) sm_syslog(LOG_DEBUG, CurEnv->e_id, - "finis, pid=%d", - getpid()); + "finis, pid=%d", + getpid()); if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) exitstat = EX_OK; + sync_queue_time(); + /* reset uid for process accounting */ endpwent(); - setuid(RealUid); - + (void) setuid(RealUid); exit(exitstat); } /* ** INTSIG -- clean up on interrupt ** -** This just arranges to exit. It pessimises in that it +** This just arranges to exit. It pessimizes in that it ** may resend a message. ** ** Parameters: @@ -1777,15 +2081,48 @@ SIGFUNC_DECL intsig(sig) int sig; { - if (LogLevel > 79) + bool drop = FALSE; + + clear_events(); + if (sig != 0 && LogLevel > 79) sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); FileName = NULL; - unlockqueue(CurEnv); closecontrolsocket(TRUE); #ifdef XLA xla_all_end(); -#endif - finis(FALSE, EX_OK); +#endif /* XLA */ + + /* Clean-up on aborted stdin message submission */ + if (CurEnv->e_id != NULL && + (OpMode == MD_SMTP || + OpMode == MD_DELIVER || + OpMode == MD_ARPAFTP)) + { + register ADDRESS *q; + + /* don't return an error indication */ + CurEnv->e_to = NULL; + CurEnv->e_flags &= ~EF_FATALERRS; + CurEnv->e_flags |= EF_CLRQUEUE; + + /* + ** Spin through the addresses and + ** mark them dead to prevent bounces + */ + + for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) + q->q_state = QS_DONTSEND; + + /* and don't try to deliver the partial message either */ + if (InChild) + ExitStat = EX_QUIT; + + drop = TRUE; + } + else + unlockqueue(CurEnv); + + finis(drop, EX_OK); } /* ** INITMACROS -- initialize the macro system @@ -1867,7 +2204,7 @@ initmacros(e) ** droplev -- how "deeply" we should drop the line. ** 0 -- ignore signals, mail back errors, make sure ** output goes to stdout. -** 1 -- also, make stdout go to transcript. +** 1 -- also, make stdout go to /dev/null. ** 2 -- also, disconnect from controlling terminal ** (only for daemon mode). ** e -- the current envelope. @@ -1888,17 +2225,17 @@ disconnect(droplev, e) int fd; if (tTd(52, 1)) - printf("disconnect: In %d Out %d, e=%lx\n", + dprintf("disconnect: In %d Out %d, e=%lx\n", fileno(InChannel), fileno(OutChannel), (u_long) e); if (tTd(52, 100)) { - printf("don't\n"); + dprintf("don't\n"); return; } if (LogLevel > 93) sm_syslog(LOG_DEBUG, e->e_id, - "disconnect level %d", - droplev); + "disconnect level %d", + droplev); /* be sure we don't get nasty signals */ (void) setsignal(SIGINT, SIG_IGN); @@ -1929,27 +2266,15 @@ disconnect(droplev, e) } if (droplev > 0) { - if (e->e_xfp == NULL) - { - fd = open("/dev/null", O_WRONLY, 0666); - if (fd == -1) - sm_syslog(LOG_ERR, e->e_id, - "disconnect: open(\"/dev/null\") failed: %s", - errstring(errno)); - } - else - { - fd = fileno(e->e_xfp); - if (fd == -1) - sm_syslog(LOG_ERR, e->e_id, - "disconnect: fileno(e->e_xfp) failed: %s", - errstring(errno)); - } + fd = open("/dev/null", O_WRONLY, 0666); + if (fd == -1) + sm_syslog(LOG_ERR, e->e_id, + "disconnect: open(\"/dev/null\") failed: %s", + errstring(errno)); (void) fflush(stdout); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (e->e_xfp == NULL) - close(fd); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + (void) close(fd); } /* drop our controlling TTY completely if possible */ @@ -1961,12 +2286,12 @@ disconnect(droplev, e) #if XDEBUG checkfd012("disconnect"); -#endif +#endif /* XDEBUG */ if (LogLevel > 71) sm_syslog(LOG_DEBUG, e->e_id, - "in background, pid=%d", - getpid()); + "in background, pid=%d", + getpid()); errno = 0; } @@ -1990,7 +2315,7 @@ obsolete(argv) ap[1] != 'd' && #if defined(sony_news) ap[1] != 'E' && ap[1] != 'J' && -#endif +#endif /* defined(sony_news) */ argv[1] != NULL && argv[1][0] != '-') { argv++; @@ -2002,9 +2327,8 @@ obsolete(argv) if (ap[1] == 'C' && ap[2] == '\0') { *argv = xalloc(sizeof(__DEFPATH) + 2); - argv[0][0] = '-'; - argv[0][1] = 'C'; - (void)strcpy(&argv[0][2], __DEFPATH); + (void) snprintf(argv[0], sizeof(__DEFPATH) + 2, "-C%s", + __DEFPATH); } /* If -q doesn't have an argument, run it once. */ @@ -2015,7 +2339,7 @@ obsolete(argv) if (ap[1] == 'd' && ap[2] == '\0') *argv = "-d0-99.1"; -# if defined(sony_news) +#if defined(sony_news) /* if -E doesn't have an argument, use -EC */ if (ap[1] == 'E' && ap[2] == '\0') *argv = "-EC"; @@ -2023,7 +2347,7 @@ obsolete(argv) /* if -J doesn't have an argument, use -JJ */ if (ap[1] == 'J' && ap[2] == '\0') *argv = "-JJ"; -# endif +#endif /* defined(sony_news) */ } } /* @@ -2041,12 +2365,12 @@ obsolete(argv) void #ifdef __STDC__ auth_warning(register ENVELOPE *e, const char *msg, ...) -#else +#else /* __STDC__ */ auth_warning(e, msg, va_alist) register ENVELOPE *e; const char *msg; va_dcl -#endif +#endif /* __STDC__ */ { char buf[MAXLINE]; VA_LOCAL_DECL @@ -2055,7 +2379,6 @@ auth_warning(e, msg, va_alist) { register char *p; static char hostbuf[48]; - extern struct hostent *myhostname __P((char *, int)); if (hostbuf[0] == '\0') (void) myhostname(hostbuf, sizeof hostbuf); @@ -2065,11 +2388,11 @@ auth_warning(e, msg, va_alist) VA_START(msg); vsnprintf(p, SPACELEFT(buf, p), msg, ap); VA_END; - addheader("X-Authentication-Warning", buf, &e->e_header); + addheader("X-Authentication-Warning", buf, 0, &e->e_header); if (LogLevel > 3) sm_syslog(LOG_INFO, e->e_id, - "Authentication-Warning: %.400s", - buf); + "Authentication-Warning: %.400s", + buf); } } /* @@ -2116,7 +2439,7 @@ setuserenv(envar, value) const char *envar; const char *value; { - int i; + int i, l; char **evp = UserEnviron; char *p; @@ -2127,11 +2450,10 @@ setuserenv(envar, value) return; } - i = strlen(envar); - p = (char *) xalloc(strlen(value) + i + 2); - strcpy(p, envar); - p[i++] = '='; - strcpy(&p[i], value); + i = strlen(envar) + 1; + l = strlen(value) + i + 1; + p = (char *) xalloc(l); + (void) snprintf(p, l, "%s=%s", envar, value); while (*evp != NULL && strncmp(*evp, p, i) != 0) evp++; @@ -2161,18 +2483,21 @@ dumpstate(when) { register char *j = macvalue('j', CurEnv); int rs; + extern int NextMacroId; sm_syslog(LOG_DEBUG, CurEnv->e_id, - "--- dumping state on %s: $j = %s ---", - when, - j == NULL ? "<NULL>" : j); + "--- dumping state on %s: $j = %s ---", + when, + j == NULL ? "<NULL>" : j); if (j != NULL) { if (!wordinclass(j, 'w')) sm_syslog(LOG_DEBUG, CurEnv->e_id, - "*** $j not in $=w ***"); + "*** $j not in $=w ***"); } sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); + sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)\n", + NextMacroId, MAXMACROID); sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); printopenfds(TRUE); sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); @@ -2180,15 +2505,15 @@ dumpstate(when) rs = strtorwset("debug_dumpstate", NULL, ST_FIND); if (rs > 0) { - int stat; + int status; register char **pvp; char *pv[MAXATOM + 1]; pv[0] = NULL; - stat = rewrite(pv, rs, 0, CurEnv); + status = rewrite(pv, rs, 0, CurEnv); sm_syslog(LOG_DEBUG, CurEnv->e_id, - "--- ruleset debug_dumpstate returns stat %d, pv: ---", - stat); + "--- ruleset debug_dumpstate returns stat %d, pv: ---", + status); for (pvp = pv; *pvp != NULL; pvp++) sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); } @@ -2211,27 +2536,50 @@ SIGFUNC_DECL sighup(sig) int sig; { + int i; + extern int DtableSize; + + clear_events(); + (void) alarm(0); if (SaveArgv[0][0] != '/') { if (LogLevel > 3) - sm_syslog(LOG_INFO, NOQID, "could not restart: need full path"); + sm_syslog(LOG_INFO, NOQID, + "could not restart: need full path"); finis(FALSE, EX_OSFILE); } if (LogLevel > 3) - sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]); - alarm(0); - releasesignal(SIGHUP); + sm_syslog(LOG_INFO, NOQID, "restarting %s %s", + sig == 0 ? "due to control command" : "on signal", + SaveArgv[0]); + + /* Control socket restart? */ + if (sig != 0) + (void) releasesignal(SIGHUP); + closecontrolsocket(TRUE); if (drop_privileges(TRUE) != EX_OK) { if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m", - RunAsUid, RunAsGid); + sm_syslog(LOG_ALERT, NOQID, + "could not set[ug]id(%d, %d): %m", + RunAsUid, RunAsGid); finis(FALSE, EX_OSERR); } - execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); + + /* arrange for all the files to be closed */ + for (i = 3; i < DtableSize; i++) + { + register int j; + + if ((j = fcntl(i, F_GETFD, 0)) != -1) + (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); + } + + (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]); + sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", + SaveArgv[0]); finis(FALSE, EX_OSFILE); } /* @@ -2254,8 +2602,9 @@ drop_privileges(to_real_uid) GIDSET_T emptygidset[1]; if (tTd(47, 1)) - printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", - (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid); + dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", + (int)to_real_uid, (int)RealUid, + (int)RealGid, (int)RunAsUid, (int)RunAsGid); if (to_real_uid) { @@ -2270,18 +2619,61 @@ drop_privileges(to_real_uid) /* reset group permissions; these can be set later */ emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); if (setgroups(1, emptygidset) == -1 && geteuid() == 0) + { + syserr("drop_privileges: setgroups(1, %d) failed", + (int)emptygidset[0]); rval = EX_OSERR; + } /* reset primary group and user id */ if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0) + { + syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid); rval = EX_OSERR; - if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0) - rval = EX_OSERR; + } + if (to_real_uid || RunAsUid != 0) + { + uid_t euid = geteuid(); + + if (setuid(RunAsUid) < 0) + { + syserr("drop_privileges: setuid(%d) failed", + (int)RunAsUid); + rval = EX_OSERR; + } + else if (RunAsUid != 0 && setuid(0) == 0) + { + /* + ** Believe it or not, the Linux capability model + ** allows a non-root process to override setuid() + ** on a process running as root and prevent that + ** process from dropping privileges. + */ + + syserr("drop_privileges: setuid(0) succeeded (when it should not)"); + rval = EX_OSERR; + } + else if (RunAsUid != euid && setuid(euid) == 0) + { + /* + ** Some operating systems will keep the saved-uid + ** if a non-root effective-uid calls setuid(real-uid) + ** making it possible to set it back again later. + */ + + syserr("drop_privileges: Unable to drop non-root set-user-id privileges"); + rval = EX_OSERR; + } + } if (tTd(47, 5)) { - printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", - (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); - printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); + dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", + (int)geteuid(), (int)getuid(), + (int)getegid(), (int)getgid()); + dprintf("drop_privileges: RunAsUser = %d:%d\n", + (int)RunAsUid, (int)RunAsGid); + if (tTd(47, 10)) + dprintf("drop_privileges: rval = %d\n", rval); } return rval; } @@ -2342,7 +2734,7 @@ fill_fd(fd, where) ** X normal process through rule set X */ -void +static void testmodeline(line, e) char *line; ENVELOPE *e; @@ -2358,20 +2750,19 @@ testmodeline(line, e) ADDRESS a; static int tryflags = RF_COPYNONE; char exbuf[MAXLINE]; - extern bool invalidaddr __P((char *, char *)); - extern char *crackaddr __P((char *)); - extern void dump_class __P((STAB *, int)); - extern void translate_dollars __P((char *)); - extern void help __P((char *)); + extern u_char TokTypeNoC[]; +#if _FFR_ADDR_TYPE + define(macid("{addr_type}", NULL), "e r", e); +#endif /* _FFR_ADDR_TYPE */ switch (line[0]) { case '#': - case 0: + case '\0': return; case '?': - help("-bt"); + help("-bt", e); return; case '.': /* config-style settings */ @@ -2438,22 +2829,22 @@ testmodeline(line, e) return; do { - putchar('R'); + (void) putchar('R'); s = rw->r_lhs; while (*s != NULL) { xputs(*s++); - putchar(' '); + (void) putchar(' '); } - putchar('\t'); - putchar('\t'); + (void) putchar('\t'); + (void) putchar('\t'); s = rw->r_rhs; while (*s != NULL) { xputs(*s++); - putchar(' '); + (void) putchar(' '); } - putchar('\n'); + (void) putchar('\n'); } while ((rw = rw->r_next) != NULL); break; @@ -2530,6 +2921,11 @@ testmodeline(line, e) printf("Usage: /[canon|map|mx|parse|try|tryflags]\n"); return; } + if (strcasecmp(&line[1], "quit") == 0) + { + CurEnv->e_id = NULL; + finis(TRUE, ExitStat); + } if (strcasecmp(&line[1], "mx") == 0) { #if NAMED_BIND @@ -2543,13 +2939,13 @@ testmodeline(line, e) printf("Usage: /mx address\n"); return; } - nmx = getmxrr(p, mxhosts, FALSE, &rcode); + nmx = getmxrr(p, mxhosts, NULL, FALSE, &rcode); printf("getmxrr(%s) returns %d value(s):\n", p, nmx); for (i = 0; i < nmx; i++) printf("\t%s\n", mxhosts[i]); -#else +#else /* NAMED_BIND */ printf("No MX code compiled in\n"); -#endif +#endif /* NAMED_BIND */ } else if (strcasecmp(&line[1], "canon") == 0) { @@ -2560,13 +2956,12 @@ testmodeline(line, e) printf("Usage: /canon address\n"); return; } - else if (strlen(p) >= sizeof host) + else if (strlcpy(host, p, sizeof host) >= sizeof host) { printf("Name too long\n"); return; } - strcpy(host, p); - (void) getcanonname(host, sizeof(host), HasWildcardMX); + (void) getcanonname(host, sizeof host, HasWildcardMX); printf("getcanonname(%s) returns %s\n", p, host); } else if (strcasecmp(&line[1], "map") == 0) @@ -2593,7 +2988,8 @@ testmodeline(line, e) printf("Map named \"%s\" not found\n", p); return; } - if (!bitset(MF_OPEN, map->s_map.map_mflags)) + if (!bitset(MF_OPEN, map->s_map.map_mflags) && + !openmap(&(map->s_map))) { printf("Map named \"%s\" not open\n", p); return; @@ -2611,7 +3007,7 @@ testmodeline(line, e) else if (strcasecmp(&line[1], "try") == 0) { MAILER *m; - STAB *s; + STAB *st; auto int rcode = EX_OK; q = strpbrk(p, " \t"); @@ -2625,13 +3021,13 @@ testmodeline(line, e) printf("Usage: /try mailer address\n"); return; } - s = stab(p, ST_MAILER, ST_FIND); - if (s == NULL) + st = stab(p, ST_MAILER, ST_FIND); + if (st == NULL) { printf("Unknown mailer %s\n", p); return; } - m = s->s_mailer; + m = st->s_mailer; printf("Trying %s %s address %s for mailer %s\n", bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient", @@ -2673,6 +3069,13 @@ testmodeline(line, e) break; } } +#if _FFR_ADDR_TYPE + exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; + exbuf[1] = ' '; + exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; + exbuf[3] = '\0'; + define(macid("{addr_type}", NULL), newstr(exbuf), e); +#endif /* _FFR_ADDR_TYPE */ } else if (strcasecmp(&line[1], "parse") == 0) { @@ -2723,13 +3126,13 @@ testmodeline(line, e) char pvpbuf[PSBUFSIZE]; pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, - &delimptr, NULL); + &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL); if (pvp == NULL) continue; p = q; while (*p != '\0') { - int stat; + int status; rs = strtorwset(p, NULL, ST_FIND); if (rs < 0) @@ -2737,18 +3140,17 @@ testmodeline(line, e) printf("Undefined ruleset %s\n", p); break; } - stat = rewrite(pvp, rs, 0, e); - if (stat != EX_OK) + status = rewrite(pvp, rs, 0, e); + if (status != EX_OK) printf("== Ruleset %s (%d) status %d\n", - p, rs, stat); + p, rs, status); while (*p != '\0' && *p++ != ',') continue; } } while (*(p = delimptr) != '\0'); } - -void +static void dump_class(s, id) register STAB *s; int id; |