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);
987 if (OpMode == MD_INITALIAS &&
989 RealUid != TrustedUid &&
990 !wordinclass(RealUserName, 't'))
993 sm_syslog(LOG_ALERT, NOQID,
994 "user %d attempted to rebuild the alias map",
996 usrerr("Permission denied");
997 finis(FALSE, EX_USAGE);
1001 BlankEnvelope.e_flags |= EF_METOO;
1006 /* don't have persistent host status in test mode */
1010 CurEnv->e_errormode = EM_PRINT;
1015 CurEnv->e_errormode = EM_PRINT;
1017 /* arrange to exit cleanly on hangup signal */
1018 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1019 setsignal(SIGHUP, intsig);
1023 run_in_foreground = TRUE;
1025 /* fall through ... */
1028 vendor_daemon_setup(CurEnv);
1030 /* remove things that don't make sense in daemon mode */
1034 /* arrange to restart on hangup signal */
1035 if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1036 sm_syslog(LOG_WARNING, NOQID,
1037 "daemon invoked without full pathname; kill -1 won't work");
1038 setsignal(SIGHUP, sighup);
1040 /* workaround: can't seem to release the signal in the parent */
1041 releasesignal(SIGHUP);
1046 CurEnv->e_errormode = EM_PRINT;
1048 /* fall through... */
1051 /* to handle sendmail -bp -qSfoobar properly */
1053 /* fall through... */
1056 /* arrange to exit cleanly on hangup signal */
1057 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1058 setsignal(SIGHUP, intsig);
1062 /* special considerations for FullName */
1063 if (FullName != NULL)
1066 extern bool rfc822_string __P((char *));
1068 /* full names can't have newlines */
1069 if (strchr(FullName, '\n') != NULL)
1071 FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
1073 /* check for characters that may have to be quoted */
1074 if (!rfc822_string(FullName))
1076 extern char *addquotes __P((char *));
1079 ** Quote a full name with special characters
1080 ** as a comment so crackaddr() doesn't destroy
1081 ** the name portion of the address.
1083 FullName = addquotes(FullName);
1089 /* do heuristic mode adjustment */
1092 /* turn off noconnect option */
1093 setoption('c', "F", TRUE, FALSE, CurEnv);
1095 /* turn on interactive delivery */
1096 setoption('d', "", TRUE, FALSE, CurEnv);
1100 /* check for vendor mismatch */
1101 if (VendorCode != VENDOR_CODE)
1103 extern char *getvendor __P((int));
1105 message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1106 getvendor(VENDOR_CODE), getvendor(VendorCode));
1110 /* check for out of date configuration level */
1111 if (ConfigLevel < MAXCONFIGLEVEL)
1113 message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1114 Version, MAXCONFIGLEVEL, ConfigLevel);
1117 if (ConfigLevel < 3)
1122 /* set options that were previous macros */
1123 if (SmtpGreeting == NULL)
1125 if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
1126 SmtpGreeting = newstr(p);
1128 SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1130 if (UnixFromLine == NULL)
1132 if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
1133 UnixFromLine = newstr(p);
1135 UnixFromLine = "From \201g \201d";
1138 /* our name for SMTP codes */
1139 expand("\201j", jbuf, sizeof jbuf, CurEnv);
1141 if (strchr(jbuf, '.') == NULL)
1142 message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1145 /* make certain that this name is part of the $=w class */
1146 setclass('w', MyHostName);
1148 /* the indices of built-in mailers */
1149 st = stab("local", ST_MAILER, ST_FIND);
1151 LocalMailer = st->s_mailer;
1152 else if (OpMode != MD_TEST || !warn_C_flag)
1153 syserr("No local mailer defined");
1155 st = stab("prog", ST_MAILER, ST_FIND);
1157 syserr("No prog mailer defined");
1160 ProgMailer = st->s_mailer;
1161 clrbitn(M_MUSER, ProgMailer->m_flags);
1164 st = stab("*file*", ST_MAILER, ST_FIND);
1166 syserr("No *file* mailer defined");
1169 FileMailer = st->s_mailer;
1170 clrbitn(M_MUSER, FileMailer->m_flags);
1173 st = stab("*include*", ST_MAILER, ST_FIND);
1175 syserr("No *include* mailer defined");
1177 InclMailer = st->s_mailer;
1179 if (ConfigLevel < 6)
1181 /* heuristic tweaking of local mailer for back compat */
1182 if (LocalMailer != NULL)
1184 setbitn(M_ALIASABLE, LocalMailer->m_flags);
1185 setbitn(M_HASPWENT, LocalMailer->m_flags);
1186 setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1187 setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1188 setbitn(M_CHECKPROG, LocalMailer->m_flags);
1189 setbitn(M_CHECKFILE, LocalMailer->m_flags);
1190 setbitn(M_CHECKUDB, LocalMailer->m_flags);
1192 if (ProgMailer != NULL)
1193 setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1194 if (FileMailer != NULL)
1195 setbitn(M_RUNASRCPT, FileMailer->m_flags);
1197 if (ConfigLevel < 7)
1199 if (LocalMailer != NULL)
1200 setbitn(M_VRFY250, LocalMailer->m_flags);
1201 if (ProgMailer != NULL)
1202 setbitn(M_VRFY250, ProgMailer->m_flags);
1203 if (FileMailer != NULL)
1204 setbitn(M_VRFY250, FileMailer->m_flags);
1207 /* MIME Content-Types that cannot be transfer encoded */
1208 setclass('n', "multipart/signed");
1210 /* MIME message/xxx subtypes that can be treated as messages */
1211 setclass('s', "rfc822");
1213 /* MIME Content-Transfer-Encodings that can be encoded */
1214 setclass('e', "7bit");
1215 setclass('e', "8bit");
1216 setclass('e', "binary");
1219 /* MIME Content-Types that should be treated as binary */
1220 setclass('b', "image");
1221 setclass('b', "audio");
1222 setclass('b', "video");
1223 setclass('b', "application/octet-stream");
1226 #if _FFR_MAX_MIME_HEADER_LENGTH
1227 /* MIME headers which have fields to check for overflow */
1228 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
1229 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
1231 /* MIME headers to check for length overflow */
1232 setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
1234 /* MIME headers to check for overflow and rebalance */
1235 setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
1236 setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
1237 setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
1238 setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
1239 setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
1242 /* operate in queue directory */
1243 if (QueueDir == NULL)
1245 if (OpMode != MD_TEST)
1247 syserr("QueueDirectory (Q) option must be set");
1248 ExitStat = EX_CONFIG;
1253 /* test path to get warning messages */
1254 (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE);
1255 if (OpMode != MD_TEST && chdir(QueueDir) < 0)
1257 syserr("cannot chdir(%s)", QueueDir);
1258 ExitStat = EX_CONFIG;
1262 /* check host status directory for validity */
1263 if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
1265 /* cannot use this value */
1267 printf("Cannot use HostStatusDirectory = %s: %s\n",
1268 HostStatDir, errstring(errno));
1273 if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1277 /* check to see if we own the queue directory */
1278 if (stat(".", &stbuf) < 0)
1279 syserr("main: cannot stat %s", QueueDir);
1280 if (stbuf.st_uid != RealUid)
1282 /* nope, really a botch */
1283 usrerr("You do not have permission to process the queue");
1284 finis(FALSE, EX_NOPERM);
1289 /* if we've had errors so far, exit now */
1290 if (ExitStat != EX_OK && OpMode != MD_TEST)
1291 finis(FALSE, ExitStat);
1294 checkfd012("before main() initmaps");
1298 ** Do operation-mode-dependent initialization.
1304 /* print the queue */
1306 dropenvelope(CurEnv, TRUE);
1307 signal(SIGPIPE, quiesce);
1309 finis(FALSE, EX_OK);
1311 usrerr("No queue to print");
1312 finis(FALSE, ExitStat);
1317 signal(SIGPIPE, quiesce);
1318 mci_traverse_persistent(mci_print_persistent, NULL);
1319 finis(FALSE, EX_OK);
1323 mci_traverse_persistent(mci_purge_persistent, NULL);
1324 finis(FALSE, EX_OK);
1328 /* initialize maps */
1329 initmaps(TRUE, CurEnv);
1330 finis(FALSE, ExitStat);
1335 /* reset DSN parameters */
1336 DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1337 CurEnv->e_envid = NULL;
1338 CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
1340 /* don't open maps for daemon -- done below in child */
1345 initmaps(FALSE, CurEnv);
1351 extern void printrules __P((void));
1353 /* print configuration table (or at least part of it) */
1356 for (i = 0; i < MAXMAILERS; i++)
1358 if (Mailer[i] != NULL)
1359 printmailer(Mailer[i]);
1364 ** Switch to the main envelope.
1367 CurEnv = newenvelope(&MainEnvelope, CurEnv);
1368 MainEnvelope.e_flags = BlankEnvelope.e_flags;
1371 ** If test mode, read addresses from stdin and process.
1374 if (OpMode == MD_TEST)
1377 SIGFUNC_DECL intindebug __P((int));
1379 if (isatty(fileno(stdin)))
1384 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1385 printf("Enter <ruleset> <address>\n");
1387 if (setjmp(TopFrame) > 0)
1389 (void) setsignal(SIGINT, intindebug);
1392 extern void testmodeline __P((char *, ENVELOPE *));
1396 (void) fflush(stdout);
1397 if (fgets(buf, sizeof buf, stdin) == NULL)
1398 finis(TRUE, ExitStat);
1399 p = strchr(buf, '\n');
1403 printf("> %s\n", buf);
1404 testmodeline(buf, CurEnv);
1410 ** If collecting stuff from the queue, go start doing that.
1413 if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
1415 (void) runqueue(FALSE, Verbose);
1416 finis(TRUE, ExitStat);
1421 ** If a daemon, wait for a request.
1422 ** getrequests will always return in a child.
1423 ** If we should also be processing the queue, start
1424 ** doing it in background.
1425 ** We check for any errors that might have happened
1429 if (OpMode == MD_DAEMON || QueueIntvl != 0)
1432 extern void getrequests __P((ENVELOPE *));
1434 if (!run_in_foreground && !tTd(99, 100))
1436 /* put us in background */
1439 syserr("daemon: cannot fork");
1441 finis(FALSE, EX_OK);
1443 /* disconnect from our controlling tty */
1444 disconnect(2, CurEnv);
1448 if (OpMode == MD_DAEMON)
1449 strcat(dtype, "+SMTP");
1450 if (QueueIntvl != 0)
1452 strcat(dtype, "+queueing@");
1453 strcat(dtype, pintvl(QueueIntvl, TRUE));
1456 strcat(dtype, "+debugging");
1458 sm_syslog(LOG_INFO, NOQID,
1459 "starting daemon (%s): %s", Version, dtype + 1);
1467 (void) runqueue(TRUE, FALSE);
1468 if (OpMode != MD_DAEMON)
1474 (void) runqueue(TRUE, FALSE);
1479 dropenvelope(CurEnv, TRUE);
1482 getrequests(CurEnv);
1484 /* drop privileges */
1485 (void) drop_privileges(FALSE);
1487 /* at this point we are in a child: reset state */
1488 (void) newenvelope(CurEnv, CurEnv);
1491 ** Get authentication data
1494 p = getauthinfo(fileno(InChannel), &forged);
1495 define('_', p, &BlankEnvelope);
1501 ** If running SMTP protocol, start collecting and executing
1502 ** commands. This will never return.
1505 if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1508 extern void smtp __P((char *, ENVELOPE *));
1511 ** Save some macros for check_* rulesets.
1518 snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
1519 inet_ntoa(RealHostAddr.sin.sin_addr));
1521 define(macid("{client_name}", NULL),
1522 newstr(ipbuf), &BlankEnvelope);
1525 define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope);
1526 define(macid("{client_addr}", NULL),
1527 newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
1528 if (RealHostAddr.sa.sa_family == AF_INET)
1529 snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
1531 snprintf(pbuf, sizeof pbuf, "0");
1532 define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
1534 /* initialize maps now for check_relay ruleset */
1535 initmaps(FALSE, CurEnv);
1537 if (OpMode == MD_DAEMON)
1539 /* validate the connection */
1541 nullserver = validate_connection(&RealHostAddr,
1542 RealHostName, CurEnv);
1545 smtp(nullserver, CurEnv);
1549 clearenvelope(CurEnv, FALSE);
1550 if (OpMode == MD_VERIFY)
1552 CurEnv->e_sendmode = SM_VERIFY;
1553 PostMasterCopy = NULL;
1557 /* interactive -- all errors are global */
1558 CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
1562 ** Do basic system initialization and set the sender
1566 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't'))
1567 auth_warning(CurEnv, "%s set sender to %s using -%c",
1568 RealUserName, from, warn_f_flag);
1569 setsender(from, CurEnv, NULL, '\0', FALSE);
1570 if (macvalue('s', CurEnv) == NULL)
1571 define('s', RealHostName, CurEnv);
1573 if (*av == NULL && !GrabTo)
1575 CurEnv->e_flags |= EF_GLOBALERRS;
1576 usrerr("Recipient names must be specified");
1578 /* collect body for UUCP return */
1579 if (OpMode != MD_VERIFY)
1580 collect(InChannel, FALSE, NULL, CurEnv);
1581 finis(TRUE, ExitStat);
1585 ** Scan argv and deliver the message to everyone.
1588 sendtoargv(av, CurEnv);
1590 /* if we have had errors sofar, arrange a meaningful exit stat */
1591 if (Errors > 0 && ExitStat == EX_OK)
1592 ExitStat = EX_USAGE;
1596 ** If using -t, force not sending to argv recipients, even
1597 ** if they are mentioned in the headers.
1604 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
1605 q->q_flags |= QDONTSEND;
1610 ** Read the input mail.
1613 CurEnv->e_to = NULL;
1614 if (OpMode != MD_VERIFY || GrabTo)
1616 long savedflags = CurEnv->e_flags & EF_FATALERRS;
1618 CurEnv->e_flags |= EF_GLOBALERRS;
1619 CurEnv->e_flags &= ~EF_FATALERRS;
1620 collect(InChannel, FALSE, NULL, CurEnv);
1622 /* bail out if message too large */
1623 if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
1625 finis(TRUE, ExitStat);
1629 CurEnv->e_flags |= savedflags;
1634 printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
1637 ** Actually send everything.
1638 ** If verifying, just ack.
1641 CurEnv->e_from.q_flags |= QDONTSEND;
1644 printf("main: QDONTSEND ");
1645 printaddr(&CurEnv->e_from, FALSE);
1647 CurEnv->e_to = NULL;
1648 CurrentLA = getla();
1650 sendall(CurEnv, SM_DEFAULT);
1654 ** Don't send return error message if in VERIFY mode.
1657 finis(TRUE, ExitStat);
1667 finis(FALSE, EX_OK);
1675 longjmp(TopFrame, 1);
1676 return SIGFUNC_RETURN;
1681 ** FINIS -- Clean up and exit.
1684 ** drop -- whether or not to drop CurEnv envelope
1685 ** exitstat -- exit status to use for exit() call
1695 finis(drop, exitstat)
1697 volatile int exitstat;
1699 extern void closemaps __P((void));
1701 extern void _udbx_close __P((void));
1706 extern void printenvflags __P((ENVELOPE *));
1708 printf("\n====finis: stat %d e_id=%s e_flags=",
1710 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
1711 printenvflags(CurEnv);
1714 printopenfds(FALSE);
1716 /* if we fail in finis(), just exit */
1717 if (setjmp(TopFrame) != 0)
1719 /* failed -- just give it up */
1723 /* clean up temp files */
1724 CurEnv->e_to = NULL;
1725 if (drop && CurEnv->e_id != NULL)
1726 dropenvelope(CurEnv, TRUE);
1728 /* flush any cached connections */
1729 mci_flush(TRUE, NULL);
1731 /* close maps belonging to this pid */
1735 /* close UserDatabase */
1740 /* clean up extended load average stuff */
1747 sm_syslog(LOG_DEBUG, CurEnv->e_id,
1750 if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
1753 /* reset uid for process accounting */
1760 ** INTSIG -- clean up on interrupt
1762 ** This just arranges to exit. It pessimises in that it
1763 ** may resend a message.
1772 ** Unlocks the current job.
1781 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
1783 unlockqueue(CurEnv);
1784 closecontrolsocket(TRUE);
1788 finis(FALSE, EX_OK);
1791 ** INITMACROS -- initialize the macro system
1793 ** This just involves defining some macros that are actually
1794 ** used internally as metasymbols to be themselves.
1803 ** initializes several macros to be themselves.
1806 struct metamac MetaMacros[] =
1808 /* LHS pattern matching characters */
1809 { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
1810 { '=', MATCHCLASS }, { '~', MATCHNCLASS },
1812 /* these are RHS metasymbols */
1813 { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
1816 /* the conditional operations */
1817 { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
1819 /* the hostname lookup characters */
1820 { '[', HOSTBEGIN }, { ']', HOSTEND },
1821 { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
1823 /* miscellaneous control characters */
1824 { '&', MACRODEXPAND },
1829 #define MACBINDING(name, mid) \
1830 stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
1831 MacroName[mid] = name;
1835 register ENVELOPE *e;
1837 register struct metamac *m;
1840 extern char *MacroName[256];
1842 for (m = MetaMacros; m->metaname != '\0'; m++)
1844 buf[0] = m->metaval;
1846 define(m->metaname, newstr(buf), e);
1850 for (c = '0'; c <= '9'; c++)
1853 define(c, newstr(buf), e);
1856 /* set defaults for some macros sendmail will use later */
1857 define('n', "MAILER-DAEMON", e);
1859 /* set up external names for some internal macros */
1860 MACBINDING("opMode", MID_OPMODE);
1861 /*XXX should probably add equivalents for all short macros here XXX*/
1864 ** DISCONNECT -- remove our connection with any foreground process
1867 ** droplev -- how "deeply" we should drop the line.
1868 ** 0 -- ignore signals, mail back errors, make sure
1869 ** output goes to stdout.
1870 ** 1 -- also, make stdout go to transcript.
1871 ** 2 -- also, disconnect from controlling terminal
1872 ** (only for daemon mode).
1873 ** e -- the current envelope.
1879 ** Trys to insure that we are immune to vagaries of
1880 ** the controlling tty.
1884 disconnect(droplev, e)
1886 register ENVELOPE *e;
1891 printf("disconnect: In %d Out %d, e=%lx\n",
1892 fileno(InChannel), fileno(OutChannel), (u_long) e);
1899 sm_syslog(LOG_DEBUG, e->e_id,
1900 "disconnect level %d",
1903 /* be sure we don't get nasty signals */
1904 (void) setsignal(SIGINT, SIG_IGN);
1905 (void) setsignal(SIGQUIT, SIG_IGN);
1907 /* we can't communicate with our caller, so.... */
1909 CurEnv->e_errormode = EM_MAIL;
1911 DisConnected = TRUE;
1913 /* all input from /dev/null */
1914 if (InChannel != stdin)
1916 (void) fclose(InChannel);
1919 if (freopen("/dev/null", "r", stdin) == NULL)
1920 sm_syslog(LOG_ERR, e->e_id,
1921 "disconnect: freopen(\"/dev/null\") failed: %s",
1924 /* output to the transcript */
1925 if (OutChannel != stdout)
1927 (void) fclose(OutChannel);
1928 OutChannel = stdout;
1932 if (e->e_xfp == NULL)
1934 fd = open("/dev/null", O_WRONLY, 0666);
1936 sm_syslog(LOG_ERR, e->e_id,
1937 "disconnect: open(\"/dev/null\") failed: %s",
1942 fd = fileno(e->e_xfp);
1944 sm_syslog(LOG_ERR, e->e_id,
1945 "disconnect: fileno(e->e_xfp) failed: %s",
1948 (void) fflush(stdout);
1949 dup2(fd, STDOUT_FILENO);
1950 dup2(fd, STDERR_FILENO);
1951 if (e->e_xfp == NULL)
1955 /* drop our controlling TTY completely if possible */
1963 checkfd012("disconnect");
1967 sm_syslog(LOG_DEBUG, e->e_id,
1968 "in background, pid=%d",
1981 while ((ap = *++argv) != NULL)
1983 /* Return if "--" or not an option of any form. */
1984 if (ap[0] != '-' || ap[1] == '-')
1987 /* skip over options that do have a value */
1988 op = strchr(OPTIONS, ap[1]);
1989 if (op != NULL && *++op == ':' && ap[2] == '\0' &&
1991 #if defined(sony_news)
1992 ap[1] != 'E' && ap[1] != 'J' &&
1994 argv[1] != NULL && argv[1][0] != '-')
2000 /* If -C doesn't have an argument, use sendmail.cf. */
2001 #define __DEFPATH "sendmail.cf"
2002 if (ap[1] == 'C' && ap[2] == '\0')
2004 *argv = xalloc(sizeof(__DEFPATH) + 2);
2007 (void)strcpy(&argv[0][2], __DEFPATH);
2010 /* If -q doesn't have an argument, run it once. */
2011 if (ap[1] == 'q' && ap[2] == '\0')
2014 /* if -d doesn't have an argument, use 0-99.1 */
2015 if (ap[1] == 'd' && ap[2] == '\0')
2018 # if defined(sony_news)
2019 /* if -E doesn't have an argument, use -EC */
2020 if (ap[1] == 'E' && ap[2] == '\0')
2023 /* if -J doesn't have an argument, use -JJ */
2024 if (ap[1] == 'J' && ap[2] == '\0')
2030 ** AUTH_WARNING -- specify authorization warning
2033 ** e -- the current envelope.
2034 ** msg -- the text of the message.
2035 ** args -- arguments to the message.
2043 auth_warning(register ENVELOPE *e, const char *msg, ...)
2045 auth_warning(e, msg, va_alist)
2046 register ENVELOPE *e;
2054 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
2057 static char hostbuf[48];
2058 extern struct hostent *myhostname __P((char *, int));
2060 if (hostbuf[0] == '\0')
2061 (void) myhostname(hostbuf, sizeof hostbuf);
2063 (void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
2064 p = &buf[strlen(buf)];
2066 vsnprintf(p, SPACELEFT(buf, p), msg, ap);
2068 addheader("X-Authentication-Warning", buf, &e->e_header);
2070 sm_syslog(LOG_INFO, e->e_id,
2071 "Authentication-Warning: %.400s",
2076 ** GETEXTENV -- get from external environment
2079 ** envar -- the name of the variable to retrieve
2082 ** The value, if any.
2093 for (envp = ExternalEnviron; *envp != NULL; envp++)
2095 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
2096 return &(*envp)[l + 1];
2101 ** SETUSERENV -- set an environment in the propogated environment
2104 ** envar -- the name of the environment variable.
2105 ** value -- the value to which it should be set. If
2106 ** null, this is extracted from the incoming
2107 ** environment. If that is not set, the call
2108 ** to setuserenv is ignored.
2115 setuserenv(envar, value)
2120 char **evp = UserEnviron;
2125 value = getextenv(envar);
2131 p = (char *) xalloc(strlen(value) + i + 2);
2134 strcpy(&p[i], value);
2136 while (*evp != NULL && strncmp(*evp, p, i) != 0)
2142 else if (evp < &UserEnviron[MAXUSERENVIRON])
2148 /* make sure it is in our environment as well */
2150 syserr("setuserenv: putenv(%s) failed", p);
2153 ** DUMPSTATE -- dump state
2162 register char *j = macvalue('j', CurEnv);
2165 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2166 "--- dumping state on %s: $j = %s ---",
2168 j == NULL ? "<NULL>" : j);
2171 if (!wordinclass(j, 'w'))
2172 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2173 "*** $j not in $=w ***");
2175 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
2176 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
2178 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
2180 rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
2184 register char **pvp;
2185 char *pv[MAXATOM + 1];
2188 stat = rewrite(pv, rs, 0, CurEnv);
2189 sm_syslog(LOG_DEBUG, CurEnv->e_id,
2190 "--- ruleset debug_dumpstate returns stat %d, pv: ---",
2192 for (pvp = pv; *pvp != NULL; pvp++)
2193 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
2195 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
2204 dumpstate("user signal");
2205 return SIGFUNC_RETURN;
2214 if (SaveArgv[0][0] != '/')
2217 sm_syslog(LOG_INFO, NOQID, "could not restart: need full path");
2218 finis(FALSE, EX_OSFILE);
2221 sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]);
2223 releasesignal(SIGHUP);
2224 closecontrolsocket(TRUE);
2225 if (drop_privileges(TRUE) != EX_OK)
2228 sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m",
2229 RunAsUid, RunAsGid);
2230 finis(FALSE, EX_OSERR);
2232 execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
2234 sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]);
2235 finis(FALSE, EX_OSFILE);
2238 ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
2241 ** to_real_uid -- if set, drop to the real uid instead
2242 ** of the RunAsUser.
2245 ** EX_OSERR if the setuid failed.
2250 drop_privileges(to_real_uid)
2254 GIDSET_T emptygidset[1];
2257 printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
2258 (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
2262 RunAsUserName = RealUserName;
2267 /* make sure no one can grab open descriptors for secret files */
2270 /* reset group permissions; these can be set later */
2271 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
2272 if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
2275 /* reset primary group and user id */
2276 if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
2278 if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
2282 printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
2283 (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
2284 printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
2289 ** FILL_FD -- make sure a file descriptor has been properly allocated
2291 ** Used to make sure that stdin/out/err are allocated on startup
2294 ** fd -- the file descriptor to be filled.
2295 ** where -- a string used for logging. If NULL, this is
2296 ** being called on startup, and logging should
2311 if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
2315 syserr("fill_fd: %s: fd %d not open", where, fd);
2317 MissingFds |= 1 << fd;
2318 i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
2321 syserr("!fill_fd: %s: cannot open /dev/null",
2322 where == NULL ? "startup" : where);
2331 ** TESTMODELINE -- process a test mode input line
2334 ** line -- the input line.
2335 ** e -- the current environment.
2338 ** .X process X as a configuration line
2339 ** =X dump a configuration item (such as mailers)
2340 ** $X dump a macro or class
2341 ** /X try an activity
2342 ** X normal process through rule set X
2346 testmodeline(line, e)
2352 auto char *delimptr;
2359 static int tryflags = RF_COPYNONE;
2360 char exbuf[MAXLINE];
2361 extern bool invalidaddr __P((char *, char *));
2362 extern char *crackaddr __P((char *));
2363 extern void dump_class __P((STAB *, int));
2364 extern void translate_dollars __P((char *));
2365 extern void help __P((char *));
2377 case '.': /* config-style settings */
2381 mid = macid(&line[2], &delimptr);
2384 translate_dollars(delimptr);
2385 define(mid, newstr(delimptr), e);
2389 if (line[2] == '\0') /* not to call syserr() */
2392 mid = macid(&line[2], &delimptr);
2395 translate_dollars(delimptr);
2396 expand(delimptr, exbuf, sizeof exbuf, e);
2403 while (*p != '\0' && isascii(*p) && isspace(*p))
2406 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2417 printf("Usage: .[DC]macro value(s)\n");
2421 printf("Unknown \".\" command %s\n", line);
2426 case '=': /* config-style settings */
2429 case 'S': /* dump rule set */
2430 rs = strtorwset(&line[2], NULL, ST_FIND);
2433 printf("Undefined ruleset %s\n", &line[2]);
2436 rw = RewriteRules[rs];
2457 } while ((rw = rw->r_next) != NULL);
2461 for (i = 0; i < MAXMAILERS; i++)
2463 if (Mailer[i] != NULL)
2464 printmailer(Mailer[i]);
2469 printf("Usage: =Sruleset or =M\n");
2473 printf("Unknown \"=\" command %s\n", line);
2478 case '-': /* set command-line-like opts */
2486 printf("Usage: -d{debug arguments}\n");
2490 printf("Unknown \"-\" command %s\n", line);
2498 mid = macid(&line[2], NULL);
2500 stabapply(dump_class, mid);
2503 mid = macid(&line[1], NULL);
2506 p = macvalue(mid, e);
2508 printf("Undefined\n");
2516 case '/': /* miscellaneous commands */
2517 p = &line[strlen(line)];
2518 while (--p >= line && isascii(*p) && isspace(*p))
2520 p = strpbrk(line, " \t");
2523 while (isascii(*p) && isspace(*p))
2528 if (line[1] == '\0')
2530 printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
2533 if (strcasecmp(&line[1], "mx") == 0)
2536 /* look up MX records */
2539 char *mxhosts[MAXMXHOSTS + 1];
2543 printf("Usage: /mx address\n");
2546 nmx = getmxrr(p, mxhosts, FALSE, &rcode);
2547 printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
2548 for (i = 0; i < nmx; i++)
2549 printf("\t%s\n", mxhosts[i]);
2551 printf("No MX code compiled in\n");
2554 else if (strcasecmp(&line[1], "canon") == 0)
2556 char host[MAXHOSTNAMELEN];
2560 printf("Usage: /canon address\n");
2563 else if (strlen(p) >= sizeof host)
2565 printf("Name too long\n");
2569 (void) getcanonname(host, sizeof(host), HasWildcardMX);
2570 printf("getcanonname(%s) returns %s\n", p, host);
2572 else if (strcasecmp(&line[1], "map") == 0)
2574 auto int rcode = EX_OK;
2579 printf("Usage: /map mapname key\n");
2582 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
2586 printf("No key specified\n");
2590 map = stab(p, ST_MAP, ST_FIND);
2593 printf("Map named \"%s\" not found\n", p);
2596 if (!bitset(MF_OPEN, map->s_map.map_mflags))
2598 printf("Map named \"%s\" not open\n", p);
2601 printf("map_lookup: %s (%s) ", p, q);
2604 p = (*map->s_map.map_class->map_lookup)
2605 (&map->s_map, q, av, &rcode);
2607 printf("no match (%d)\n", rcode);
2609 printf("returns %s (%d)\n", p, rcode);
2611 else if (strcasecmp(&line[1], "try") == 0)
2615 auto int rcode = EX_OK;
2617 q = strpbrk(p, " \t");
2620 while (isascii(*q) && isspace(*q))
2623 if (q == NULL || *q == '\0')
2625 printf("Usage: /try mailer address\n");
2628 s = stab(p, ST_MAILER, ST_FIND);
2631 printf("Unknown mailer %s\n", p);
2635 printf("Trying %s %s address %s for mailer %s\n",
2636 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2637 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
2639 p = remotename(q, m, tryflags, &rcode, CurEnv);
2640 printf("Rcode = %d, addr = %s\n",
2641 rcode, p == NULL ? "<NULL>" : p);
2644 else if (strcasecmp(&line[1], "tryflags") == 0)
2648 printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
2651 for (; *p != '\0'; p++)
2657 tryflags |= RF_HEADERADDR;
2662 tryflags &= ~RF_HEADERADDR;
2667 tryflags |= RF_SENDERADDR;
2672 tryflags &= ~RF_SENDERADDR;
2677 else if (strcasecmp(&line[1], "parse") == 0)
2681 printf("Usage: /parse address\n");
2685 printf("Cracked address = ");
2687 printf("\nParsing %s %s address\n",
2688 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2689 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
2690 if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
2691 printf("Cannot parse\n");
2692 else if (a.q_host != NULL && a.q_host[0] != '\0')
2693 printf("mailer %s, host %s, user %s\n",
2694 a.q_mailer->m_name, a.q_host, a.q_user);
2696 printf("mailer %s, user %s\n",
2697 a.q_mailer->m_name, a.q_user);
2702 printf("Unknown \"/\" command %s\n", line);
2707 for (p = line; isascii(*p) && isspace(*p); p++)
2710 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2714 printf("No address!\n");
2718 if (invalidaddr(p + 1, NULL))
2722 register char **pvp;
2723 char pvpbuf[PSBUFSIZE];
2725 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
2734 rs = strtorwset(p, NULL, ST_FIND);
2737 printf("Undefined ruleset %s\n", p);
2740 stat = rewrite(pvp, rs, 0, e);
2742 printf("== Ruleset %s (%d) status %d\n",
2744 while (*p != '\0' && *p++ != ',')
2747 } while (*(p = delimptr) != '\0');
2756 if (s->s_type != ST_CLASS)
2758 if (bitnset(id & 0xff, s->s_class))
2759 printf("%s\n", s->s_name);