2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
14 static char copyright[] =
15 "@(#) Copyright (c) 1998 Sendmail, Inc. All rights reserved.\n\
16 Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\
17 Copyright (c) 1988, 1993\n\
18 The Regents of the University of California. All rights reserved.\n";
22 static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998";
28 #include <arpa/inet.h>
35 ** SENDMAIL -- Post mail to a set of destinations.
37 ** This is the basic mail router. All user mail programs should
38 ** call this routine to actually deliver mail. Sendmail in
39 ** turn calls a bunch of mail servers that do the real work of
40 ** delivering the mail.
42 ** Sendmail is driven by settings read in from /etc/sendmail.cf
43 ** (read by readcf.c).
46 ** /usr/lib/sendmail [flags] addr ...
48 ** See the associated documentation for details.
51 ** Eric Allman, UCB/INGRES (until 10/81).
52 ** Britton-Lee, Inc., purveyors of fine
53 ** database computers (11/81 - 10/88).
54 ** International Computer Science Institute
56 ** UCB/Mammoth Project (10/89 - 7/95).
57 ** InReference, Inc. (8/95 - 1/97).
58 ** Sendmail, Inc. (1/98 - present).
59 ** The support of the my employers is gratefully acknowledged.
60 ** Few of them (Britton-Lee in particular) have had
61 ** anything to gain from my involvement in this project.
65 int NextMailer; /* "free" index into Mailer struct */
66 char *FullName; /* sender's full name */
67 ENVELOPE BlankEnvelope; /* a "blank" envelope */
68 ENVELOPE MainEnvelope; /* the envelope around the basic letter */
69 ADDRESS NullAddress = /* a null address */
71 char *CommandLineArgs; /* command line args for pid file */
72 bool Warn_Q_option = FALSE; /* warn about Q option use */
73 char **SaveArgv; /* argument vector for re-execing */
74 int MissingFds = 0; /* bit map of fds missing on startup */
77 GIDSET_T InitialGidSet[NGROUPS_MAX];
80 static void obsolete __P((char **));
81 extern void printmailer __P((MAILER *));
82 extern void tTflag __P((char *));
85 ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR
86 #endif /* DAEMON && !SMTP */
88 ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR
89 #endif /* DAEMON && !SMTP */
91 #define MAXCONFIGLEVEL 8 /* highest config version level known */
94 main(argc, argv, envp)
101 extern char Version[];
106 bool queuemode = FALSE; /* process queue requests */
108 bool warn_C_flag = FALSE;
109 char warn_f_flag = '\0';
110 bool run_in_foreground = FALSE; /* -bD mode */
111 static bool reenter = FALSE;
114 char *nullserver = NULL;
116 char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
117 static char rnamebuf[MAXNAME]; /* holds RealUserName */
118 char *emptyenviron[1];
120 extern int DtableSize;
124 extern char **environ;
125 extern time_t convtime __P((char *, char));
126 extern SIGFUNC_DECL intsig __P((int));
127 extern struct hostent *myhostname __P((char *, int));
128 extern char *getauthinfo __P((int, bool *));
129 extern char *getcfname __P((void));
130 extern SIGFUNC_DECL sigusr1 __P((int));
131 extern SIGFUNC_DECL sighup __P((int));
132 extern SIGFUNC_DECL quiesce __P((int));
133 extern void initmacros __P((ENVELOPE *));
134 extern void init_md __P((int, char **));
135 extern int getdtsize __P((void));
136 extern void tTsetup __P((u_char *, int, char *));
137 extern void setdefaults __P((ENVELOPE *));
138 extern void initsetproctitle __P((int, char **, char **));
139 extern void init_vendor_macros __P((ENVELOPE *));
140 extern void load_if_names __P((void));
141 extern void vendor_pre_defaults __P((ENVELOPE *));
142 extern void vendor_post_defaults __P((ENVELOPE *));
143 extern void readcf __P((char *, bool, ENVELOPE *));
144 extern void printqueue __P((void));
145 extern void sendtoargv __P((char **, ENVELOPE *));
146 extern void resetlimits __P((void));
148 extern void unsetenv __P((char *));
152 ** Check to see if we reentered.
153 ** This would normally happen if e_putheader or e_putbody
154 ** were NULL when invoked.
159 syserr("main: reentered!");
164 /* avoid null pointer dereferences */
165 TermEscape.te_rv_on = TermEscape.te_rv_off = "";
167 /* do machine-dependent initializations */
170 /* in 4.4BSD, the table can be huge; impose a reasonable limit */
171 DtableSize = getdtsize();
172 if (DtableSize > 256)
176 ** Be sure we have enough file descriptors.
177 ** But also be sure that 0, 1, & 2 are open.
180 fill_fd(STDIN_FILENO, NULL);
181 fill_fd(STDOUT_FILENO, NULL);
182 fill_fd(STDERR_FILENO, NULL);
187 if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
194 openlog("sendmail", LOG_PID, LOG_MAIL);
196 openlog("sendmail", LOG_PID);
205 if (bitset(1 << STDIN_FILENO, MissingFds))
206 strcat(mbuf, ", stdin");
207 if (bitset(1 << STDOUT_FILENO, MissingFds))
208 strcat(mbuf, ", stdout");
209 if (bitset(1 << STDERR_FILENO, MissingFds))
210 strcat(mbuf, ", stderr");
211 syserr("File descriptors missing on startup: %s", &mbuf[2]);
214 /* reset status from syserr() calls for missing file descriptors */
219 checkfd012("after openlog");
222 tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
225 /* save initial group set for future checks */
226 i = getgroups(NGROUPS_MAX, InitialGidSet);
228 InitialGidSet[0] = (GID_T) -1;
229 while (i < NGROUPS_MAX)
230 InitialGidSet[i++] = InitialGidSet[0];
233 /* drop group id privileges (RunAsUser not yet set) */
234 (void) drop_privileges(FALSE);
237 /* arrange to dump state on user-1 signal */
238 setsignal(SIGUSR1, sigusr1);
241 /* initialize for setproctitle */
242 initsetproctitle(argc, argv, envp);
244 /* Handle any non-getoptable constructions. */
248 ** Do a quick prescan of the argument list.
251 #if defined(__osf__) || defined(_AIX3)
252 # define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x"
254 #if defined(sony_news)
255 # define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
258 # define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:"
261 while ((j = getopt(argc, argv, OPTIONS)) != -1)
266 /* hack attack -- see if should use ANSI mode */
267 if (strcmp(optarg, "ANSI") == 0)
269 TermEscape.te_rv_on = "\033[7m";
270 TermEscape.te_rv_off = "\033[0m";
274 setbuf(stdout, (char *) NULL);
280 /* set up the blank envelope */
281 BlankEnvelope.e_puthdr = putheader;
282 BlankEnvelope.e_putbody = putbody;
283 BlankEnvelope.e_xfp = NULL;
284 STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
285 CurEnv = &BlankEnvelope;
286 STRUCTCOPY(NullAddress, MainEnvelope.e_from);
289 ** Set default values for variables.
290 ** These cannot be in initialized data space.
293 setdefaults(&BlankEnvelope);
298 pw = sm_getpwuid(RealUid);
300 (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
302 (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", RealUid);
303 RealUserName = rnamebuf;
307 printf("Version %s\n", Version);
312 ** if running non-setuid binary as non-root, pretend
313 ** we are the RunAsUid
315 if (RealUid != 0 && geteuid() == RealUid)
318 printf("Non-setuid binary: RunAsUid = RealUid = %d\n",
322 else if (geteuid() != 0)
323 RunAsUid = geteuid();
325 if (RealUid != 0 && getegid() == RealGid)
330 printf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
331 (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
332 printf("main: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
335 /* save command line arguments */
337 for (av = argv; *av != NULL; )
338 i += strlen(*av++) + 1;
339 SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
340 CommandLineArgs = xalloc(i);
342 for (av = argv, i = 0; *av != NULL; )
344 SaveArgv[i++] = newstr(*av);
355 extern char *CompileOptions[];
357 printf("Version %s\n Compiled with:", Version);
362 if (ll + strlen(*av) > 63)
375 ll += strlen(*av++) + 1;
382 extern char *OsCompileOptions[];
384 printf(" OS Defines:");
385 av = OsCompileOptions;
389 if (ll + strlen(*av) > 63)
402 ll += strlen(*av++) + 1;
406 printf("Kernel symbols:\t%s\n", _PATH_UNIX);
408 printf(" Def Conf file:\t%s\n", getcfname());
409 printf(" Pid file:\t%s\n", PidFile);
415 /* clear sendmail's environment */
416 ExternalEnviron = environ;
417 emptyenviron[0] = NULL;
418 environ = emptyenviron;
421 ** restore any original TZ setting until TimeZoneSpec has been
422 ** determined - or early log messages may get bogus time stamps
424 if ((p = getextenv("TZ")) != NULL)
429 tzlen = strlen(p) + 4;
431 snprintf(tz, tzlen, "TZ=%s", p);
435 /* prime the child environment */
436 setuserenv("AGENT", "sendmail");
438 if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
439 (void) setsignal(SIGINT, intsig);
440 (void) setsignal(SIGTERM, intsig);
441 (void) setsignal(SIGPIPE, SIG_IGN);
442 OldUmask = umask(022);
444 FullName = getextenv("NAME");
447 ** Initialize name server if it is going to be used.
451 if (!bitset(RES_INIT, _res.options))
454 _res.options |= RES_DEBUG;
456 _res.options &= ~RES_DEBUG;
457 # ifdef RES_NOALIASES
458 _res.options |= RES_NOALIASES;
465 /* initialize some macros, etc. */
467 init_vendor_macros(CurEnv);
470 define('v', Version, CurEnv);
473 hp = myhostname(jbuf, sizeof jbuf);
476 struct utsname utsname;
479 printf("canonical name: %s\n", jbuf);
480 define('w', newstr(jbuf), CurEnv); /* must be new string */
481 define('j', newstr(jbuf), CurEnv);
484 p = strchr(jbuf, '.');
489 define('m', newstr(&p[1]), CurEnv);
491 while (p != NULL && strchr(&p[1], '.') != NULL)
495 printf("\ta.k.a.: %s\n", jbuf);
502 if (uname(&utsname) >= 0)
503 p = utsname.nodename;
507 printf("uname failed (%s)\n", errstring(errno));
512 printf(" UUCP nodename: %s\n", p);
514 define('k', p, CurEnv);
520 for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
523 printf("\ta.k.a.: %s\n", *av);
527 if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ)
529 for (i = 0; hp->h_addr_list[i] != NULL; i++)
533 snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
534 inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
536 printf("\ta.k.a.: %s\n", ipbuf);
537 setclass('w', ipbuf);
544 define('b', arpadate((char *) NULL), CurEnv);
546 QueueLimitRecipient = (QUEUE_CHAR *) NULL;
547 QueueLimitSender = (QUEUE_CHAR *) NULL;
548 QueueLimitId = (QUEUE_CHAR *) NULL;
555 p = strrchr(*av, '/');
558 if (strcmp(p, "newaliases") == 0)
559 OpMode = MD_INITALIAS;
560 else if (strcmp(p, "mailq") == 0)
562 else if (strcmp(p, "smtpd") == 0)
564 else if (strcmp(p, "hoststat") == 0)
565 OpMode = MD_HOSTSTAT;
566 else if (strcmp(p, "purgestat") == 0)
567 OpMode = MD_PURGESTAT;
570 while ((j = getopt(argc, argv, OPTIONS)) != -1)
574 case 'b': /* operations mode */
580 usrerr("Daemon mode not implemented");
586 usrerr("I don't speak SMTP");
603 usrerr("Frozen configurations unsupported");
608 usrerr("Invalid operation mode %c", j);
614 case 'B': /* body type */
615 CurEnv->e_bodytype = optarg;
618 case 'C': /* select configuration file (already done) */
622 (void) drop_privileges(TRUE);
626 case 'd': /* debugging -- already done */
629 case 'f': /* from address */
630 case 'r': /* obsolete -f flag */
633 usrerr("More than one \"from\" person");
637 from = newstr(denlstring(optarg, TRUE, TRUE));
638 if (strcmp(RealUserName, from) != 0)
642 case 'F': /* set full name */
643 FullName = newstr(optarg);
646 case 'h': /* hop count */
647 CurEnv->e_hopcount = strtol(optarg, &ep, 10);
650 usrerr("Bad hop count (%s)", optarg);
655 case 'n': /* don't alias */
659 case 'N': /* delivery status notifications */
660 DefaultNotify |= QHASNOTIFY;
661 if (strcasecmp(optarg, "never") == 0)
663 for (p = optarg; p != NULL; optarg = p)
668 if (strcasecmp(optarg, "success") == 0)
669 DefaultNotify |= QPINGONSUCCESS;
670 else if (strcasecmp(optarg, "failure") == 0)
671 DefaultNotify |= QPINGONFAILURE;
672 else if (strcasecmp(optarg, "delay") == 0)
673 DefaultNotify |= QPINGONDELAY;
676 usrerr("Invalid -N argument");
682 case 'o': /* set option */
683 setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
686 case 'O': /* set option (long form) */
687 setoption(' ', optarg, FALSE, TRUE, CurEnv);
690 case 'p': /* set protocol */
691 p = strchr(optarg, ':');
697 ep = xalloc(strlen(p) + 1);
698 cleanstrcpy(ep, p, MAXNAME);
699 define('s', ep, CurEnv);
704 ep = xalloc(strlen(optarg) + 1);
705 cleanstrcpy(ep, optarg, MAXNAME);
706 define('r', ep, CurEnv);
710 case 'q': /* run queue files at intervals */
717 if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
718 syserr("!Out of memory!!");
719 new->queue_match = newstr(&optarg[1]);
720 new->queue_next = QueueLimitId;
725 if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
726 syserr("!Out of memory!!");
727 new->queue_match = newstr(&optarg[1]);
728 new->queue_next = QueueLimitRecipient;
729 QueueLimitRecipient = new;
733 if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
734 syserr("!Out of memory!!");
735 new->queue_match = newstr(&optarg[1]);
736 new->queue_next = QueueLimitSender;
737 QueueLimitSender = new;
741 QueueIntvl = convtime(optarg, 'm');
745 usrerr("I don't know about queues");
750 case 'R': /* DSN RET: what to return */
751 if (bitset(EF_RET_PARAM, CurEnv->e_flags))
753 usrerr("Duplicate -R flag");
757 CurEnv->e_flags |= EF_RET_PARAM;
758 if (strcasecmp(optarg, "hdrs") == 0)
759 CurEnv->e_flags |= EF_NO_BODY_RETN;
760 else if (strcasecmp(optarg, "full") != 0)
762 usrerr("Invalid -R value");
767 case 't': /* read recipients from message */
771 case 'U': /* initial (user) submission */
772 UserSubmission = TRUE;
775 case 'V': /* DSN ENVID: set "original" envelope id */
776 if (!xtextok(optarg))
778 usrerr("Invalid syntax in -V flag");
782 CurEnv->e_envid = newstr(optarg);
785 case 'X': /* traffic log file */
786 (void) drop_privileges(TRUE);
787 TrafficLogFile = fopen(optarg, "a");
788 if (TrafficLogFile == NULL)
790 syserr("cannot open %s", optarg);
791 ExitStat = EX_CANTCREAT;
795 setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
797 setlinebuf(TrafficLogFile);
801 /* compatibility flags */
802 case 'c': /* connect to non-local mailers */
803 case 'i': /* don't let dot stop me */
804 case 'm': /* send to me too */
805 case 'T': /* set timeout interval */
806 case 'v': /* give blow-by-blow description */
807 setoption(j, "T", FALSE, TRUE, CurEnv);
810 case 'e': /* error message disposition */
811 case 'M': /* define macro */
812 setoption(j, optarg, FALSE, TRUE, CurEnv);
815 case 's': /* save From lines in headers */
816 setoption('f', "T", FALSE, TRUE, CurEnv);
820 case 'I': /* initialize alias DBM file */
821 OpMode = MD_INITALIAS;
825 # if defined(__osf__) || defined(_AIX3)
826 case 'x': /* random flag that OSF/1 & AIX mailx passes */
829 # if defined(sony_news)
831 case 'J': /* ignore flags for Japanese code conversion
832 impremented on Sony NEWS */
837 finis(TRUE, EX_USAGE);
844 ** Do basic initialization.
845 ** Read system control file.
846 ** Extract special fields for local use.
849 /* set up ${opMode} for use in config file */
855 define(MID_OPMODE, newstr(mbuf), CurEnv);
859 checkfd012("before readcf");
861 vendor_pre_defaults(CurEnv);
862 readcf(getcfname(), safecf, CurEnv);
863 ConfigFileRead = TRUE;
864 vendor_post_defaults(CurEnv);
866 /* Enforce use of local time (null string overrides this) */
867 if (TimeZoneSpec == NULL)
869 else if (TimeZoneSpec[0] != '\0')
870 setuserenv("TZ", TimeZoneSpec);
872 setuserenv("TZ", NULL);
875 /* avoid denial-of-service attacks */
878 if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
880 /* drop privileges -- daemon mode done after socket/bind */
881 (void) drop_privileges(FALSE);
885 ** Find our real host name for future logging.
888 p = getauthinfo(STDIN_FILENO, &forged);
889 define('_', p, CurEnv);
891 /* suppress error printing if errors mailed back or whatever */
892 if (CurEnv->e_errormode != EM_PRINT)
895 /* set up the $=m class now, after .cf has a chance to redefine $m */
896 expand("\201m", jbuf, sizeof jbuf, CurEnv);
899 /* probe interfaces and locate any additional names */
900 if (!DontProbeInterfaces)
905 printf("\n============ SYSTEM IDENTITY (after readcf) ============");
906 printf("\n (short domain name) $w = ");
907 xputs(macvalue('w', CurEnv));
908 printf("\n (canonical domain name) $j = ");
909 xputs(macvalue('j', CurEnv));
910 printf("\n (subdomain name) $m = ");
911 xputs(macvalue('m', CurEnv));
912 printf("\n (node name) $k = ");
913 xputs(macvalue('k', CurEnv));
914 printf("\n========================================================\n\n");
918 ** Do more command line checking -- these are things that
919 ** have to modify the results of reading the config file.
922 /* process authorization warnings from command line */
924 auth_warning(CurEnv, "Processed by %s with -C %s",
925 RealUserName, ConfFile);
927 auth_warning(CurEnv, "Processed from queue %s", QueueDir);
929 /* check body type for legality */
930 if (CurEnv->e_bodytype == NULL)
932 else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
933 SevenBitInput = TRUE;
934 else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
935 SevenBitInput = FALSE;
938 usrerr("Illegal body type %s", CurEnv->e_bodytype);
939 CurEnv->e_bodytype = NULL;
942 /* tweak default DSN notifications */
943 if (DefaultNotify == 0)
944 DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
946 /* be sure we don't pick up bogus HOSTALIASES environment variable */
947 if (queuemode && RealUid != 0)
948 (void) unsetenv("HOSTALIASES");
950 /* check for sane configuration level */
951 if (ConfigLevel > MAXCONFIGLEVEL)
953 syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
954 ConfigLevel, Version, MAXCONFIGLEVEL);
957 /* need MCI cache to have persistence */
958 if (HostStatDir != NULL && MaxMciCache == 0)
961 printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
964 /* need HostStatusDir in order to have SingleThreadDelivery */
965 if (SingleThreadDelivery && HostStatDir == NULL)
967 SingleThreadDelivery = FALSE;
968 printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
971 /* check for permissions */
972 if ((OpMode == MD_DAEMON ||
973 OpMode == MD_FGDAEMON ||
974 OpMode == MD_PURGESTAT) &&
976 RealUid != TrustedUid)
979 sm_syslog(LOG_ALERT, NOQID,
980 "user %d attempted to %s",
982 OpMode != MD_PURGESTAT ? "run daemon"
983 : "purge host status");
984 usrerr("Permission denied");
985 finis(FALSE, EX_USAGE);
989 BlankEnvelope.e_flags |= EF_METOO;
994 /* don't have persistent host status in test mode */
998 CurEnv->e_errormode = EM_PRINT;
1003 CurEnv->e_errormode = EM_PRINT;
1005 /* arrange to exit cleanly on hangup signal */
1006 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1007 setsignal(SIGHUP, intsig);
1011 run_in_foreground = TRUE;
1013 /* fall through ... */
1016 vendor_daemon_setup(CurEnv);
1018 /* remove things that don't make sense in daemon mode */
1022 /* arrange to restart on hangup signal */
1023 if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1024 sm_syslog(LOG_WARNING, NOQID,
1025 "daemon invoked without full pathname; kill -1 won't work");
1026 setsignal(SIGHUP, sighup);
1028 /* workaround: can't seem to release the signal in the parent */
1029 releasesignal(SIGHUP);
1034 CurEnv->e_errormode = EM_PRINT;
1036 /* fall through... */
1039 /* to handle sendmail -bp -qSfoobar properly */
1041 /* fall through... */
1044 /* arrange to exit cleanly on hangup signal */
1045 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1046 setsignal(SIGHUP, intsig);
1050 /* special considerations for FullName */
1051 if (FullName != NULL)
1054 extern bool rfc822_string __P((char *));
1056 /* full names can't have newlines */
1057 if (strchr(FullName, '\n') != NULL)
1059 FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
1061 /* check for characters that may have to be quoted */
1062 if (!rfc822_string(FullName))
1064 extern char *addquotes __P((char *));
1067 ** Quote a full name with special characters
1068 ** as a comment so crackaddr() doesn't destroy
1069 ** the name portion of the address.
1071 FullName = addquotes(FullName);
1077 /* do heuristic mode adjustment */
1080 /* turn off noconnect option */
1081 setoption('c', "F", TRUE, FALSE, CurEnv);
1083 /* turn on interactive delivery */
1084 setoption('d', "", TRUE, FALSE, CurEnv);
1088 /* check for vendor mismatch */
1089 if (VendorCode != VENDOR_CODE)
1091 extern char *getvendor __P((int));
1093 message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1094 getvendor(VENDOR_CODE), getvendor(VendorCode));
1098 /* check for out of date configuration level */
1099 if (ConfigLevel < MAXCONFIGLEVEL)
1101 message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1102 Version, MAXCONFIGLEVEL, ConfigLevel);
1105 if (ConfigLevel < 3)
1110 /* set options that were previous macros */
1111 if (SmtpGreeting == NULL)
1113 if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
1114 SmtpGreeting = newstr(p);
1116 SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1118 if (UnixFromLine == NULL)
1120 if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
1121 UnixFromLine = newstr(p);
1123 UnixFromLine = "From \201g \201d";
1126 /* our name for SMTP codes */
1127 expand("\201j", jbuf, sizeof jbuf, CurEnv);
1129 if (strchr(jbuf, '.') == NULL)
1130 message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1133 /* make certain that this name is part of the $=w class */
1134 setclass('w', MyHostName);
1136 /* the indices of built-in mailers */
1137 st = stab("local", ST_MAILER, ST_FIND);
1139 LocalMailer = st->s_mailer;
1140 else if (OpMode != MD_TEST || !warn_C_flag)
1141 syserr("No local mailer defined");
1143 st = stab("prog", ST_MAILER, ST_FIND);
1145 syserr("No prog mailer defined");
1148 ProgMailer = st->s_mailer;
1149 clrbitn(M_MUSER, ProgMailer->m_flags);
1152 st = stab("*file*", ST_MAILER, ST_FIND);
1154 syserr("No *file* mailer defined");
1157 FileMailer = st->s_mailer;
1158 clrbitn(M_MUSER, FileMailer->m_flags);
1161 st = stab("*include*", ST_MAILER, ST_FIND);
1163 syserr("No *include* mailer defined");
1165 InclMailer = st->s_mailer;
1167 if (ConfigLevel < 6)
1169 /* heuristic tweaking of local mailer for back compat */
1170 if (LocalMailer != NULL)
1172 setbitn(M_ALIASABLE, LocalMailer->m_flags);
1173 setbitn(M_HASPWENT, LocalMailer->m_flags);
1174 setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1175 setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1176 setbitn(M_CHECKPROG, LocalMailer->m_flags);
1177 setbitn(M_CHECKFILE, LocalMailer->m_flags);
1178 setbitn(M_CHECKUDB, LocalMailer->m_flags);
1180 if (ProgMailer != NULL)
1181 setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1182 if (FileMailer != NULL)
1183 setbitn(M_RUNASRCPT, FileMailer->m_flags);
1185 if (ConfigLevel < 7)
1187 if (LocalMailer != NULL)
1188 setbitn(M_VRFY250, LocalMailer->m_flags);
1189 if (ProgMailer != NULL)
1190 setbitn(M_VRFY250, ProgMailer->m_flags);
1191 if (FileMailer != NULL)
1192 setbitn(M_VRFY250, FileMailer->m_flags);
1195 /* MIME Content-Types that cannot be transfer encoded */
1196 setclass('n', "multipart/signed");
1198 /* MIME message/xxx subtypes that can be treated as messages */
1199 setclass('s', "rfc822");
1201 /* MIME Content-Transfer-Encodings that can be encoded */
1202 setclass('e', "7bit");
1203 setclass('e', "8bit");
1204 setclass('e', "binary");
1207 /* MIME Content-Types that should be treated as binary */
1208 setclass('b', "image");
1209 setclass('b', "audio");
1210 setclass('b', "video");
1211 setclass('b', "application/octet-stream");
1214 #if _FFR_MAX_MIME_HEADER_LENGTH
1215 /* MIME headers which have fields to check for overflow */
1216 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
1217 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
1219 /* MIME headers to check for length overflow */
1220 setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
1222 /* MIME headers to check for overflow and rebalance */
1223 setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
1224 setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
1225 setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
1226 setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
1227 setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
1230 /* operate in queue directory */
1231 if (QueueDir == NULL)
1233 if (OpMode != MD_TEST)
1235 syserr("QueueDirectory (Q) option must be set");
1236 ExitStat = EX_CONFIG;
1241 /* test path to get warning messages */
1242 (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE);
1243 if (OpMode != MD_TEST && chdir(QueueDir) < 0)
1245 syserr("cannot chdir(%s)", QueueDir);
1246 ExitStat = EX_CONFIG;
1250 /* check host status directory for validity */
1251 if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
1253 /* cannot use this value */
1255 printf("Cannot use HostStatusDirectory = %s: %s\n",
1256 HostStatDir, errstring(errno));
1261 if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1265 /* check to see if we own the queue directory */
1266 if (stat(".", &stbuf) < 0)
1267 syserr("main: cannot stat %s", QueueDir);
1268 if (stbuf.st_uid != RealUid)
1270 /* nope, really a botch */
1271 usrerr("You do not have permission to process the queue");
1272 finis(FALSE, EX_NOPERM);
1277 /* if we've had errors so far, exit now */
1278 if (ExitStat != EX_OK && OpMode != MD_TEST)
1279 finis(FALSE, ExitStat);
1282 checkfd012("before main() initmaps");
1286 ** Do operation-mode-dependent initialization.
1292 /* print the queue */
1294 dropenvelope(CurEnv, TRUE);
1295 signal(SIGPIPE, quiesce);
1297 finis(FALSE, EX_OK);
1299 usrerr("No queue to print");
1300 finis(FALSE, ExitStat);
1305 signal(SIGPIPE, quiesce);
1306 mci_traverse_persistent(mci_print_persistent, NULL);
1307 finis(FALSE, EX_OK);
1311 mci_traverse_persistent(mci_purge_persistent, NULL);
1312 finis(FALSE, EX_OK);
1316 /* initialize maps */
1317 initmaps(TRUE, CurEnv);
1318 finis(FALSE, ExitStat);
1323 /* reset DSN parameters */
1324 DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1325 CurEnv->e_envid = NULL;
1326 CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
1328 /* don't open maps for daemon -- done below in child */
1333 initmaps(FALSE, CurEnv);
1339 extern void printrules __P((void));
1341 /* print configuration table (or at least part of it) */
1344 for (i = 0; i < MAXMAILERS; i++)
1346 if (Mailer[i] != NULL)
1347 printmailer(Mailer[i]);
1352 ** Switch to the main envelope.
1355 CurEnv = newenvelope(&MainEnvelope, CurEnv);
1356 MainEnvelope.e_flags = BlankEnvelope.e_flags;
1359 ** If test mode, read addresses from stdin and process.
1362 if (OpMode == MD_TEST)
1365 SIGFUNC_DECL intindebug __P((int));
1367 if (isatty(fileno(stdin)))
1372 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1373 printf("Enter <ruleset> <address>\n");
1375 if (setjmp(TopFrame) > 0)
1377 (void) setsignal(SIGINT, intindebug);
1380 extern void testmodeline __P((char *, ENVELOPE *));
1384 (void) fflush(stdout);
1385 if (fgets(buf, sizeof buf, stdin) == NULL)
1386 finis(TRUE, ExitStat);
1387 p = strchr(buf, '\n');
1391 printf("> %s\n", buf);
1392 testmodeline(buf, CurEnv);
1398 ** If collecting stuff from the queue, go start doing that.
1401 if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
1403 (void) runqueue(FALSE, Verbose);
1404 finis(TRUE, ExitStat);
1409 ** If a daemon, wait for a request.
1410 ** getrequests will always return in a child.
1411 ** If we should also be processing the queue, start
1412 ** doing it in background.
1413 ** We check for any errors that might have happened
1417 if (OpMode == MD_DAEMON || QueueIntvl != 0)
1420 extern void getrequests __P((ENVELOPE *));
1422 if (!run_in_foreground && !tTd(99, 100))
1424 /* put us in background */
1427 syserr("daemon: cannot fork");
1429 finis(FALSE, EX_OK);
1431 /* disconnect from our controlling tty */
1432 disconnect(2, CurEnv);
1436 if (OpMode == MD_DAEMON)
1437 strcat(dtype, "+SMTP");
1438 if (QueueIntvl != 0)
1440 strcat(dtype, "+queueing@");
1441 strcat(dtype, pintvl(QueueIntvl, TRUE));
1444 strcat(dtype, "+debugging");
1446 sm_syslog(LOG_INFO, NOQID,
1447 "starting daemon (%s): %s", Version, dtype + 1);
1455 (void) runqueue(TRUE, FALSE);
1456 if (OpMode != MD_DAEMON)
1462 (void) runqueue(TRUE, FALSE);
1467 dropenvelope(CurEnv, TRUE);
1470 getrequests(CurEnv);
1472 /* drop privileges */
1473 (void) drop_privileges(FALSE);
1475 /* at this point we are in a child: reset state */
1476 (void) newenvelope(CurEnv, CurEnv);
1479 ** Get authentication data
1482 p = getauthinfo(fileno(InChannel), &forged);
1483 define('_', p, &BlankEnvelope);
1489 ** If running SMTP protocol, start collecting and executing
1490 ** commands. This will never return.
1493 if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1496 extern void smtp __P((char *, ENVELOPE *));
1499 ** Save some macros for check_* rulesets.
1506 snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
1507 inet_ntoa(RealHostAddr.sin.sin_addr));
1509 define(macid("{client_name}", NULL),
1510 newstr(ipbuf), &BlankEnvelope);
1513 define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope);
1514 define(macid("{client_addr}", NULL),
1515 newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
1516 if (RealHostAddr.sa.sa_family == AF_INET)
1517 snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
1519 snprintf(pbuf, sizeof pbuf, "0");
1520 define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
1522 /* initialize maps now for check_relay ruleset */
1523 initmaps(FALSE, CurEnv);
1525 if (OpMode == MD_DAEMON)
1527 /* validate the connection */
1529 nullserver = validate_connection(&RealHostAddr,
1530 RealHostName, CurEnv);
1533 smtp(nullserver, CurEnv);
1537 clearenvelope(CurEnv, FALSE);
1538 if (OpMode == MD_VERIFY)
1540 CurEnv->e_sendmode = SM_VERIFY;
1541 PostMasterCopy = NULL;
1545 /* interactive -- all errors are global */
1546 CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
1550 ** Do basic system initialization and set the sender
1554 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't'))
1555 auth_warning(CurEnv, "%s set sender to %s using -%c",
1556 RealUserName, from, warn_f_flag);
1557 setsender(from, CurEnv, NULL, '\0', FALSE);
1558 if (macvalue('s', CurEnv) == NULL)
1559 define('s', RealHostName, CurEnv);
1561 if (*av == NULL && !GrabTo)
1563 CurEnv->e_flags |= EF_GLOBALERRS;
1564 usrerr("Recipient names must be specified");
1566 /* collect body for UUCP return */
1567 if (OpMode != MD_VERIFY)
1568 collect(InChannel, FALSE, NULL, CurEnv);
1569 finis(TRUE, ExitStat);
1573 ** Scan argv and deliver the message to everyone.
1576 sendtoargv(av, CurEnv);
1578 /* if we have had errors sofar, arrange a meaningful exit stat */
1579 if (Errors > 0 && ExitStat == EX_OK)
1580 ExitStat = EX_USAGE;
1584 ** If using -t, force not sending to argv recipients, even
1585 ** if they are mentioned in the headers.
1592 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
1593 q->q_flags |= QDONTSEND;
1598 ** Read the input mail.
1601 CurEnv->e_to = NULL;
1602 if (OpMode != MD_VERIFY || GrabTo)
1604 long savedflags = CurEnv->e_flags & EF_FATALERRS;
1606 CurEnv->e_flags |= EF_GLOBALERRS;
1607 CurEnv->e_flags &= ~EF_FATALERRS;
1608 collect(InChannel, FALSE, NULL, CurEnv);
1610 /* bail out if message too large */
1611 if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
1613 finis(TRUE, ExitStat);
1617 CurEnv->e_flags |= savedflags;
1622 printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
1625 ** Actually send everything.
1626 ** If verifying, just ack.
1629 CurEnv->e_from.q_flags |= QDONTSEND;
1632 printf("main: QDONTSEND ");
1633 printaddr(&CurEnv->e_from, FALSE);
1635 CurEnv->e_to = NULL;
1636 CurrentLA = getla();
1638 sendall(CurEnv, SM_DEFAULT);
1642 ** Don't send return error message if in VERIFY mode.
1645 finis(TRUE, ExitStat);
1655 finis(FALSE, EX_OK);
1663 longjmp(TopFrame, 1);
1664 return SIGFUNC_RETURN;
1669 ** FINIS -- Clean up and exit.
1672 ** drop -- whether or not to drop CurEnv envelope
1673 ** exitstat -- exit status to use for exit() call
1683 finis(drop, exitstat)
1685 volatile int exitstat;
1687 extern void closemaps __P((void));
1689 extern void _udbx_close __P((void));
1694 extern void printenvflags __P((ENVELOPE *));
1696 printf("\n====finis: stat %d e_id=%s e_flags=",
1698 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
1699 printenvflags(CurEnv);
1702 printopenfds(FALSE);
1704 /* if we fail in finis(), just exit */
1705 if (setjmp(TopFrame) != 0)
1707 /* failed -- just give it up */
1711 /* clean up temp files */
1712 CurEnv->e_to = NULL;
1713 if (drop && CurEnv->e_id != NULL)
1714 dropenvelope(CurEnv, TRUE);
1716 /* flush any cached connections */
1717 mci_flush(TRUE, NULL);
1719 /* close maps belonging to this pid */
1723 /* close UserDatabase */
1728 /* clean up extended load average stuff */
1735 sm_syslog(LOG_DEBUG, CurEnv->e_id,
1738 if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
1741 /* reset uid for process accounting */
1748 ** INTSIG -- clean up on interrupt
1750 ** This just arranges to exit. It pessimises in that it
1751 ** may resend a message.
1760 ** Unlocks the current job.
1769 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
1771 unlockqueue(CurEnv);
1772 closecontrolsocket(TRUE);
1776 finis(FALSE, EX_OK);
1779 ** INITMACROS -- initialize the macro system
1781 ** This just involves defining some macros that are actually
1782 ** used internally as metasymbols to be themselves.
1791 ** initializes several macros to be themselves.
1794 struct metamac MetaMacros[] =
1796 /* LHS pattern matching characters */
1797 { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
1798 { '=', MATCHCLASS }, { '~', MATCHNCLASS },
1800 /* these are RHS metasymbols */
1801 { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
1804 /* the conditional operations */
1805 { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
1807 /* the hostname lookup characters */
1808 { '[', HOSTBEGIN }, { ']', HOSTEND },
1809 { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
1811 /* miscellaneous control characters */
1812 { '&', MACRODEXPAND },
1817 #define MACBINDING(name, mid) \
1818 stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
1819 MacroName[mid] = name;
1823 register ENVELOPE *e;
1825 register struct metamac *m;
1828 extern char *MacroName[256];
1830 for (m = MetaMacros; m->metaname != '\0'; m++)
1832 buf[0] = m->metaval;
1834 define(m->metaname, newstr(buf), e);
1838 for (c = '0'; c <= '9'; c++)
1841 define(c, newstr(buf), e);
1844 /* set defaults for some macros sendmail will use later */
1845 define('n', "MAILER-DAEMON", e);
1847 /* set up external names for some internal macros */
1848 MACBINDING("opMode", MID_OPMODE);
1849 /*XXX should probably add equivalents for all short macros here XXX*/
1852 ** DISCONNECT -- remove our connection with any foreground process
1855 ** droplev -- how "deeply" we should drop the line.
1856 ** 0 -- ignore signals, mail back errors, make sure
1857 ** output goes to stdout.
1858 ** 1 -- also, make stdout go to transcript.
1859 ** 2 -- also, disconnect from controlling terminal
1860 ** (only for daemon mode).
1861 ** e -- the current envelope.
1867 ** Trys to insure that we are immune to vagaries of
1868 ** the controlling tty.
1872 disconnect(droplev, e)
1874 register ENVELOPE *e;
1879 printf("disconnect: In %d Out %d, e=%lx\n",
1880 fileno(InChannel), fileno(OutChannel), (u_long) e);
1887 sm_syslog(LOG_DEBUG, e->e_id,
1888 "disconnect level %d",
1891 /* be sure we don't get nasty signals */
1892 (void) setsignal(SIGINT, SIG_IGN);
1893 (void) setsignal(SIGQUIT, SIG_IGN);
1895 /* we can't communicate with our caller, so.... */
1897 CurEnv->e_errormode = EM_MAIL;
1899 DisConnected = TRUE;
1901 /* all input from /dev/null */
1902 if (InChannel != stdin)
1904 (void) fclose(InChannel);
1907 if (freopen("/dev/null", "r", stdin) == NULL)
1908 sm_syslog(LOG_ERR, e->e_id,
1909 "disconnect: freopen(\"/dev/null\") failed: %s",
1912 /* output to the transcript */
1913 if (OutChannel != stdout)
1915 (void) fclose(OutChannel);
1916 OutChannel = stdout;
1920 if (e->e_xfp == NULL)
1922 fd = open("/dev/null", O_WRONLY, 0666);
1924 sm_syslog(LOG_ERR, e->e_id,
1925 "disconnect: open(\"/dev/null\") failed: %s",
1930 fd = fileno(e->e_xfp);
1932 sm_syslog(LOG_ERR, e->e_id,
1933 "disconnect: fileno(e->e_xfp) failed: %s",
1936 (void) fflush(stdout);
1937 dup2(fd, STDOUT_FILENO);
1938 dup2(fd, STDERR_FILENO);
1939 if (e->e_xfp == NULL)
1943 /* drop our controlling TTY completely if possible */
1951 checkfd012("disconnect");
1955 sm_syslog(LOG_DEBUG, e->e_id,
1956 "in background, pid=%d",
1969 while ((ap = *++argv) != NULL)
1971 /* Return if "--" or not an option of any form. */
1972 if (ap[0] != '-' || ap[1] == '-')
1975 /* skip over options that do have a value */
1976 op = strchr(OPTIONS, ap[1]);
1977 if (op != NULL && *++op == ':' && ap[2] == '\0' &&
1979 #if defined(sony_news)
1980 ap[1] != 'E' && ap[1] != 'J' &&
1982 argv[1] != NULL && argv[1][0] != '-')
1988 /* If -C doesn't have an argument, use sendmail.cf. */
1989 #define __DEFPATH "sendmail.cf"
1990 if (ap[1] == 'C' && ap[2] == '\0')
1992 *argv = xalloc(sizeof(__DEFPATH) + 2);
1995 (void)strcpy(&argv[0][2], __DEFPATH);
1998 /* If -q doesn't have an argument, run it once. */
1999 if (ap[1] == 'q' && ap[2] == '\0')
2002 /* if -d doesn't have an argument, use 0-99.1 */
2003 if (ap[1] == 'd' && ap[2] == '\0')
2006 # if defined(sony_news)
2007 /* if -E doesn't have an argument, use -EC */
2008 if (ap[1] == 'E' && ap[2] == '\0')
2011 /* if -J doesn't have an argument, use -JJ */
2012 if (ap[1] == 'J' && ap[2] == '\0')
2018 ** AUTH_WARNING -- specify authorization warning
2021 ** e -- the current envelope.
2022 ** msg -- the text of the message.
2023 ** args -- arguments to the message.
2031 auth_warning(register ENVELOPE *e, const char *msg, ...)
2033 auth_warning(e, msg, va_alist)
2034 register ENVELOPE *e;
2042 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
2045 static char hostbuf[48];
2046 extern struct hostent *myhostname __P((char *, int));
2048 if (hostbuf[0] == '\0')
2049 (void) myhostname(hostbuf, sizeof hostbuf);
2051 (void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
2052 p = &buf[strlen(buf)];
2054 vsnprintf(p, SPACELEFT(buf, p), msg, ap);
2056 addheader("X-Authentication-Warning", buf, &e->e_header);
2058 sm_syslog(LOG_INFO, e->e_id,
2059 "Authentication-Warning: %.400s",
2064 ** GETEXTENV -- get from external environment
2067 ** envar -- the name of the variable to retrieve
2070 ** The value, if any.
2081 for (envp = ExternalEnviron; *envp != NULL; envp++)
2083 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
2084 return &(*envp)[l + 1];
2089 ** SETUSERENV -- set an environment in the propogated environment
2092 ** envar -- the name of the environment variable.
2093 ** value -- the value to which it should be set. If
2094 ** null, this is extracted from the incoming
2095 ** environment. If that is not set, the call
2096 ** to setuserenv is ignored.
2103 setuserenv(envar, value)
2108 char **evp = UserEnviron;
2113 value = getextenv(envar);
2119 p = (char *) xalloc(strlen(value) + i + 2);
2122 strcpy(&p[i], value);
2124 while (*evp != NULL && strncmp(*evp, p, i) != 0)
2130 else if (evp < &UserEnviron[MAXUSERENVIRON])
2136 /* make sure it is in our environment as well */
2138 syserr("setuserenv: putenv(%s) failed", p);
2141 ** DUMPSTATE -- dump state
2150 register char *j = macvalue('j', CurEnv);
2153 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2154 "--- dumping state on %s: $j = %s ---",
2156 j == NULL ? "<NULL>" : j);
2159 if (!wordinclass(j, 'w'))
2160 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2161 "*** $j not in $=w ***");
2163 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
2164 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
2166 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
2168 rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
2172 register char **pvp;
2173 char *pv[MAXATOM + 1];
2176 stat = rewrite(pv, rs, 0, CurEnv);
2177 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2178 "--- ruleset debug_dumpstate returns stat %d, pv: ---",
2180 for (pvp = pv; *pvp != NULL; pvp++)
2181 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
2183 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
2192 dumpstate("user signal");
2193 return SIGFUNC_RETURN;
2202 if (SaveArgv[0][0] != '/')
2205 sm_syslog(LOG_INFO, NOQID, "could not restart: need full path");
2206 finis(FALSE, EX_OSFILE);
2209 sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]);
2211 releasesignal(SIGHUP);
2212 closecontrolsocket(TRUE);
2213 if (drop_privileges(TRUE) != EX_OK)
2216 sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m",
2217 RunAsUid, RunAsGid);
2218 finis(FALSE, EX_OSERR);
2220 execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
2222 sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]);
2223 finis(FALSE, EX_OSFILE);
2226 ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
2229 ** to_real_uid -- if set, drop to the real uid instead
2230 ** of the RunAsUser.
2233 ** EX_OSERR if the setuid failed.
2238 drop_privileges(to_real_uid)
2242 GIDSET_T emptygidset[1];
2245 printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
2246 (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
2250 RunAsUserName = RealUserName;
2255 /* make sure no one can grab open descriptors for secret files */
2258 /* reset group permissions; these can be set later */
2259 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
2260 if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
2263 /* reset primary group and user id */
2264 if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
2266 if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
2270 printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
2271 (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
2272 printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
2277 ** FILL_FD -- make sure a file descriptor has been properly allocated
2279 ** Used to make sure that stdin/out/err are allocated on startup
2282 ** fd -- the file descriptor to be filled.
2283 ** where -- a string used for logging. If NULL, this is
2284 ** being called on startup, and logging should
2299 if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
2303 syserr("fill_fd: %s: fd %d not open", where, fd);
2305 MissingFds |= 1 << fd;
2306 i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
2309 syserr("!fill_fd: %s: cannot open /dev/null",
2310 where == NULL ? "startup" : where);
2319 ** TESTMODELINE -- process a test mode input line
2322 ** line -- the input line.
2323 ** e -- the current environment.
2326 ** .X process X as a configuration line
2327 ** =X dump a configuration item (such as mailers)
2328 ** $X dump a macro or class
2329 ** /X try an activity
2330 ** X normal process through rule set X
2334 testmodeline(line, e)
2340 auto char *delimptr;
2347 static int tryflags = RF_COPYNONE;
2348 char exbuf[MAXLINE];
2349 extern bool invalidaddr __P((char *, char *));
2350 extern char *crackaddr __P((char *));
2351 extern void dump_class __P((STAB *, int));
2352 extern void translate_dollars __P((char *));
2353 extern void help __P((char *));
2365 case '.': /* config-style settings */
2369 mid = macid(&line[2], &delimptr);
2372 translate_dollars(delimptr);
2373 define(mid, newstr(delimptr), e);
2377 if (line[2] == '\0') /* not to call syserr() */
2380 mid = macid(&line[2], &delimptr);
2383 translate_dollars(delimptr);
2384 expand(delimptr, exbuf, sizeof exbuf, e);
2391 while (*p != '\0' && isascii(*p) && isspace(*p))
2394 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2405 printf("Usage: .[DC]macro value(s)\n");
2409 printf("Unknown \".\" command %s\n", line);
2414 case '=': /* config-style settings */
2417 case 'S': /* dump rule set */
2418 rs = strtorwset(&line[2], NULL, ST_FIND);
2421 printf("Undefined ruleset %s\n", &line[2]);
2424 rw = RewriteRules[rs];
2445 } while ((rw = rw->r_next) != NULL);
2449 for (i = 0; i < MAXMAILERS; i++)
2451 if (Mailer[i] != NULL)
2452 printmailer(Mailer[i]);
2457 printf("Usage: =Sruleset or =M\n");
2461 printf("Unknown \"=\" command %s\n", line);
2466 case '-': /* set command-line-like opts */
2474 printf("Usage: -d{debug arguments}\n");
2478 printf("Unknown \"-\" command %s\n", line);
2486 mid = macid(&line[2], NULL);
2488 stabapply(dump_class, mid);
2491 mid = macid(&line[1], NULL);
2494 p = macvalue(mid, e);
2496 printf("Undefined\n");
2504 case '/': /* miscellaneous commands */
2505 p = &line[strlen(line)];
2506 while (--p >= line && isascii(*p) && isspace(*p))
2508 p = strpbrk(line, " \t");
2511 while (isascii(*p) && isspace(*p))
2516 if (line[1] == '\0')
2518 printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
2521 if (strcasecmp(&line[1], "mx") == 0)
2524 /* look up MX records */
2527 char *mxhosts[MAXMXHOSTS + 1];
2531 printf("Usage: /mx address\n");
2534 nmx = getmxrr(p, mxhosts, FALSE, &rcode);
2535 printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
2536 for (i = 0; i < nmx; i++)
2537 printf("\t%s\n", mxhosts[i]);
2539 printf("No MX code compiled in\n");
2542 else if (strcasecmp(&line[1], "canon") == 0)
2544 char host[MAXHOSTNAMELEN];
2548 printf("Usage: /canon address\n");
2551 else if (strlen(p) >= sizeof host)
2553 printf("Name too long\n");
2557 (void) getcanonname(host, sizeof(host), HasWildcardMX);
2558 printf("getcanonname(%s) returns %s\n", p, host);
2560 else if (strcasecmp(&line[1], "map") == 0)
2562 auto int rcode = EX_OK;
2567 printf("Usage: /map mapname key\n");
2570 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
2574 printf("No key specified\n");
2578 map = stab(p, ST_MAP, ST_FIND);
2581 printf("Map named \"%s\" not found\n", p);
2584 if (!bitset(MF_OPEN, map->s_map.map_mflags))
2586 printf("Map named \"%s\" not open\n", p);
2589 printf("map_lookup: %s (%s) ", p, q);
2592 p = (*map->s_map.map_class->map_lookup)
2593 (&map->s_map, q, av, &rcode);
2595 printf("no match (%d)\n", rcode);
2597 printf("returns %s (%d)\n", p, rcode);
2599 else if (strcasecmp(&line[1], "try") == 0)
2603 auto int rcode = EX_OK;
2605 q = strpbrk(p, " \t");
2608 while (isascii(*q) && isspace(*q))
2611 if (q == NULL || *q == '\0')
2613 printf("Usage: /try mailer address\n");
2616 s = stab(p, ST_MAILER, ST_FIND);
2619 printf("Unknown mailer %s\n", p);
2623 printf("Trying %s %s address %s for mailer %s\n",
2624 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2625 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
2627 p = remotename(q, m, tryflags, &rcode, CurEnv);
2628 printf("Rcode = %d, addr = %s\n",
2629 rcode, p == NULL ? "<NULL>" : p);
2632 else if (strcasecmp(&line[1], "tryflags") == 0)
2636 printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
2639 for (; *p != '\0'; p++)
2645 tryflags |= RF_HEADERADDR;
2650 tryflags &= ~RF_HEADERADDR;
2655 tryflags |= RF_SENDERADDR;
2660 tryflags &= ~RF_SENDERADDR;
2665 else if (strcasecmp(&line[1], "parse") == 0)
2669 printf("Usage: /parse address\n");
2673 printf("Cracked address = ");
2675 printf("\nParsing %s %s address\n",
2676 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2677 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
2678 if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
2679 printf("Cannot parse\n");
2680 else if (a.q_host != NULL && a.q_host[0] != '\0')
2681 printf("mailer %s, host %s, user %s\n",
2682 a.q_mailer->m_name, a.q_host, a.q_user);
2684 printf("mailer %s, user %s\n",
2685 a.q_mailer->m_name, a.q_user);
2690 printf("Unknown \"/\" command %s\n", line);
2695 for (p = line; isascii(*p) && isspace(*p); p++)
2698 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2702 printf("No address!\n");
2706 if (invalidaddr(p + 1, NULL))
2710 register char **pvp;
2711 char pvpbuf[PSBUFSIZE];
2713 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
2722 rs = strtorwset(p, NULL, ST_FIND);
2725 printf("Undefined ruleset %s\n", p);
2728 stat = rewrite(pvp, rs, 0, e);
2730 printf("== Ruleset %s (%d) status %d\n",
2732 while (*p != '\0' && *p++ != ',')
2735 } while (*(p = delimptr) != '\0');
2744 if (s->s_type != ST_CLASS)
2746 if (bitnset(id & 0xff, s->s_class))
2747 printf("%s\n", s->s_name);