diff options
Diffstat (limited to 'usr.sbin/sendmail/src/main.c')
| -rw-r--r-- | usr.sbin/sendmail/src/main.c | 1081 |
1 files changed, 842 insertions, 239 deletions
diff --git a/usr.sbin/sendmail/src/main.c b/usr.sbin/sendmail/src/main.c index bae41d5f67d6..1b2b9da15023 100644 --- a/usr.sbin/sendmail/src/main.c +++ b/usr.sbin/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -39,17 +39,15 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.55.1.7 (Berkeley) 3/5/95"; +static char sccsid[] = "@(#)main.c 8.162 (Berkeley) 11/18/95"; #endif /* not lint */ #define _DEFINE #include "sendmail.h" #if NAMED_BIND -#include <arpa/nameser.h> #include <resolv.h> #endif -#include <pwd.h> # ifdef lint char edata, end; @@ -94,21 +92,9 @@ ENVELOPE BlankEnvelope; /* a "blank" envelope */ ENVELOPE MainEnvelope; /* the envelope around the basic letter */ ADDRESS NullAddress = /* a null address */ { "", "", NULL, "" }; -char *UserEnviron[MAXUSERENVIRON + 2]; - /* saved user environment */ -char RealUserName[256]; /* the actual user id on this host */ char *CommandLineArgs; /* command line args for pid file */ bool Warn_Q_option = FALSE; /* warn about Q option use */ - -/* -** Pointers for setproctitle. -** This allows "ps" listings to give more useful information. -*/ - -# ifdef SETPROCTITLE -char **Argv = NULL; /* pointer to argument vector */ -char *LastArgv = NULL; /* end of argv */ -# endif /* SETPROCTITLE */ +char **SaveArgv; /* argument vector for re-execing */ static void obsolete(); @@ -118,8 +104,9 @@ ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR #endif /* SMTP */ #endif /* DAEMON */ -#define MAXCONFIGLEVEL 5 /* highest config version level known */ +#define MAXCONFIGLEVEL 6 /* highest config version level known */ +int main(argc, argv, envp) int argc; char **argv; @@ -127,7 +114,6 @@ main(argc, argv, envp) { register char *p; char **av; - extern int finis(); extern char Version[]; char *ep, *from; typedef int (*fnptr)(); @@ -139,22 +125,25 @@ main(argc, argv, envp) bool warn_C_flag = FALSE; char warn_f_flag = '\0'; static bool reenter = FALSE; - char *argv0 = argv[0]; struct passwd *pw; struct stat stb; + struct hostent *hp; char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ + static char rnamebuf[MAXNAME]; /* holds RealUserName */ extern int DtableSize; extern int optind; + extern int opterr; extern time_t convtime(); - extern putheader(), putbody(); extern void intsig(); - extern char **myhostname(); + extern struct hostent *myhostname(); extern char *arpadate(); extern char *getauthinfo(); extern char *getcfname(); extern char *optarg; extern char **environ; extern void sigusr1(); + extern void sighup(); + extern void initmacros __P((ENVELOPE *)); /* ** Check to see if we reentered. @@ -172,8 +161,8 @@ main(argc, argv, envp) /* do machine-dependent initializations */ init_md(argc, argv); - /* arrange to dump state on signal */ #ifdef SIGUSR1 + /* arrange to dump state on user-1 signal */ setsignal(SIGUSR1, sigusr1); #endif @@ -211,7 +200,9 @@ main(argc, argv, envp) # else openlog("sendmail", LOG_PID); # endif -#endif +#endif + + tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; @@ -231,25 +222,29 @@ main(argc, argv, envp) RealUid = getuid(); RealGid = getgid(); - pw = getpwuid(RealUid); + pw = sm_getpwuid(RealUid); if (pw != NULL) - (void) strcpy(RealUserName, pw->pw_name); + (void) strcpy(rnamebuf, pw->pw_name); else - (void) sprintf(RealUserName, "Unknown UID %d", RealUid); + (void) sprintf(rnamebuf, "Unknown UID %d", RealUid); + RealUserName = rnamebuf; /* save command line arguments */ i = 0; for (av = argv; *av != NULL; ) i += strlen(*av++) + 1; + SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); CommandLineArgs = xalloc(i); p = CommandLineArgs; - for (av = argv; *av != NULL; ) + for (av = argv, i = 0; *av != NULL; ) { + SaveArgv[i++] = newstr(*av); if (av != argv) *p++ = ' '; strcpy(p, *av++); p += strlen(p); } + SaveArgv[i] = NULL; /* Handle any non-getoptable constructions. */ obsolete(argv); @@ -259,63 +254,98 @@ main(argc, argv, envp) */ #if defined(__osf__) || defined(_AIX3) -# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:x" -#endif -#if defined(ultrix) -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mno:p:q:r:sTtvX:" +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:x" #endif -#if defined(NeXT) -# define OPTIONS "B:b:C:cd:e:F:f:h:IimnOo:p:q:r:sTtvX:" +#if defined(sony_news) +# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mnO:o:p:q:r:sTtvX:" #endif #ifndef OPTIONS -# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:" +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:" #endif + opterr = 0; while ((j = getopt(argc, argv, OPTIONS)) != EOF) { switch (j) { case 'd': - tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(optarg); setbuf(stdout, (char *) NULL); - printf("Version %s\n", Version); break; } } + opterr = 1; - InChannel = stdin; - OutChannel = stdout; - - /* - ** Move the environment so setproctitle can use the space at - ** the top of memory. - */ + if (tTd(0, 1)) + { + int ll; + extern char *CompileOptions[]; - for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++) + printf("Version %s\n Compiled with:", Version); + av = CompileOptions; + ll = 7; + while (*av != NULL) + { + if (ll + strlen(*av) > 63) + { + putchar('\n'); + ll = 0; + } + if (ll == 0) + { + putchar('\t'); + putchar('\t'); + } + else + putchar(' '); + printf("%s", *av); + ll += strlen(*av++) + 1; + } + putchar('\n'); + } + if (tTd(0, 10)) { - if (strncmp(p, "IFS=", 4) == 0 || strncmp(p, "LD_", 3) == 0) - continue; - UserEnviron[j++] = newstr(p); + int ll; + extern char *OsCompileOptions[]; + + printf(" OS Defines:", Version); + av = OsCompileOptions; + ll = 7; + while (*av != NULL) + { + if (ll + strlen(*av) > 63) + { + putchar('\n'); + ll = 0; + } + if (ll == 0) + { + putchar('\t'); + putchar('\t'); + } + else + putchar(' '); + printf("%s", *av); + ll += strlen(*av++) + 1; + } + putchar('\n'); +#ifdef _PATH_UNIX + printf("Kernel symbols:\t%s\n", _PATH_UNIX); +#endif + printf(" Config file:\t%s\n", getcfname()); + printf(" Pid file:\t%s\n", PidFile); } - UserEnviron[j] = NULL; - environ = UserEnviron; -# ifdef SETPROCTITLE - /* - ** Save start and extent of argv for setproctitle. - */ + InChannel = stdin; + OutChannel = stdout; - Argv = argv; - if (i > 0) - LastArgv = envp[i - 1] + strlen(envp[i - 1]); - else - LastArgv = argv[argc - 1] + strlen(argv[argc - 1]); -# endif /* SETPROCTITLE */ + /* initialize for setproctitle */ + initsetproctitle(argc, argv, envp); + + /* prime the child environment */ + setuserenv("AGENT", "sendmail"); if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) (void) setsignal(SIGINT, intsig); - if (setsignal(SIGHUP, SIG_IGN) != SIG_IGN) - (void) setsignal(SIGHUP, intsig); (void) setsignal(SIGTERM, intsig); (void) setsignal(SIGPIPE, SIG_IGN); OldUmask = umask(022); @@ -335,12 +365,13 @@ main(argc, argv, envp) /* initialize some macros, etc. */ initmacros(CurEnv); + init_vendor_macros(CurEnv); /* version */ define('v', Version, CurEnv); /* hostname */ - av = myhostname(jbuf, sizeof jbuf); + hp = myhostname(jbuf, sizeof jbuf); if (jbuf[0] != '\0') { struct utsname utsname; @@ -357,7 +388,6 @@ main(argc, argv, envp) if (p[1] != '\0') { define('m', newstr(&p[1]), CurEnv); - setclass('m', &p[1]); } while (p != NULL && strchr(&p[1], '.') != NULL) { @@ -378,19 +408,42 @@ main(argc, argv, envp) p = jbuf; } if (tTd(0, 4)) - printf("UUCP nodename: %s\n", p); + printf(" UUCP nodename: %s\n", p); p = newstr(p); define('k', p, CurEnv); setclass('k', p); setclass('w', p); } - while (av != NULL && *av != NULL) + if (hp != NULL) { - if (tTd(0, 4)) - printf("\ta.k.a.: %s\n", *av); - setclass('w', *av++); + for (av = hp->h_aliases; av != NULL && *av != NULL; av++) + { + if (tTd(0, 4)) + printf("\ta.k.a.: %s\n", *av); + setclass('w', *av); + } +#if NETINET + if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ) + { + register int i; + + for (i = 0; hp->h_addr_list[i] != NULL; i++) + { + char ipbuf[103]; + + sprintf(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); + } + } +#endif } + /* probe interfaces and locate any additional names */ + load_if_names(); + /* current time */ define('b', arpadate((char *) NULL), CurEnv); @@ -447,9 +500,7 @@ main(argc, argv, envp) case MD_TEST: case MD_INITALIAS: case MD_PRINT: -#ifdef MAYBE_NEXT_RELEASE case MD_ARPAFTP: -#endif OpMode = j; break; @@ -466,17 +517,14 @@ main(argc, argv, envp) break; case 'B': /* body type */ - if (strcasecmp(optarg, "7bit") == 0 || - strcasecmp(optarg, "8bitmime") == 0) - CurEnv->e_bodytype = newstr(optarg); - else - usrerr("Illegal body type %s", optarg); + CurEnv->e_bodytype = optarg; break; case 'C': /* select configuration file (already done) */ if (RealUid != 0) warn_C_flag = TRUE; ConfFile = optarg; + endpwent(); (void) setgid(RealGid); (void) setuid(RealUid); safecf = FALSE; @@ -520,6 +568,10 @@ main(argc, argv, envp) setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv); break; + case 'O': /* set option (long form) */ + setoption(' ', optarg, FALSE, TRUE, CurEnv); + break; + case 'p': /* set protocol */ p = strchr(optarg, ':'); if (p != NULL) @@ -574,6 +626,7 @@ main(argc, argv, envp) break; case 'X': /* traffic log file */ + endpwent(); setgid(RealGid); setuid(RealUid); TrafficLogFile = fopen(optarg, "a"); @@ -599,9 +652,7 @@ main(argc, argv, envp) break; case 'e': /* error message disposition */ -# if defined(ultrix) case 'M': /* define macro */ -# endif setoption(j, optarg, FALSE, TRUE, CurEnv); break; @@ -619,8 +670,10 @@ main(argc, argv, envp) case 'x': /* random flag that OSF/1 & AIX mailx passes */ break; # endif -# if defined(NeXT) - case 'O': /* random flag that NeXT Mail.app passes */ +# if defined(sony_news) + case 'E': + case 'J': /* ignore flags for Japanese code conversion + impremented on Sony NEWS */ break; # endif @@ -638,23 +691,42 @@ main(argc, argv, envp) ** Extract special fields for local use. */ -#ifdef XDEBUG + /* set up ${opMode} for use in config file */ + { + char mbuf[2]; + + mbuf[0] = OpMode; + mbuf[1] = '\0'; + define(MID_OPMODE, newstr(mbuf), CurEnv); + } + +#if XDEBUG checkfd012("before readcf"); #endif + vendor_pre_defaults(CurEnv); readcf(getcfname(), safecf, CurEnv); + vendor_post_defaults(CurEnv); + + /* suppress error printing if errors mailed back or whatever */ + if (CurEnv->e_errormode != EM_PRINT) + HoldErrs = TRUE; + + /* set up the $=m class now, after .cf has a chance to redefine $m */ + expand("\201m", jbuf, sizeof jbuf, CurEnv); + setclass('m', jbuf); if (tTd(0, 1)) { - printf("SYSTEM IDENTITY (after readcf):"); - printf("\n\t (short domain name) $w = "); + printf("\n============ SYSTEM IDENTITY (after readcf) ============"); + printf("\n (short domain name) $w = "); xputs(macvalue('w', CurEnv)); - printf("\n\t(canonical domain name) $j = "); + printf("\n (canonical domain name) $j = "); xputs(macvalue('j', CurEnv)); - printf("\n\t (subdomain name) $m = "); + printf("\n (subdomain name) $m = "); xputs(macvalue('m', CurEnv)); - printf("\n\t (node name) $k = "); + printf("\n (node name) $k = "); xputs(macvalue('k', CurEnv)); - printf("\n"); + printf("\n========================================================\n\n"); } /* @@ -662,47 +734,48 @@ main(argc, argv, envp) */ #if NAMED_BIND - if (!bitset(RES_INIT, _res.options)) + if (UseNameServer && !bitset(RES_INIT, _res.options)) res_init(); +# ifdef RES_NOALIASES + _res.options |= RES_NOALIASES; +# endif #endif /* - ** Process authorization warnings from command line. + ** Do more command line checking -- these are things that + ** have to modify the results of reading the config file. */ + /* process authorization warnings from command line */ if (warn_C_flag) auth_warning(CurEnv, "Processed by %s with -C %s", RealUserName, ConfFile); -/* - if (warn_f_flag != '\0') - auth_warning(CurEnv, "%s set sender to %s using -%c", - RealUserName, from, warn_f_flag); -*/ if (Warn_Q_option) auth_warning(CurEnv, "Processed from queue %s", QueueDir); + /* check body type for legality */ + if (CurEnv->e_bodytype == NULL) + /* nothing */ ; + else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0) + SevenBitInput = TRUE; + else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0) + SevenBitInput = FALSE; + else + { + usrerr("Illegal body type %s", CurEnv->e_bodytype); + CurEnv->e_bodytype = NULL; + } + /* Enforce use of local time (null string overrides this) */ if (TimeZoneSpec == NULL) unsetenv("TZ"); else if (TimeZoneSpec[0] != '\0') - { - char **evp = UserEnviron; - char tzbuf[100]; - - strcpy(tzbuf, "TZ="); - strcpy(&tzbuf[3], TimeZoneSpec); - - while (*evp != NULL && strncmp(*evp, "TZ=", 3) != 0) - evp++; - if (*evp == NULL) - { - *evp++ = newstr(tzbuf); - *evp = NULL; - } - else - *evp++ = newstr(tzbuf); - } + setuserenv("TZ", TimeZoneSpec); + else + setuserenv("TZ", NULL); + tzset(); + /* check for sane configuration level */ if (ConfigLevel > MAXCONFIGLEVEL) { syserr("Warning: .cf version level (%d) exceeds program functionality (%d)", @@ -712,32 +785,24 @@ main(argc, argv, envp) if (MeToo) BlankEnvelope.e_flags |= EF_METOO; -# ifdef QUEUE - if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) + switch (OpMode) { - struct stat stbuf; + case MD_DAEMON: + /* remove things that don't make sense in daemon mode */ + FullName = NULL; + GrabTo = FALSE; - /* check to see if we own the queue directory */ - if (stat(QueueDir, &stbuf) < 0) - syserr("main: cannot stat %s", QueueDir); - if (stbuf.st_uid != RealUid) - { - /* nope, really a botch */ - usrerr("You do not have permission to process the queue"); - exit (EX_NOPERM); - } - } -# endif /* QUEUE */ + /* arrange to restart on hangup signal */ + setsignal(SIGHUP, sighup); + break; - switch (OpMode) - { case MD_INITALIAS: Verbose = TRUE; - break; + /* fall through... */ - case MD_DAEMON: - /* remove things that don't make sense in daemon mode */ - FullName = NULL; + default: + /* arrange to exit cleanly on hangup signal */ + setsignal(SIGHUP, intsig); break; } @@ -760,31 +825,56 @@ main(argc, argv, envp) UseErrorsTo = TRUE; } + /* set options that were previous macros */ + if (SmtpGreeting == NULL) + { + if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL) + SmtpGreeting = newstr(p); + else + SmtpGreeting = "\201j Sendmail \201v ready at \201b"; + } + if (UnixFromLine == NULL) + { + if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL) + UnixFromLine = newstr(p); + else + UnixFromLine = "From \201g \201d"; + } + /* our name for SMTP codes */ - expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); + expand("\201j", jbuf, sizeof jbuf, CurEnv); MyHostName = jbuf; + if (strchr(jbuf, '.') == NULL) + message("WARNING: local host name (%s) is not qualified; fix $j in config file", + jbuf); /* make certain that this name is part of the $=w class */ setclass('w', MyHostName); /* the indices of built-in mailers */ st = stab("local", ST_MAILER, ST_FIND); - if (st == NULL) - syserr("No local mailer defined"); - else + if (st != NULL) LocalMailer = st->s_mailer; + else if (OpMode != MD_TEST || !warn_C_flag) + syserr("No local mailer defined"); st = stab("prog", ST_MAILER, ST_FIND); if (st == NULL) syserr("No prog mailer defined"); else + { ProgMailer = st->s_mailer; + clrbitn(M_MUSER, ProgMailer->m_flags); + } st = stab("*file*", ST_MAILER, ST_FIND); if (st == NULL) syserr("No *file* mailer defined"); else + { FileMailer = st->s_mailer; + clrbitn(M_MUSER, FileMailer->m_flags); + } st = stab("*include*", ST_MAILER, ST_FIND); if (st == NULL) @@ -792,6 +882,39 @@ main(argc, argv, envp) else InclMailer = st->s_mailer; + if (ConfigLevel < 6) + { + /* heuristic tweaking of local mailer for back compat */ + if (LocalMailer != NULL) + { + setbitn(M_ALIASABLE, LocalMailer->m_flags); + setbitn(M_HASPWENT, LocalMailer->m_flags); + setbitn(M_TRYRULESET5, LocalMailer->m_flags); + setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); + setbitn(M_CHECKPROG, LocalMailer->m_flags); + setbitn(M_CHECKFILE, LocalMailer->m_flags); + setbitn(M_CHECKUDB, LocalMailer->m_flags); + } + if (ProgMailer != NULL) + setbitn(M_RUNASRCPT, ProgMailer->m_flags); + if (FileMailer != NULL) + setbitn(M_RUNASRCPT, FileMailer->m_flags); + + /* propogate some envariables into children */ + setuserenv("ISP", NULL); + setuserenv("SYSTYPE", NULL); + } + + /* MIME Content-Types that cannot be transfer encoded */ + setclass('n', "multipart/signed"); + + /* MIME message/* subtypes that can be treated as messages */ + setclass('s', "rfc822"); + + /* MIME Content-Transfer-Encodings that can be encoded */ + setclass('e', "7bit"); + setclass('e', "8bit"); + setclass('e', "binary"); /* operate in queue directory */ if (OpMode != MD_TEST && chdir(QueueDir) < 0) @@ -800,14 +923,32 @@ main(argc, argv, envp) ExitStat = EX_SOFTWARE; } +# ifdef QUEUE + if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) + { + struct stat stbuf; + + /* check to see if we own the queue directory */ + if (stat(".", &stbuf) < 0) + syserr("main: cannot stat %s", QueueDir); + if (stbuf.st_uid != RealUid) + { + /* nope, really a botch */ + usrerr("You do not have permission to process the queue"); + exit (EX_NOPERM); + } + } +# endif /* QUEUE */ + /* if we've had errors so far, exit now */ if (ExitStat != EX_OK && OpMode != MD_TEST) { + endpwent(); setuid(RealUid); exit(ExitStat); } -#ifdef XDEBUG +#if XDEBUG checkfd012("before main() initmaps"); #endif @@ -822,6 +963,7 @@ main(argc, argv, envp) #ifdef QUEUE dropenvelope(CurEnv); printqueue(); + endpwent(); setuid(RealUid); exit(EX_OK); #else /* QUEUE */ @@ -832,10 +974,12 @@ main(argc, argv, envp) case MD_INITALIAS: /* initialize alias database */ initmaps(TRUE, CurEnv); + endpwent(); setuid(RealUid); exit(EX_OK); case MD_DAEMON: + case MD_SMTP: /* don't open alias database -- done in srvrsmtp */ break; @@ -848,35 +992,12 @@ main(argc, argv, envp) if (tTd(0, 15)) { /* print configuration table (or at least part of it) */ - printrules(); + if (tTd(0, 90)) + printrules(); for (i = 0; i < MAXMAILERS; i++) { - register struct mailer *m = Mailer[i]; - int j; - - if (m == NULL) - continue; - printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name, - m->m_mailer, m->m_se_rwset, m->m_sh_rwset, - m->m_re_rwset, m->m_rh_rwset, m->m_maxsize); - for (j = '\0'; j <= '\177'; j++) - if (bitnset(j, m->m_flags)) - (void) putchar(j); - printf(" E="); - xputs(m->m_eol); - if (m->m_argv != NULL) - { - char **a = m->m_argv; - - printf(" A="); - while (*a != NULL) - { - if (a != m->m_argv) - printf(" "); - xputs(*a++); - } - } - printf("\n"); + if (Mailer[i] != NULL) + printmailer(Mailer[i]); } } @@ -894,6 +1015,7 @@ main(argc, argv, envp) if (OpMode == MD_TEST) { char buf[MAXLINE]; + void intindebug(); if (isatty(fileno(stdin))) Verbose = TRUE; @@ -903,69 +1025,24 @@ main(argc, argv, envp) printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); printf("Enter <ruleset> <address>\n"); } + if (setjmp(TopFrame) > 0) + printf("\n"); + (void) setsignal(SIGINT, intindebug); for (;;) { - register char **pvp; - char *q; - auto char *delimptr; - extern bool invalidaddr(); - extern char *crackaddr(); + extern void testmodeline __P((char *, ENVELOPE *)); if (Verbose) printf("> "); (void) fflush(stdout); if (fgets(buf, sizeof buf, stdin) == NULL) finis(); + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; if (!Verbose) - printf("> %s", buf); - switch (buf[0]) - { - case '#': - continue; - -#ifdef MAYBENEXTRELEASE - case 'C': /* try crackaddr */ - q = crackaddr(&buf[1]); - xputs(q); - printf("\n"); - continue; -#endif - } - - for (p = buf; isascii(*p) && isspace(*p); p++) - continue; - q = p; - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - if (*p == '\0') - { - printf("No address!\n"); - continue; - } - *p = '\0'; - if (invalidaddr(p + 1, NULL)) - continue; - do - { - char pvpbuf[PSBUFSIZE]; - - pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, - &delimptr); - if (pvp == NULL) - continue; - p = q; - while (*p != '\0') - { - int stat; - - stat = rewrite(pvp, atoi(p), 0, CurEnv); - if (stat != EX_OK) - printf("== Ruleset %s status %d\n", - p, stat); - while (*p != '\0' && *p++ != ',') - continue; - } - } while (*(p = delimptr) != '\0'); + printf("> %s\n", buf); + testmodeline(buf, CurEnv); } } @@ -976,6 +1053,7 @@ main(argc, argv, envp) if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) { + (void) unsetenv("HOSTALIASES"); runqueue(FALSE); finis(); } @@ -994,7 +1072,7 @@ main(argc, argv, envp) { char dtype[200]; - if (!tTd(0, 1)) + if (!tTd(99, 100)) { /* put us in background */ i = fork(); @@ -1066,11 +1144,12 @@ main(argc, argv, envp) { CurEnv->e_sendmode = SM_VERIFY; CurEnv->e_errormode = EM_QUIET; + PostMasterCopy = NULL; } else { /* interactive -- all errors are global */ - CurEnv->e_flags |= EF_GLOBALERRS; + CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER; } /* @@ -1078,6 +1157,9 @@ main(argc, argv, envp) */ initsys(CurEnv); + if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't')) + auth_warning(CurEnv, "%s set sender to %s using -%c", + RealUserName, from, warn_f_flag); setsender(from, CurEnv, NULL, FALSE); if (macvalue('s', CurEnv) == NULL) define('s', RealHostName, CurEnv); @@ -1089,7 +1171,7 @@ main(argc, argv, envp) /* collect body for UUCP return */ if (OpMode != MD_VERIFY) - collect(FALSE, FALSE, CurEnv); + collect(InChannel, FALSE, FALSE, NULL, CurEnv); finis(); } @@ -1111,7 +1193,7 @@ main(argc, argv, envp) if (OpMode != MD_VERIFY || GrabTo) { CurEnv->e_flags |= EF_GLOBALERRS; - collect(FALSE, FALSE, CurEnv); + collect(InChannel, FALSE, FALSE, NULL, CurEnv); } errno = 0; @@ -1139,6 +1221,15 @@ main(argc, argv, envp) finis(); } + + +void +intindebug() +{ + longjmp(TopFrame, 1); +} + + /* ** FINIS -- Clean up and exit. ** @@ -1152,12 +1243,18 @@ main(argc, argv, envp) ** exits sendmail */ +void finis() { if (tTd(2, 1)) - printf("\n====finis: stat %d e_flags %o, e_id=%s\n", - ExitStat, CurEnv->e_flags, + { + extern void printenvflags(); + + printf("\n====finis: stat %d e_id=%s e_flags=", + ExitStat, CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); + printenvflags(CurEnv); + } if (tTd(2, 9)) printopenfds(FALSE); @@ -1178,10 +1275,11 @@ finis() if (LogLevel > 78) syslog(LOG_DEBUG, "finis, pid=%d", getpid()); # endif /* LOG */ - if (ExitStat == EX_TEMPFAIL) + if (ExitStat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) ExitStat = EX_OK; /* reset uid for process accounting */ + endpwent(); setuid(RealUid); exit(ExitStat); @@ -1212,6 +1310,7 @@ intsig() #endif /* reset uid for process accounting */ + endpwent(); setuid(RealUid); exit(EX_OK); @@ -1255,12 +1354,18 @@ struct metamac MetaMacros[] = '\0' }; +#define MACBINDING(name, mid) \ + stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \ + MacroName[mid] = name; + +void initmacros(e) register ENVELOPE *e; { register struct metamac *m; - char buf[5]; register int c; + char buf[5]; + extern char *MacroName[256]; for (m = MetaMacros; m->metaname != '\0'; m++) { @@ -1277,11 +1382,11 @@ initmacros(e) } /* set defaults for some macros sendmail will use later */ - define('e', "\201j Sendmail \201v ready at \201b", e); - define('l', "From \201g \201d", e); define('n', "MAILER-DAEMON", e); - define('o', ".:@[]", e); - define('q', "<\201g>", e); + + /* set up external names for some internal macros */ + MACBINDING("opMode", MID_OPMODE); + /*XXX should probably add equivalents for all short macros here XXX*/ } /* ** DISCONNECT -- remove our connection with any foreground process @@ -1303,6 +1408,7 @@ initmacros(e) ** the controlling tty. */ +void disconnect(droplev, e) int droplev; register ENVELOPE *e; @@ -1312,14 +1418,13 @@ disconnect(droplev, e) if (tTd(52, 1)) printf("disconnect: In %d Out %d, e=%x\n", fileno(InChannel), fileno(OutChannel), e); - if (tTd(52, 5)) + if (tTd(52, 100)) { printf("don't\n"); return; } /* be sure we don't get nasty signals */ - (void) setsignal(SIGHUP, SIG_IGN); (void) setsignal(SIGINT, SIG_IGN); (void) setsignal(SIGQUIT, SIG_IGN); @@ -1363,7 +1468,7 @@ disconnect(droplev, e) errno = 0; } -#ifdef XDEBUG +#if XDEBUG checkfd012("disconnect"); #endif @@ -1391,7 +1496,11 @@ obsolete(argv) /* skip over options that do have a value */ op = strchr(OPTIONS, ap[1]); if (op != NULL && *++op == ':' && ap[2] == '\0' && - ap[1] != 'd' && argv[1] != NULL && argv[1][0] != '-') + ap[1] != 'd' && +#if defined(sony_news) + ap[1] != 'E' && ap[1] != 'J' && +#endif + argv[1] != NULL && argv[1][0] != '-') { argv++; continue; @@ -1414,6 +1523,16 @@ obsolete(argv) /* if -d doesn't have an argument, use 0-99.1 */ if (ap[1] == 'd' && ap[2] == '\0') *argv = "-d0-99.1"; + +# if defined(sony_news) + /* if -E doesn't have an argument, use -EC */ + if (ap[1] == 'E' && ap[2] == '\0') + *argv = "-EC"; + + /* if -J doesn't have an argument, use -JJ */ + if (ap[1] == 'J' && ap[2] == '\0') + *argv = "-JJ"; +# endif } } /* @@ -1445,7 +1564,7 @@ auth_warning(e, msg, va_alist) { register char *p; static char hostbuf[48]; - extern char **myhostname(); + extern struct hostent *myhostname(); if (hostbuf[0] == '\0') (void) myhostname(hostbuf, sizeof hostbuf); @@ -1453,10 +1572,67 @@ auth_warning(e, msg, va_alist) (void) sprintf(buf, "%s: ", hostbuf); p = &buf[strlen(buf)]; VA_START(msg); - vsprintf(p, msg, ap); + vsnprintf(p, sizeof buf - (p - buf), msg, ap); VA_END; - addheader("X-Authentication-Warning", buf, e); + addheader("X-Authentication-Warning", buf, &e->e_header); +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_INFO, "%s: Authentication-Warning: %.400s", + e->e_id == NULL ? "[NOQUEUE]" : e->e_id, buf); +#endif + } +} +/* +** SETUSERENV -- set an environment in the propogated environment +** +** Parameters: +** envar -- the name of the environment variable. +** value -- the value to which it should be set. If +** null, this is extracted from the incoming +** environment. If that is not set, the call +** to setuserenv is ignored. +** +** Returns: +** none. +*/ + +void +setuserenv(envar, value) + const char *envar; + const char *value; +{ + int i; + char **evp = UserEnviron; + char *p; + + if (value == NULL) + { + value = getenv(envar); + if (value == NULL) + return; + } + + i = strlen(envar); + p = (char *) xalloc(strlen(value) + i + 2); + strcpy(p, envar); + p[i++] = '='; + strcpy(&p[i], value); + + while (*evp != NULL && strncmp(*evp, p, i) != 0) + evp++; + if (*evp != NULL) + { + *evp++ = p; + } + else if (evp < &UserEnviron[MAXUSERENVIRON]) + { + *evp++ = p; + *evp = NULL; } + + /* make sure it is in our environment as well */ + if (putenv(p) < 0) + syserr("setuserenv: putenv(%s) failed", p); } /* ** DUMPSTATE -- dump state @@ -1470,17 +1646,16 @@ dumpstate(when) { #ifdef LOG register char *j = macvalue('j', CurEnv); - register STAB *s; syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---", when, j == NULL ? "<NULL>" : j); if (j != NULL) { - s = stab(j, ST_CLASS, ST_FIND); - if (s == NULL || !bitnset('w', s->s_class)) + if (!wordinclass(j, 'w')) syslog(LOG_DEBUG, "*** $j not in $=w ***"); } + syslog(LOG_DEBUG, "CurChildren = %d", CurChildren); syslog(LOG_DEBUG, "--- open file descriptors: ---"); printopenfds(TRUE); syslog(LOG_DEBUG, "--- connection cache: ---"); @@ -1508,3 +1683,431 @@ sigusr1() { dumpstate("user signal"); } + + +void +sighup() +{ +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]); +#endif + releasesignal(SIGHUP); + execv(SaveArgv[0], (ARGV_T) SaveArgv); +#ifdef LOG + if (LogLevel > 0) + syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]); +#endif + exit(EX_OSFILE); +} +/* +** TESTMODELINE -- process a test mode input line +** +** Parameters: +** line -- the input line. +** e -- the current environment. +** Syntax: +** # a comment +** .X process X as a configuration line +** =X dump a configuration item (such as mailers) +** $X dump a macro or class +** /X try an activity +** X normal process through rule set X +*/ + +void +testmodeline(line, e) + char *line; + ENVELOPE *e; +{ + register char *p; + char *q; + auto char *delimptr; + int mid; + int i, rs; + STAB *map; + char **s; + struct rewrite *rw; + 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 *)); + + switch (line[0]) + { + case '#': + case 0: + return; + + case '?': + help("-bt"); + return; + + case '.': /* config-style settings */ + switch (line[1]) + { + case 'D': + mid = macid(&line[2], &delimptr); + if (mid == '\0') + return; + translate_dollars(delimptr); + define(mid, newstr(delimptr), e); + break; + + case 'C': + if (line[2] == '\0') /* not to call syserr() */ + return; + + mid = macid(&line[2], &delimptr); + if (mid == '\0') + return; + translate_dollars(delimptr); + expand(delimptr, exbuf, sizeof exbuf, e); + p = exbuf; + while (*p != '\0') + { + register char *wd; + char delim; + + while (*p != '\0' && isascii(*p) && isspace(*p)) + p++; + wd = p; + while (*p != '\0' && !(isascii(*p) && isspace(*p))) + p++; + delim = *p; + *p = '\0'; + if (wd[0] != '\0') + setclass(mid, wd); + *p = delim; + } + break; + + case '\0': + printf("Usage: .[DC]macro value(s)\n"); + break; + + default: + printf("Unknown \".\" command %s\n", line); + break; + } + return; + + case '=': /* config-style settings */ + switch (line[1]) + { + case 'S': /* dump rule set */ + rs = strtorwset(&line[2], NULL, ST_FIND); + if (rs < 0) + return; + rw = RewriteRules[rs]; + if (rw == NULL) + return; + do + { + putchar('R'); + s = rw->r_lhs; + while (*s != NULL) + { + xputs(*s++); + putchar(' '); + } + putchar('\t'); + putchar('\t'); + s = rw->r_rhs; + while (*s != NULL) + { + xputs(*s++); + putchar(' '); + } + putchar('\n'); + } while (rw = rw->r_next); + break; + + case 'M': + for (i = 0; i < MAXMAILERS; i++) + { + if (Mailer[i] != NULL) + printmailer(Mailer[i]); + } + break; + + case '\0': + printf("Usage: =Sruleset or =M\n"); + break; + + default: + printf("Unknown \"=\" command %s\n", line); + break; + } + return; + + case '-': /* set command-line-like opts */ + switch (line[1]) + { + case 'd': + tTflag(&line[2]); + break; + + case '\0': + printf("Usage: -d{debug arguments}\n"); + break; + + default: + printf("Unknown \"-\" command %s\n", line); + break; + } + return; + + case '$': + if (line[1] == '=') + { + mid = macid(&line[2], NULL); + if (mid != '\0') + stabapply(dump_class, mid); + return; + } + mid = macid(&line[1], NULL); + if (mid == '\0') + return; + p = macvalue(mid, e); + if (p == NULL) + printf("Undefined\n"); + else + { + xputs(p); + printf("\n"); + } + return; + + case '/': /* miscellaneous commands */ + p = &line[strlen(line)]; + while (--p >= line && isascii(*p) && isspace(*p)) + *p = '\0'; + p = strpbrk(line, " \t"); + if (p != NULL) + { + while (isascii(*p) && isspace(*p)) + *p++ = '\0'; + } + else + p = ""; + if (line[1] == '\0') + { + printf("Usage: /[canon|map|mx|parse|try|tryflags]\n"); + return; + } + if (strcasecmp(&line[1], "mx") == 0) + { +#if NAMED_BIND + /* look up MX records */ + int nmx; + auto int rcode; + char *mxhosts[MAXMXHOSTS + 1]; + + if (*p == '\0') + { + printf("Usage: /mx address\n"); + return; + } + nmx = getmxrr(p, mxhosts, 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 + printf("No MX code compiled in\n"); +#endif + } + else if (strcasecmp(&line[1], "canon") == 0) + { + auto int rcode = EX_OK; + char host[MAXHOSTNAMELEN]; + + if (*p == '\0') + { + printf("Usage: /canon address\n"); + return; + } + strcpy(host, p); + getcanonname(host, sizeof(host), HasWildcardMX, &rcode); + printf("getcanonname(%s) returns %s (%d)\n", + p, host, rcode); + } + else if (strcasecmp(&line[1], "map") == 0) + { + auto int rcode = EX_OK; + + if (*p == '\0') + { + printf("Usage: /map mapname key\n"); + return; + } + for (q = p; *q != '\0' && !isspace(*q); q++) + continue; + if (*q == '\0') + { + printf("No key specified\n"); + return; + } + *q++ = '\0'; + map = stab(p, ST_MAP, ST_FIND); + if (map == NULL) + { + printf("Map named \"%s\" not found\n", p); + return; + } + printf("map_lookup: %s (%s) ", p, q); + p = (*map->s_map.map_class->map_lookup) + (&map->s_map, q, NULL, &rcode); + if (p == NULL) + printf("no match (%d)\n", rcode); + else + printf("returns %s (%d)\n", p, rcode); + } + else if (strcasecmp(&line[1], "try") == 0) + { + MAILER *m; + STAB *s; + auto int rcode = EX_OK; + + q = strpbrk(p, " \t"); + if (q != NULL) + { + while (isascii(*q) && isspace(*q)) + *q++ = '\0'; + } + if (q == NULL || *q == '\0') + { + printf("Usage: /try mailer address\n"); + return; + } + s = stab(p, ST_MAILER, ST_FIND); + if (s == NULL) + { + printf("Unknown mailer %s\n", p); + return; + } + m = s->s_mailer; + printf("Trying %s %s address %s for mailer %s\n", + bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", + bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient", + q, p); + p = remotename(q, m, tryflags, &rcode, CurEnv); + printf("Rcode = %d, addr = %s\n", + rcode, p == NULL ? "<NULL>" : p); + } + else if (strcasecmp(&line[1], "tryflags") == 0) + { + if (*p == '\0') + { + printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); + return; + } + for (; *p != '\0'; p++) + { + switch (*p) + { + case 'H': + case 'h': + tryflags |= RF_HEADERADDR; + break; + + case 'E': + case 'e': + tryflags &= ~RF_HEADERADDR; + break; + + case 'S': + case 's': + tryflags |= RF_SENDERADDR; + break; + + case 'R': + case 'r': + tryflags &= ~RF_SENDERADDR; + break; + } + } + } + else if (strcasecmp(&line[1], "parse") == 0) + { + if (*p == '\0') + { + printf("Usage: /parse address\n"); + return; + } + q = crackaddr(p); + printf("Cracked address = "); + xputs(q); + printf("\nParsing %s %s address\n", + bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", + bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient"); + if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL) + printf("Cannot parse\n"); + else if (a.q_host != NULL && a.q_host[0] != '\0') + printf("mailer %s, host %s, user %s\n", + a.q_mailer->m_name, a.q_host, a.q_user); + else + printf("mailer %s, user %s\n", + a.q_mailer->m_name, a.q_user); + } + else + { + printf("Unknown \"/\" command %s\n", line); + } + return; + } + + for (p = line; isascii(*p) && isspace(*p); p++) + continue; + q = p; + while (*p != '\0' && !(isascii(*p) && isspace(*p))) + p++; + if (*p == '\0') + { + printf("No address!\n"); + return; + } + *p = '\0'; + if (invalidaddr(p + 1, NULL)) + return; + do + { + register char **pvp; + char pvpbuf[PSBUFSIZE]; + + pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, + &delimptr, NULL); + if (pvp == NULL) + continue; + p = q; + while (*p != '\0') + { + int stat; + int rs = strtorwset(p, NULL, ST_FIND); + + if (rs < 0) + break; + stat = rewrite(pvp, rs, 0, e); + if (stat != EX_OK) + printf("== Ruleset %s (%d) status %d\n", + p, rs, stat); + while (*p != '\0' && *p++ != ',') + continue; + } + } while (*(p = delimptr) != '\0'); +} + + +void +dump_class(s, id) + register STAB *s; + int id; +{ + if (s->s_type != ST_CLASS) + return; + if (bitnset(id & 0xff, s->s_class)) + printf("%s\n", s->s_name); +} |
