main.c
Upload User: xu_441
Upload Date: 2007-01-04
Package Size: 1640k
Code Size: 67k
Category:

Email Client

Development Platform:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char copyright[] =
  15. "@(#) Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.n
  16. All rights reserved.n
  17.      Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.n
  18.      Copyright (c) 1988, 1993n
  19. The Regents of the University of California.  All rights reserved.n";
  20. #endif /* ! lint */
  21. #ifndef lint
  22. static char id[] = "@(#)$Id: main.c,v 8.469 1999/11/24 08:44:36 gshapiro Exp $";
  23. #endif /* ! lint */
  24. #define _DEFINE
  25. #include <sendmail.h>
  26. #if NETINET || NETINET6
  27. # include <arpa/inet.h>
  28. #endif /* NETINET || NETINET6 */
  29. static void dump_class __P((STAB *, int));
  30. static void obsolete __P((char **));
  31. static void testmodeline __P((char *, ENVELOPE *));
  32. /*
  33. **  SENDMAIL -- Post mail to a set of destinations.
  34. **
  35. ** This is the basic mail router.  All user mail programs should
  36. ** call this routine to actually deliver mail.  Sendmail in
  37. ** turn calls a bunch of mail servers that do the real work of
  38. ** delivering the mail.
  39. **
  40. ** Sendmail is driven by settings read in from /etc/mail/sendmail.cf
  41. ** (read by readcf.c).
  42. **
  43. ** Usage:
  44. ** /usr/lib/sendmail [flags] addr ...
  45. **
  46. ** See the associated documentation for details.
  47. **
  48. ** Author:
  49. ** Eric Allman, UCB/INGRES (until 10/81).
  50. **      Britton-Lee, Inc., purveyors of fine
  51. ** database computers (11/81 - 10/88).
  52. **      International Computer Science Institute
  53. ** (11/88 - 9/89).
  54. **      UCB/Mammoth Project (10/89 - 7/95).
  55. **      InReference, Inc. (8/95 - 1/97).
  56. **      Sendmail, Inc. (1/98 - present).
  57. ** The support of the my employers is gratefully acknowledged.
  58. ** Few of them (Britton-Lee in particular) have had
  59. ** anything to gain from my involvement in this project.
  60. */
  61. int NextMailer; /* "free" index into Mailer struct */
  62. char *FullName; /* sender's full name */
  63. ENVELOPE BlankEnvelope; /* a "blank" envelope */
  64. static ENVELOPE MainEnvelope; /* the envelope around the basic letter */
  65. ADDRESS NullAddress = /* a null address */
  66. { "", "", NULL, "" };
  67. char *CommandLineArgs; /* command line args for pid file */
  68. bool Warn_Q_option = FALSE; /* warn about Q option use */
  69. char **SaveArgv; /* argument vector for re-execing */
  70. static int MissingFds = 0; /* bit map of fds missing on startup */
  71. #ifdef NGROUPS_MAX
  72. GIDSET_T InitialGidSet[NGROUPS_MAX];
  73. #endif /* NGROUPS_MAX */
  74. #if DAEMON && !SMTP
  75. ERROR %%%%   Cannot have DAEMON mode without SMTP   %%%% ERROR
  76. #endif /* DAEMON && !SMTP */
  77. #if SMTP && !QUEUE
  78. ERROR %%%%   Cannot have SMTP mode without QUEUE   %%%% ERROR
  79. #endif /* SMTP && !QUEUE */
  80. #define MAXCONFIGLEVEL 9 /* highest config version level known */
  81. /* Flags for submitmode */
  82. #define SUBMIT_UNKNOWN 0x0000 /* unknown agent type */
  83. #define SUBMIT_MTA 0x0001 /* act like a message transfer agent */
  84. #define SUBMIT_MSA 0x0002 /* act like a message submission agent */
  85. #if SASL
  86. static sasl_callback_t srvcallbacks[] = {
  87. { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
  88. { SASL_CB_PROXY_POLICY, &proxy_policy, NULL },
  89. { SASL_CB_LIST_END, NULL, NULL }
  90. };
  91. #endif /* SASL */
  92. int
  93. main(argc, argv, envp)
  94. int argc;
  95. char **argv;
  96. char **envp;
  97. {
  98. register char *p;
  99. char **av;
  100. extern char Version[];
  101. char *ep, *from;
  102. STAB *st;
  103. register int i;
  104. int j;
  105. int submitmode = SUBMIT_UNKNOWN;
  106. bool safecf = TRUE;
  107. BITMAP256 *p_flags = NULL; /* daemon flags */
  108. bool warn_C_flag = FALSE;
  109. bool auth = TRUE; /* whether to set e_auth_param */
  110. char warn_f_flag = '';
  111. bool run_in_foreground = FALSE; /* -bD mode */
  112. static bool reenter = FALSE;
  113. struct passwd *pw;
  114. struct hostent *hp;
  115. char *nullserver = NULL;
  116. char *authinfo = NULL;
  117. char *sysloglabel = NULL; /* label for syslog */
  118. bool forged;
  119. struct stat traf_st; /* for TrafficLog FIFO check */
  120. char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
  121. static char rnamebuf[MAXNAME]; /* holds RealUserName */
  122. char *emptyenviron[1];
  123. QUEUE_CHAR *new;
  124. extern int DtableSize;
  125. extern int optind;
  126. extern int opterr;
  127. extern char *optarg;
  128. extern char **environ;
  129. /*
  130. **  Check to see if we reentered.
  131. ** This would normally happen if e_putheader or e_putbody
  132. ** were NULL when invoked.
  133. */
  134. if (reenter)
  135. {
  136. syserr("main: reentered!");
  137. abort();
  138. }
  139. reenter = TRUE;
  140. /* avoid null pointer dereferences */
  141. TermEscape.te_rv_on = TermEscape.te_rv_off = "";
  142. /* do machine-dependent initializations */
  143. init_md(argc, argv);
  144. /* in 4.4BSD, the table can be huge; impose a reasonable limit */
  145. DtableSize = getdtsize();
  146. if (DtableSize > 256)
  147. DtableSize = 256;
  148. /*
  149. **  Be sure we have enough file descriptors.
  150. ** But also be sure that 0, 1, & 2 are open.
  151. */
  152. fill_fd(STDIN_FILENO, NULL);
  153. fill_fd(STDOUT_FILENO, NULL);
  154. fill_fd(STDERR_FILENO, NULL);
  155. i = DtableSize;
  156. while (--i > 0)
  157. {
  158. if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
  159. (void) close(i);
  160. }
  161. errno = 0;
  162. #if LOG
  163. # ifdef LOG_MAIL
  164. openlog("sendmail", LOG_PID, LOG_MAIL);
  165. # else /* LOG_MAIL */
  166. openlog("sendmail", LOG_PID);
  167. # endif /* LOG_MAIL */
  168. #endif /* LOG */
  169. if (MissingFds != 0)
  170. {
  171. char mbuf[MAXLINE];
  172. mbuf[0] = '';
  173. if (bitset(1 << STDIN_FILENO, MissingFds))
  174. (void) strlcat(mbuf, ", stdin", sizeof mbuf);
  175. if (bitset(1 << STDOUT_FILENO, MissingFds))
  176. (void) strlcat(mbuf, ", stdout", sizeof mbuf);
  177. if (bitset(1 << STDERR_FILENO, MissingFds))
  178. (void) strlcat(mbuf, ", stderr", sizeof mbuf);
  179. syserr("File descriptors missing on startup: %s", &mbuf[2]);
  180. }
  181. /* reset status from syserr() calls for missing file descriptors */
  182. Errors = 0;
  183. ExitStat = EX_OK;
  184. #if XDEBUG
  185. checkfd012("after openlog");
  186. #endif /* XDEBUG */
  187. /*
  188. **  Seed the random number generator.
  189. **  Used for queue file names, picking a queue directory, and
  190. **  MX randomization.
  191. */
  192. seed_random();
  193. tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
  194. #ifdef NGROUPS_MAX
  195. /* save initial group set for future checks */
  196. i = getgroups(NGROUPS_MAX, InitialGidSet);
  197. if (i == 0)
  198. InitialGidSet[0] = (GID_T) -1;
  199. while (i < NGROUPS_MAX)
  200. InitialGidSet[i++] = InitialGidSet[0];
  201. #endif /* NGROUPS_MAX */
  202. /* drop group id privileges (RunAsUser not yet set) */
  203. (void) drop_privileges(FALSE);
  204. #ifdef SIGUSR1
  205. /* arrange to dump state on user-1 signal */
  206. (void) setsignal(SIGUSR1, sigusr1);
  207. #endif /* SIGUSR1 */
  208. /* initialize for setproctitle */
  209. initsetproctitle(argc, argv, envp);
  210. /* Handle any non-getoptable constructions. */
  211. obsolete(argv);
  212. /*
  213. **  Do a quick prescan of the argument list.
  214. */
  215. #if defined(__osf__) || defined(_AIX3)
  216. # define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x"
  217. #endif /* defined(__osf__) || defined(_AIX3) */
  218. #if defined(sony_news)
  219. # define OPTIONS "B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
  220. #endif /* defined(sony_news) */
  221. #ifndef OPTIONS
  222. # define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
  223. #endif /* ! OPTIONS */
  224. opterr = 0;
  225. while ((j = getopt(argc, argv, OPTIONS)) != -1)
  226. {
  227. switch (j)
  228. {
  229.   case 'd':
  230. /* hack attack -- see if should use ANSI mode */
  231. if (strcmp(optarg, "ANSI") == 0)
  232. {
  233. TermEscape.te_rv_on = "33[7m";
  234. TermEscape.te_rv_off = "33[0m";
  235. break;
  236. }
  237. tTflag(optarg);
  238. setbuf(stdout, (char *) NULL);
  239. break;
  240.   case 'L':
  241. sysloglabel = optarg;
  242. break;
  243. }
  244. }
  245. opterr = 1;
  246. if (sysloglabel != NULL)
  247. {
  248. if (strlen(sysloglabel) > 24)
  249. sysloglabel[24] = '';
  250. #if LOG
  251. closelog();
  252. # ifdef LOG_MAIL
  253. openlog(sysloglabel, LOG_PID, LOG_MAIL);
  254. # else /* LOG_MAIL */
  255. openlog(sysloglabel, LOG_PID);
  256. # endif /* LOG_MAIL */
  257. #endif /* LOG */
  258. }
  259. /* set up the blank envelope */
  260. BlankEnvelope.e_puthdr = putheader;
  261. BlankEnvelope.e_putbody = putbody;
  262. BlankEnvelope.e_xfp = NULL;
  263. STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
  264. CurEnv = &BlankEnvelope;
  265. STRUCTCOPY(NullAddress, MainEnvelope.e_from);
  266. /*
  267. **  Set default values for variables.
  268. ** These cannot be in initialized data space.
  269. */
  270. setdefaults(&BlankEnvelope);
  271. RealUid = getuid();
  272. RealGid = getgid();
  273. pw = sm_getpwuid(RealUid);
  274. if (pw != NULL)
  275. (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
  276. else
  277. (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
  278. (int) RealUid);
  279. RealUserName = rnamebuf;
  280. if (tTd(0, 101))
  281. {
  282. dprintf("Version %sn", Version);
  283. finis(FALSE, EX_OK);
  284. }
  285. /*
  286. **  if running non-setuid binary as non-root, pretend
  287. **  we are the RunAsUid
  288. */
  289. if (RealUid != 0 && geteuid() == RealUid)
  290. {
  291. if (tTd(47, 1))
  292. dprintf("Non-setuid binary: RunAsUid = RealUid = %dn",
  293. (int)RealUid);
  294. RunAsUid = RealUid;
  295. }
  296. else if (geteuid() != 0)
  297. RunAsUid = geteuid();
  298. if (RealUid != 0 && getegid() == RealGid)
  299. RunAsGid = RealGid;
  300. if (tTd(47, 5))
  301. {
  302. dprintf("main: e/ruid = %d/%d e/rgid = %d/%dn",
  303. (int)geteuid(), (int)getuid(),
  304. (int)getegid(), (int)getgid());
  305. dprintf("main: RunAsUser = %d:%dn",
  306. (int)RunAsUid, (int)RunAsGid);
  307. }
  308. /* save command line arguments */
  309. j = 0;
  310. for (av = argv; *av != NULL; )
  311. j += strlen(*av++) + 1;
  312. SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
  313. CommandLineArgs = xalloc(j);
  314. p = CommandLineArgs;
  315. for (av = argv, i = 0; *av != NULL; )
  316. {
  317. int h;
  318. SaveArgv[i++] = newstr(*av);
  319. if (av != argv)
  320. *p++ = ' ';
  321. (void) strlcpy(p, *av++, j);
  322. h = strlen(p);
  323. p += h;
  324. j -= h + 1;
  325. }
  326. SaveArgv[i] = NULL;
  327. if (tTd(0, 1))
  328. {
  329. int ll;
  330. extern char *CompileOptions[];
  331. dprintf("Version %sn Compiled with:", Version);
  332. av = CompileOptions;
  333. ll = 7;
  334. while (*av != NULL)
  335. {
  336. if (ll + strlen(*av) > 63)
  337. {
  338. dprintf("n");
  339. ll = 0;
  340. }
  341. if (ll == 0)
  342. dprintf("tt");
  343. else
  344. dprintf(" ");
  345. dprintf("%s", *av);
  346. ll += strlen(*av++) + 1;
  347. }
  348. dprintf("n");
  349. }
  350. if (tTd(0, 10))
  351. {
  352. int ll;
  353. extern char *OsCompileOptions[];
  354. dprintf("    OS Defines:");
  355. av = OsCompileOptions;
  356. ll = 7;
  357. while (*av != NULL)
  358. {
  359. if (ll + strlen(*av) > 63)
  360. {
  361. dprintf("n");
  362. ll = 0;
  363. }
  364. if (ll == 0)
  365. dprintf("tt");
  366. else
  367. dprintf(" ");
  368. dprintf("%s", *av);
  369. ll += strlen(*av++) + 1;
  370. }
  371. dprintf("n");
  372. #ifdef _PATH_UNIX
  373. dprintf("Kernel symbols:t%sn", _PATH_UNIX);
  374. #endif /* _PATH_UNIX */
  375. dprintf(" Def Conf file:t%sn", getcfname());
  376. dprintf("  Def Pid file:t%sn", PidFile);
  377. }
  378. InChannel = stdin;
  379. OutChannel = stdout;
  380. /* clear sendmail's environment */
  381. ExternalEnviron = environ;
  382. emptyenviron[0] = NULL;
  383. environ = emptyenviron;
  384. /*
  385. **  restore any original TZ setting until TimeZoneSpec has been
  386. **  determined - or early log messages may get bogus time stamps
  387. */
  388. if ((p = getextenv("TZ")) != NULL)
  389. {
  390. char *tz;
  391. int tzlen;
  392. tzlen = strlen(p) + 4;
  393. tz = xalloc(tzlen);
  394. (void) snprintf(tz, tzlen, "TZ=%s", p);
  395. (void) putenv(tz);
  396. }
  397. /* prime the child environment */
  398. setuserenv("AGENT", "sendmail");
  399. if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
  400. (void) setsignal(SIGINT, intsig);
  401. (void) setsignal(SIGTERM, intsig);
  402. (void) setsignal(SIGPIPE, SIG_IGN);
  403. OldUmask = umask(022);
  404. OpMode = MD_DELIVER;
  405. FullName = getextenv("NAME");
  406. /*
  407. **  Initialize name server if it is going to be used.
  408. */
  409. #if NAMED_BIND
  410. if (!bitset(RES_INIT, _res.options))
  411. (void) res_init();
  412. if (tTd(8, 8))
  413. _res.options |= RES_DEBUG;
  414. else
  415. _res.options &= ~RES_DEBUG;
  416. # ifdef RES_NOALIASES
  417. _res.options |= RES_NOALIASES;
  418. # endif /* RES_NOALIASES */
  419. TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
  420. TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
  421. TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
  422. TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
  423. TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
  424. TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
  425. #endif /* NAMED_BIND */
  426. errno = 0;
  427. from = NULL;
  428. /* initialize some macros, etc. */
  429. initmacros(CurEnv);
  430. init_vendor_macros(CurEnv);
  431. /* version */
  432. define('v', Version, CurEnv);
  433. /* hostname */
  434. hp = myhostname(jbuf, sizeof jbuf);
  435. if (jbuf[0] != '')
  436. {
  437. struct utsname utsname;
  438. if (tTd(0, 4))
  439. dprintf("canonical name: %sn", jbuf);
  440. define('w', newstr(jbuf), CurEnv); /* must be new string */
  441. define('j', newstr(jbuf), CurEnv);
  442. setclass('w', jbuf);
  443. p = strchr(jbuf, '.');
  444. if (p != NULL)
  445. {
  446. if (p[1] != '')
  447. {
  448. define('m', newstr(&p[1]), CurEnv);
  449. }
  450. while (p != NULL && strchr(&p[1], '.') != NULL)
  451. {
  452. *p = '';
  453. if (tTd(0, 4))
  454. dprintf("ta.k.a.: %sn", jbuf);
  455. setclass('w', jbuf);
  456. *p++ = '.';
  457. p = strchr(p, '.');
  458. }
  459. }
  460. if (uname(&utsname) >= 0)
  461. p = utsname.nodename;
  462. else
  463. {
  464. if (tTd(0, 22))
  465. dprintf("uname failed (%s)n",
  466. errstring(errno));
  467. makelower(jbuf);
  468. p = jbuf;
  469. }
  470. if (tTd(0, 4))
  471. dprintf(" UUCP nodename: %sn", p);
  472. p = newstr(p);
  473. define('k', p, CurEnv);
  474. setclass('k', p);
  475. setclass('w', p);
  476. }
  477. if (hp != NULL)
  478. {
  479. for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
  480. {
  481. if (tTd(0, 4))
  482. dprintf("ta.k.a.: %sn", *av);
  483. setclass('w', *av);
  484. }
  485. #if NETINET || NETINET6
  486. for (i = 0; hp->h_addr_list[i] != NULL; i++)
  487. {
  488. # if NETINET6
  489. char *addr;
  490. char buf6[INET6_ADDRSTRLEN];
  491. struct in6_addr ia6;
  492. # endif /* NETINET6 */
  493. # if NETINET
  494. struct in_addr ia;
  495. # endif /* NETINET */
  496. char ipbuf[103];
  497. ipbuf[0] = '';
  498. switch (hp->h_addrtype)
  499. {
  500. # if NETINET
  501.   case AF_INET:
  502. if (hp->h_length != INADDRSZ)
  503. break;
  504. memmove(&ia, hp->h_addr_list[i], INADDRSZ);
  505. (void) snprintf(ipbuf,  sizeof ipbuf,
  506. "[%.100s]", inet_ntoa(ia));
  507. break;
  508. # endif /* NETINET */
  509. # if NETINET6
  510.   case AF_INET6:
  511. if (hp->h_length != IN6ADDRSZ)
  512. break;
  513. memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
  514. addr = anynet_ntop(&ia6, buf6, sizeof buf6);
  515. if (addr != NULL)
  516. (void) snprintf(ipbuf, sizeof ipbuf,
  517. "[%.100s]", addr);
  518. break;
  519. # endif /* NETINET6 */
  520. }
  521. if (ipbuf[0] == '')
  522. break;
  523. if (tTd(0, 4))
  524. dprintf("ta.k.a.: %sn", ipbuf);
  525. setclass('w', ipbuf);
  526. }
  527. #endif /* NETINET || NETINET6 */
  528. }
  529. /* current time */
  530. define('b', arpadate((char *) NULL), CurEnv);
  531. /* current load average */
  532. CurrentLA = sm_getla(CurEnv);
  533. QueueLimitRecipient = (QUEUE_CHAR *) NULL;
  534. QueueLimitSender = (QUEUE_CHAR *) NULL;
  535. QueueLimitId = (QUEUE_CHAR *) NULL;
  536. /*
  537. **  Crack argv.
  538. */
  539. av = argv;
  540. p = strrchr(*av, '/');
  541. if (p++ == NULL)
  542. p = *av;
  543. if (strcmp(p, "newaliases") == 0)
  544. OpMode = MD_INITALIAS;
  545. else if (strcmp(p, "mailq") == 0)
  546. OpMode = MD_PRINT;
  547. else if (strcmp(p, "smtpd") == 0)
  548. OpMode = MD_DAEMON;
  549. else if (strcmp(p, "hoststat") == 0)
  550. OpMode = MD_HOSTSTAT;
  551. else if (strcmp(p, "purgestat") == 0)
  552. OpMode = MD_PURGESTAT;
  553. optind = 1;
  554. while ((j = getopt(argc, argv, OPTIONS)) != -1)
  555. {
  556. switch (j)
  557. {
  558.   case 'b': /* operations mode */
  559. switch (j = *optarg)
  560. {
  561.   case MD_DAEMON:
  562.   case MD_FGDAEMON:
  563. #if !DAEMON
  564. usrerr("Daemon mode not implemented");
  565. ExitStat = EX_USAGE;
  566. break;
  567. #endif /* !DAEMON */
  568.   case MD_SMTP:
  569. #if !SMTP
  570. usrerr("I don't speak SMTP");
  571. ExitStat = EX_USAGE;
  572. break;
  573. #endif /* !SMTP */
  574.   case MD_INITALIAS:
  575.   case MD_DELIVER:
  576.   case MD_VERIFY:
  577.   case MD_TEST:
  578.   case MD_PRINT:
  579.   case MD_HOSTSTAT:
  580.   case MD_PURGESTAT:
  581.   case MD_ARPAFTP:
  582. OpMode = j;
  583. break;
  584.   case MD_FREEZE:
  585. usrerr("Frozen configurations unsupported");
  586. ExitStat = EX_USAGE;
  587. break;
  588.   default:
  589. usrerr("Invalid operation mode %c", j);
  590. ExitStat = EX_USAGE;
  591. break;
  592. }
  593. break;
  594.   case 'B': /* body type */
  595. CurEnv->e_bodytype = optarg;
  596. break;
  597.   case 'C': /* select configuration file (already done) */
  598. if (RealUid != 0)
  599. warn_C_flag = TRUE;
  600. ConfFile = optarg;
  601. (void) drop_privileges(TRUE);
  602. safecf = FALSE;
  603. break;
  604.   case 'd': /* debugging -- already done */
  605. break;
  606.   case 'f': /* from address */
  607.   case 'r': /* obsolete -f flag */
  608. if (from != NULL)
  609. {
  610. usrerr("More than one "from" person");
  611. ExitStat = EX_USAGE;
  612. break;
  613. }
  614. from = newstr(denlstring(optarg, TRUE, TRUE));
  615. if (strcmp(RealUserName, from) != 0)
  616. warn_f_flag = j;
  617. break;
  618.   case 'F': /* set full name */
  619. FullName = newstr(optarg);
  620. break;
  621.   case 'G': /* relay (gateway) submission */
  622. submitmode |= SUBMIT_MTA;
  623. break;
  624.   case 'h': /* hop count */
  625. CurEnv->e_hopcount = strtol(optarg, &ep, 10);
  626. if (*ep)
  627. {
  628. usrerr("Bad hop count (%s)", optarg);
  629. ExitStat = EX_USAGE;
  630. }
  631. break;
  632.   case 'L': /* program label */
  633. /* already set */
  634. break;
  635.   case 'n': /* don't alias */
  636. NoAlias = TRUE;
  637. break;
  638.   case 'N': /* delivery status notifications */
  639. DefaultNotify |= QHASNOTIFY;
  640. if (strcasecmp(optarg, "never") == 0)
  641. break;
  642. for (p = optarg; p != NULL; optarg = p)
  643. {
  644. p = strchr(p, ',');
  645. if (p != NULL)
  646. *p++ = '';
  647. if (strcasecmp(optarg, "success") == 0)
  648. DefaultNotify |= QPINGONSUCCESS;
  649. else if (strcasecmp(optarg, "failure") == 0)
  650. DefaultNotify |= QPINGONFAILURE;
  651. else if (strcasecmp(optarg, "delay") == 0)
  652. DefaultNotify |= QPINGONDELAY;
  653. else
  654. {
  655. usrerr("Invalid -N argument");
  656. ExitStat = EX_USAGE;
  657. }
  658. }
  659. break;
  660.   case 'o': /* set option */
  661. setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
  662. break;
  663.   case 'O': /* set option (long form) */
  664. setoption(' ', optarg, FALSE, TRUE, CurEnv);
  665. break;
  666.   case 'p': /* set protocol */
  667. p = strchr(optarg, ':');
  668. if (p != NULL)
  669. {
  670. *p++ = '';
  671. if (*p != '')
  672. {
  673. ep = xalloc(strlen(p) + 1);
  674. cleanstrcpy(ep, p, MAXNAME);
  675. define('s', ep, CurEnv);
  676. }
  677. }
  678. if (*optarg != '')
  679. {
  680. ep = xalloc(strlen(optarg) + 1);
  681. cleanstrcpy(ep, optarg, MAXNAME);
  682. define('r', ep, CurEnv);
  683. }
  684. break;
  685.   case 'q': /* run queue files at intervals */
  686. #if QUEUE
  687. /* sanity check */
  688. if (OpMode != MD_DELIVER &&
  689.     OpMode != MD_DAEMON &&
  690.     OpMode != MD_FGDAEMON &&
  691.     OpMode != MD_PRINT &&
  692.     OpMode != MD_QUEUERUN)
  693. {
  694. usrerr("Can not use -q with -b%c", OpMode);
  695. ExitStat = EX_USAGE;
  696. break;
  697. }
  698. /* don't override -bd, -bD or -bp */
  699. if (OpMode == MD_DELIVER)
  700. OpMode = MD_QUEUERUN;
  701. FullName = NULL;
  702. switch (optarg[0])
  703. {
  704.   case 'I':
  705. new = (QUEUE_CHAR *) xalloc(sizeof *new);
  706. new->queue_match = newstr(&optarg[1]);
  707. new->queue_next = QueueLimitId;
  708. QueueLimitId = new;
  709. break;
  710.   case 'R':
  711. new = (QUEUE_CHAR *) xalloc(sizeof *new);
  712. new->queue_match = newstr(&optarg[1]);
  713. new->queue_next = QueueLimitRecipient;
  714. QueueLimitRecipient = new;
  715. break;
  716.   case 'S':
  717. new = (QUEUE_CHAR *) xalloc(sizeof *new);
  718. new->queue_match = newstr(&optarg[1]);
  719. new->queue_next = QueueLimitSender;
  720. QueueLimitSender = new;
  721. break;
  722.   default:
  723. i = Errors;
  724. QueueIntvl = convtime(optarg, 'm');
  725. /* check for bad conversion */
  726. if (i < Errors)
  727. ExitStat = EX_USAGE;
  728. break;
  729. }
  730. #else /* QUEUE */
  731. usrerr("I don't know about queues");
  732. ExitStat = EX_USAGE;
  733. #endif /* QUEUE */
  734. break;
  735.   case 'R': /* DSN RET: what to return */
  736. if (bitset(EF_RET_PARAM, CurEnv->e_flags))
  737. {
  738. usrerr("Duplicate -R flag");
  739. ExitStat = EX_USAGE;
  740. break;
  741. }
  742. CurEnv->e_flags |= EF_RET_PARAM;
  743. if (strcasecmp(optarg, "hdrs") == 0)
  744. CurEnv->e_flags |= EF_NO_BODY_RETN;
  745. else if (strcasecmp(optarg, "full") != 0)
  746. {
  747. usrerr("Invalid -R value");
  748. ExitStat = EX_USAGE;
  749. }
  750. define(macid("{dsn_ret}", NULL),
  751.        newstr(optarg), CurEnv);
  752. break;
  753.   case 't': /* read recipients from message */
  754. GrabTo = TRUE;
  755. break;
  756.   case 'U': /* initial (user) submission */
  757. submitmode |= SUBMIT_MSA;
  758. break;
  759.   case 'V': /* DSN ENVID: set "original" envelope id */
  760. if (!xtextok(optarg))
  761. {
  762. usrerr("Invalid syntax in -V flag");
  763. ExitStat = EX_USAGE;
  764. }
  765. else
  766. {
  767. CurEnv->e_envid = newstr(optarg);
  768. define(macid("{dsn_envid}", NULL),
  769.        newstr(optarg), CurEnv);
  770. }
  771. break;
  772.   case 'X': /* traffic log file */
  773. (void) drop_privileges(TRUE);
  774. if (stat(optarg, &traf_st) == 0 &&
  775.     S_ISFIFO(traf_st.st_mode))
  776. TrafficLogFile = fopen(optarg, "w");
  777. else
  778. TrafficLogFile = fopen(optarg, "a");
  779. if (TrafficLogFile == NULL)
  780. {
  781. syserr("cannot open %s", optarg);
  782. ExitStat = EX_CANTCREAT;
  783. break;
  784. }
  785. #if HASSETVBUF
  786. (void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
  787. #else /* HASSETVBUF */
  788. (void) setlinebuf(TrafficLogFile);
  789. #endif /* HASSETVBUF */
  790. break;
  791. /* compatibility flags */
  792.   case 'c': /* connect to non-local mailers */
  793.   case 'i': /* don't let dot stop me */
  794.   case 'm': /* send to me too */
  795.   case 'T': /* set timeout interval */
  796.   case 'v': /* give blow-by-blow description */
  797. setoption(j, "T", FALSE, TRUE, CurEnv);
  798. break;
  799.   case 'e': /* error message disposition */
  800.   case 'M': /* define macro */
  801. setoption(j, optarg, FALSE, TRUE, CurEnv);
  802. break;
  803.   case 's': /* save From lines in headers */
  804. setoption('f', "T", FALSE, TRUE, CurEnv);
  805. break;
  806. #ifdef DBM
  807.   case 'I': /* initialize alias DBM file */
  808. OpMode = MD_INITALIAS;
  809. break;
  810. #endif /* DBM */
  811. #if defined(__osf__) || defined(_AIX3)
  812.   case 'x': /* random flag that OSF/1 & AIX mailx passes */
  813. break;
  814. #endif /* defined(__osf__) || defined(_AIX3) */
  815. #if defined(sony_news)
  816.   case 'E':
  817.   case 'J': /* ignore flags for Japanese code conversion
  818.    implemented on Sony NEWS */
  819. break;
  820. #endif /* defined(sony_news) */
  821.   default:
  822. finis(TRUE, EX_USAGE);
  823. break;
  824. }
  825. }
  826. av += optind;
  827. if (bitset(SUBMIT_MTA, submitmode) &&
  828.     bitset(SUBMIT_MSA, submitmode))
  829. {
  830. /* sanity check */
  831. usrerr("Cannot use both -G and -U together");
  832. }
  833. else if (bitset(SUBMIT_MTA, submitmode))
  834. define(macid("{daemon_flags}", NULL), "CCf", CurEnv);
  835. else if (bitset(SUBMIT_MSA, submitmode))
  836. define(macid("{daemon_flags}", NULL), "cu", CurEnv);
  837. else
  838. {
  839. #if _FFR_DEFAULT_SUBMIT_TO_MSA
  840. define(macid("{daemon_flags}", NULL), "cu", CurEnv);
  841. #else /* _FFR_DEFAULT_SUBMIT_TO_MSA */
  842. /* EMPTY */
  843. #endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */
  844. }
  845. /*
  846. **  Do basic initialization.
  847. ** Read system control file.
  848. ** Extract special fields for local use.
  849. */
  850. /* set up ${opMode} for use in config file */
  851. {
  852. char mbuf[2];
  853. mbuf[0] = OpMode;
  854. mbuf[1] = '';
  855. define(MID_OPMODE, newstr(mbuf), CurEnv);
  856. }
  857. #if XDEBUG
  858. checkfd012("before readcf");
  859. #endif /* XDEBUG */
  860. vendor_pre_defaults(CurEnv);
  861. readcf(getcfname(), safecf, CurEnv);
  862. ConfigFileRead = TRUE;
  863. vendor_post_defaults(CurEnv);
  864. /* Enforce use of local time (null string overrides this) */
  865. if (TimeZoneSpec == NULL)
  866. unsetenv("TZ");
  867. else if (TimeZoneSpec[0] != '')
  868. setuserenv("TZ", TimeZoneSpec);
  869. else
  870. setuserenv("TZ", NULL);
  871. tzset();
  872. /* avoid denial-of-service attacks */
  873. resetlimits();
  874. if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
  875. {
  876. /* drop privileges -- daemon mode done after socket/bind */
  877. (void) drop_privileges(FALSE);
  878. }
  879. #if NAMED_BIND
  880. _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
  881. _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
  882. #endif /* NAMED_BIND */
  883. /*
  884. **  Find our real host name for future logging.
  885. */
  886. authinfo = getauthinfo(STDIN_FILENO, &forged);
  887. define('_', authinfo, CurEnv);
  888. /* suppress error printing if errors mailed back or whatever */
  889. if (CurEnv->e_errormode != EM_PRINT)
  890. HoldErrs = TRUE;
  891. /* set up the $=m class now, after .cf has a chance to redefine $m */
  892. expand("201m", jbuf, sizeof jbuf, CurEnv);
  893. setclass('m', jbuf);
  894. /* probe interfaces and locate any additional names */
  895. if (!DontProbeInterfaces)
  896. load_if_names();
  897. if (tTd(0, 1))
  898. {
  899. dprintf("n============ SYSTEM IDENTITY (after readcf) ============");
  900. dprintf("n      (short domain name) $w = ");
  901. xputs(macvalue('w', CurEnv));
  902. dprintf("n  (canonical domain name) $j = ");
  903. xputs(macvalue('j', CurEnv));
  904. dprintf("n         (subdomain name) $m = ");
  905. xputs(macvalue('m', CurEnv));
  906. dprintf("n              (node name) $k = ");
  907. xputs(macvalue('k', CurEnv));
  908. dprintf("n========================================================nn");
  909. }
  910. /*
  911. **  Do more command line checking -- these are things that
  912. **  have to modify the results of reading the config file.
  913. */
  914. /* process authorization warnings from command line */
  915. if (warn_C_flag)
  916. auth_warning(CurEnv, "Processed by %s with -C %s",
  917. RealUserName, ConfFile);
  918. if (Warn_Q_option && !wordinclass(RealUserName, 't'))
  919. auth_warning(CurEnv, "Processed from queue %s", QueueDir);
  920. /* check body type for legality */
  921. if (CurEnv->e_bodytype == NULL)
  922. /* EMPTY */
  923. /* nothing */ ;
  924. else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
  925. SevenBitInput = TRUE;
  926. else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
  927. SevenBitInput = FALSE;
  928. else
  929. {
  930. usrerr("Illegal body type %s", CurEnv->e_bodytype);
  931. CurEnv->e_bodytype = NULL;
  932. }
  933. /* tweak default DSN notifications */
  934. if (DefaultNotify == 0)
  935. DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
  936. /* be sure we don't pick up bogus HOSTALIASES environment variable */
  937. if (OpMode == MD_QUEUERUN && RealUid != 0)
  938. (void) unsetenv("HOSTALIASES");
  939. /* check for sane configuration level */
  940. if (ConfigLevel > MAXCONFIGLEVEL)
  941. {
  942. syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
  943. ConfigLevel, Version, MAXCONFIGLEVEL);
  944. }
  945. /* need MCI cache to have persistence */
  946. if (HostStatDir != NULL && MaxMciCache == 0)
  947. {
  948. HostStatDir = NULL;
  949. printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0n");
  950. }
  951. /* need HostStatusDir in order to have SingleThreadDelivery */
  952. if (SingleThreadDelivery && HostStatDir == NULL)
  953. {
  954. SingleThreadDelivery = FALSE;
  955. printf("Warning: HostStatusDirectory required for SingleThreadDeliveryn");
  956. }
  957. /* check for permissions */
  958. if ((OpMode == MD_DAEMON ||
  959.      OpMode == MD_FGDAEMON ||
  960.      OpMode == MD_PURGESTAT) &&
  961.     RealUid != 0 &&
  962.     RealUid != TrustedUid)
  963. {
  964. if (LogLevel > 1)
  965. sm_syslog(LOG_ALERT, NOQID,
  966.   "user %d attempted to %s",
  967.   RealUid,
  968.   OpMode != MD_PURGESTAT ? "run daemon"
  969.  : "purge host status");
  970. usrerr("Permission denied");
  971. finis(FALSE, EX_USAGE);
  972. }
  973. if (OpMode == MD_INITALIAS &&
  974.     RealUid != 0 &&
  975.     RealUid != TrustedUid &&
  976.     !wordinclass(RealUserName, 't'))
  977. {
  978. if (LogLevel > 1)
  979. sm_syslog(LOG_ALERT, NOQID,
  980.   "user %d attempted to rebuild the alias map",
  981.   RealUid);
  982. usrerr("Permission denied");
  983. finis(FALSE, EX_USAGE);
  984. }
  985. if (MeToo)
  986. BlankEnvelope.e_flags |= EF_METOO;
  987. switch (OpMode)
  988. {
  989.   case MD_TEST:
  990. /* don't have persistent host status in test mode */
  991. HostStatDir = NULL;
  992. if (Verbose == 0)
  993. Verbose = 2;
  994. CurEnv->e_errormode = EM_PRINT;
  995. HoldErrs = FALSE;
  996. break;
  997.   case MD_VERIFY:
  998. CurEnv->e_errormode = EM_PRINT;
  999. HoldErrs = FALSE;
  1000. /* arrange to exit cleanly on hangup signal */
  1001. if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
  1002. (void) setsignal(SIGHUP, intsig);
  1003. break;
  1004.   case MD_FGDAEMON:
  1005. run_in_foreground = TRUE;
  1006. OpMode = MD_DAEMON;
  1007. /* FALLTHROUGH */
  1008.   case MD_DAEMON:
  1009. vendor_daemon_setup(CurEnv);
  1010. /* remove things that don't make sense in daemon mode */
  1011. FullName = NULL;
  1012. GrabTo = FALSE;
  1013. /* arrange to restart on hangup signal */
  1014. if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
  1015. sm_syslog(LOG_WARNING, NOQID,
  1016.   "daemon invoked without full pathname; kill -1 won't work");
  1017. (void) setsignal(SIGHUP, sighup);
  1018. /* workaround: can't seem to release the signal in the parent */
  1019. (void) releasesignal(SIGHUP);
  1020. break;
  1021.   case MD_INITALIAS:
  1022. Verbose = 2;
  1023. CurEnv->e_errormode = EM_PRINT;
  1024. HoldErrs = FALSE;
  1025. /* FALLTHROUGH */
  1026.   default:
  1027. /* arrange to exit cleanly on hangup signal */
  1028. if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
  1029. (void) setsignal(SIGHUP, intsig);
  1030. break;
  1031. }
  1032. /* special considerations for FullName */
  1033. if (FullName != NULL)
  1034. {
  1035. char *full = NULL;
  1036. /* full names can't have newlines */
  1037. if (strchr(FullName, 'n') != NULL)
  1038. {
  1039. FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
  1040. }
  1041. /* check for characters that may have to be quoted */
  1042. if (!rfc822_string(FullName))
  1043. {
  1044. /*
  1045. **  Quote a full name with special characters
  1046. **  as a comment so crackaddr() doesn't destroy
  1047. **  the name portion of the address.
  1048. */
  1049. FullName = addquotes(FullName);
  1050. if (full != NULL)
  1051. free(full);
  1052. }
  1053. }
  1054. /* do heuristic mode adjustment */
  1055. if (Verbose)
  1056. {
  1057. /* turn off noconnect option */
  1058. setoption('c', "F", TRUE, FALSE, CurEnv);
  1059. /* turn on interactive delivery */
  1060. setoption('d', "", TRUE, FALSE, CurEnv);
  1061. }
  1062. #ifdef VENDOR_CODE
  1063. /* check for vendor mismatch */
  1064. if (VendorCode != VENDOR_CODE)
  1065. {
  1066. message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
  1067. getvendor(VENDOR_CODE), getvendor(VendorCode));
  1068. }
  1069. #endif /* VENDOR_CODE */
  1070. /* check for out of date configuration level */
  1071. if (ConfigLevel < MAXCONFIGLEVEL)
  1072. {
  1073. message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
  1074. Version, MAXCONFIGLEVEL, ConfigLevel);
  1075. }
  1076. if (ConfigLevel < 3)
  1077. {
  1078. UseErrorsTo = TRUE;
  1079. }
  1080. /* set options that were previous macros */
  1081. if (SmtpGreeting == NULL)
  1082. {
  1083. if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
  1084. SmtpGreeting = newstr(p);
  1085. else
  1086. SmtpGreeting = "201j Sendmail 201v ready at 201b";
  1087. }
  1088. if (UnixFromLine == NULL)
  1089. {
  1090. if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
  1091. UnixFromLine = newstr(p);
  1092. else
  1093. UnixFromLine = "From 201g  201d";
  1094. }
  1095. /* our name for SMTP codes */
  1096. expand("201j", jbuf, sizeof jbuf, CurEnv);
  1097. MyHostName = jbuf;
  1098. if (strchr(jbuf, '.') == NULL)
  1099. message("WARNING: local host name (%s) is not qualified; fix $j in config file",
  1100. jbuf);
  1101. /* make certain that this name is part of the $=w class */
  1102. setclass('w', MyHostName);
  1103. /* the indices of built-in mailers */
  1104. st = stab("local", ST_MAILER, ST_FIND);
  1105. if (st != NULL)
  1106. LocalMailer = st->s_mailer;
  1107. else if (OpMode != MD_TEST || !warn_C_flag)
  1108. syserr("No local mailer defined");
  1109. st = stab("prog", ST_MAILER, ST_FIND);
  1110. if (st == NULL)
  1111. syserr("No prog mailer defined");
  1112. else
  1113. {
  1114. ProgMailer = st->s_mailer;
  1115. clrbitn(M_MUSER, ProgMailer->m_flags);
  1116. }
  1117. st = stab("*file*", ST_MAILER, ST_FIND);
  1118. if (st == NULL)
  1119. syserr("No *file* mailer defined");
  1120. else
  1121. {
  1122. FileMailer = st->s_mailer;
  1123. clrbitn(M_MUSER, FileMailer->m_flags);
  1124. }
  1125. st = stab("*include*", ST_MAILER, ST_FIND);
  1126. if (st == NULL)
  1127. syserr("No *include* mailer defined");
  1128. else
  1129. InclMailer = st->s_mailer;
  1130. if (ConfigLevel < 6)
  1131. {
  1132. /* heuristic tweaking of local mailer for back compat */
  1133. if (LocalMailer != NULL)
  1134. {
  1135. setbitn(M_ALIASABLE, LocalMailer->m_flags);
  1136. setbitn(M_HASPWENT, LocalMailer->m_flags);
  1137. setbitn(M_TRYRULESET5, LocalMailer->m_flags);
  1138. setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
  1139. setbitn(M_CHECKPROG, LocalMailer->m_flags);
  1140. setbitn(M_CHECKFILE, LocalMailer->m_flags);
  1141. setbitn(M_CHECKUDB, LocalMailer->m_flags);
  1142. }
  1143. if (ProgMailer != NULL)
  1144. setbitn(M_RUNASRCPT, ProgMailer->m_flags);
  1145. if (FileMailer != NULL)
  1146. setbitn(M_RUNASRCPT, FileMailer->m_flags);
  1147. }
  1148. if (ConfigLevel < 7)
  1149. {
  1150. if (LocalMailer != NULL)
  1151. setbitn(M_VRFY250, LocalMailer->m_flags);
  1152. if (ProgMailer != NULL)
  1153. setbitn(M_VRFY250, ProgMailer->m_flags);
  1154. if (FileMailer != NULL)
  1155. setbitn(M_VRFY250, FileMailer->m_flags);
  1156. }
  1157. /* MIME Content-Types that cannot be transfer encoded */
  1158. setclass('n', "multipart/signed");
  1159. /* MIME message/xxx subtypes that can be treated as messages */
  1160. setclass('s', "rfc822");
  1161. /* MIME Content-Transfer-Encodings that can be encoded */
  1162. setclass('e', "7bit");
  1163. setclass('e', "8bit");
  1164. setclass('e', "binary");
  1165. #ifdef USE_B_CLASS
  1166. /* MIME Content-Types that should be treated as binary */
  1167. setclass('b', "image");
  1168. setclass('b', "audio");
  1169. setclass('b', "video");
  1170. setclass('b', "application/octet-stream");
  1171. #endif /* USE_B_CLASS */
  1172. /* MIME headers which have fields to check for overflow */
  1173. setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
  1174. setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
  1175. /* MIME headers to check for length overflow */
  1176. setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
  1177. /* MIME headers to check for overflow and rebalance */
  1178. setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
  1179. setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
  1180. setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
  1181. setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
  1182. setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
  1183. /* Macros to save in the qf file -- don't remove any */
  1184. setclass(macid("{persistentMacros}", NULL), "r");
  1185. setclass(macid("{persistentMacros}", NULL), "s");
  1186. setclass(macid("{persistentMacros}", NULL), "_");
  1187. setclass(macid("{persistentMacros}", NULL), "{if_addr}");
  1188. setclass(macid("{persistentMacros}", NULL), "{if_family}");
  1189. setclass(macid("{persistentMacros}", NULL), "{daemon_flags}");
  1190. setclass(macid("{persistentMacros}", NULL), "{client_flags}");
  1191. /* operate in queue directory */
  1192. if (QueueDir == NULL)
  1193. {
  1194. if (OpMode != MD_TEST)
  1195. {
  1196. syserr("QueueDirectory (Q) option must be set");
  1197. ExitStat = EX_CONFIG;
  1198. }
  1199. }
  1200. else
  1201. {
  1202. /*
  1203. **  If multiple queues wildcarded, use one for
  1204. **  the daemon's home. Note that this preconditions
  1205. **  a wildcarded QueueDir to a real pathname.
  1206. */
  1207. if (OpMode != MD_TEST)
  1208. multiqueue_cache();
  1209. }
  1210. /* check host status directory for validity */
  1211. if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
  1212. {
  1213. /* cannot use this value */
  1214. if (tTd(0, 2))
  1215. dprintf("Cannot use HostStatusDirectory = %s: %sn",
  1216. HostStatDir, errstring(errno));
  1217. HostStatDir = NULL;
  1218. }
  1219. #if QUEUE
  1220. if (OpMode == MD_QUEUERUN && RealUid != 0 &&
  1221.     bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
  1222. {
  1223. struct stat stbuf;
  1224. /* check to see if we own the queue directory */
  1225. if (stat(".", &stbuf) < 0)
  1226. syserr("main: cannot stat %s", QueueDir);
  1227. if (stbuf.st_uid != RealUid)
  1228. {
  1229. /* nope, really a botch */
  1230. usrerr("You do not have permission to process the queue");
  1231. finis(FALSE, EX_NOPERM);
  1232. }
  1233. }
  1234. #endif /* QUEUE */
  1235. /* if we've had errors so far, exit now */
  1236. if (ExitStat != EX_OK && OpMode != MD_TEST)
  1237. finis(FALSE, ExitStat);
  1238. #if XDEBUG
  1239. checkfd012("before main() initmaps");
  1240. #endif /* XDEBUG */
  1241. /*
  1242. **  Do operation-mode-dependent initialization.
  1243. */
  1244. switch (OpMode)
  1245. {
  1246.   case MD_PRINT:
  1247. /* print the queue */
  1248. #if QUEUE
  1249. dropenvelope(CurEnv, TRUE);
  1250. (void) setsignal(SIGPIPE, quiesce);
  1251. printqueue();
  1252. finis(FALSE, EX_OK);
  1253. #else /* QUEUE */
  1254. usrerr("No queue to print");
  1255. finis(FALSE, EX_UNAVAILABLE);
  1256. #endif /* QUEUE */
  1257. break;
  1258.   case MD_HOSTSTAT:
  1259. (void) setsignal(SIGPIPE, quiesce);
  1260. (void) mci_traverse_persistent(mci_print_persistent, NULL);
  1261. finis(FALSE, EX_OK);
  1262. break;
  1263.   case MD_PURGESTAT:
  1264. (void) mci_traverse_persistent(mci_purge_persistent, NULL);
  1265. finis(FALSE, EX_OK);
  1266. break;
  1267.   case MD_INITALIAS:
  1268. /* initialize maps */
  1269. initmaps();
  1270. finis(FALSE, ExitStat);
  1271. break;
  1272.   case MD_SMTP:
  1273.   case MD_DAEMON:
  1274. /* reset DSN parameters */
  1275. DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
  1276. CurEnv->e_envid = NULL;
  1277. define(macid("{dsn_envid}", NULL), NULL, CurEnv);
  1278. CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
  1279. define(macid("{dsn_ret}", NULL), NULL, CurEnv);
  1280. /* don't open maps for daemon -- done below in child */
  1281. break;
  1282. }
  1283. if (tTd(0, 15))
  1284. {
  1285. /* print configuration table (or at least part of it) */
  1286. if (tTd(0, 90))
  1287. printrules();
  1288. for (i = 0; i < MAXMAILERS; i++)
  1289. {
  1290. if (Mailer[i] != NULL)
  1291. printmailer(Mailer[i]);
  1292. }
  1293. }
  1294. /*
  1295. **  Switch to the main envelope.
  1296. */
  1297. CurEnv = newenvelope(&MainEnvelope, CurEnv);
  1298. MainEnvelope.e_flags = BlankEnvelope.e_flags;
  1299. /*
  1300. **  If test mode, read addresses from stdin and process.
  1301. */
  1302. if (OpMode == MD_TEST)
  1303. {
  1304. char buf[MAXLINE];
  1305. if (isatty(fileno(stdin)))
  1306. Verbose = 2;
  1307. if (Verbose)
  1308. {
  1309. printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)n");
  1310. printf("Enter <ruleset> <address>n");
  1311. }
  1312. if (setjmp(TopFrame) > 0)
  1313. printf("n");
  1314. (void) setsignal(SIGINT, intindebug);
  1315. for (;;)
  1316. {
  1317. if (Verbose == 2)
  1318. printf("> ");
  1319. (void) fflush(stdout);
  1320. if (fgets(buf, sizeof buf, stdin) == NULL)
  1321. testmodeline("/quit", CurEnv);
  1322. p = strchr(buf, 'n');
  1323. if (p != NULL)
  1324. *p = '';
  1325. if (Verbose < 2)
  1326. printf("> %sn", buf);
  1327. testmodeline(buf, CurEnv);
  1328. }
  1329. }
  1330. #if SMTP
  1331. #endif /* SMTP */
  1332. #if QUEUE
  1333. /*
  1334. **  If collecting stuff from the queue, go start doing that.
  1335. */
  1336. if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
  1337. {
  1338. # if SMTP
  1339. # endif /* SMTP */
  1340. (void) runqueue(!Verbose, Verbose);
  1341. finis(TRUE, ExitStat);
  1342. }
  1343. #endif /* QUEUE */
  1344. /*
  1345. **  If a daemon, wait for a request.
  1346. ** getrequests will always return in a child.
  1347. ** If we should also be processing the queue, start
  1348. ** doing it in background.
  1349. ** We check for any errors that might have happened
  1350. ** during startup.
  1351. */
  1352. if (OpMode == MD_DAEMON || QueueIntvl != 0)
  1353. {
  1354. char dtype[200];
  1355. if (!run_in_foreground && !tTd(99, 100))
  1356. {
  1357. /* put us in background */
  1358. i = fork();
  1359. if (i < 0)
  1360. syserr("daemon: cannot fork");
  1361. if (i != 0)
  1362. finis(FALSE, EX_OK);
  1363. /* disconnect from our controlling tty */
  1364. disconnect(2, CurEnv);
  1365. }
  1366. dtype[0] = '';
  1367. if (OpMode == MD_DAEMON)
  1368. (void) strlcat(dtype, "+SMTP", sizeof dtype);
  1369. if (QueueIntvl != 0)
  1370. {
  1371. (void) strlcat(dtype, "+queueing@", sizeof dtype);
  1372. (void) strlcat(dtype, pintvl(QueueIntvl, TRUE),
  1373.        sizeof dtype);
  1374. }
  1375. if (tTd(0, 1))
  1376. (void) strlcat(dtype, "+debugging", sizeof dtype);
  1377. sm_syslog(LOG_INFO, NOQID,
  1378.   "starting daemon (%s): %s", Version, dtype + 1);
  1379. #ifdef XLA
  1380. xla_create_file();
  1381. #endif /* XLA */
  1382. /* save daemon type in a macro for possible PidFile use */
  1383. define(macid("{daemon_info}", NULL),
  1384.        newstr(dtype + 1), &BlankEnvelope);
  1385. /* save queue interval in a macro for possible PidFile use */
  1386. define(macid("{queue_interval}", NULL),
  1387.        newstr(pintvl(QueueIntvl, TRUE)), CurEnv);
  1388. #if QUEUE
  1389. if (QueueIntvl != 0)
  1390. {
  1391. (void) runqueue(TRUE, FALSE);
  1392. if (OpMode != MD_DAEMON)
  1393. {
  1394. /* write the pid to file */
  1395. log_sendmail_pid(CurEnv);
  1396. for (;;)
  1397. {
  1398. (void) pause();
  1399. if (DoQueueRun)
  1400. (void) runqueue(TRUE, FALSE);
  1401. }
  1402. }
  1403. }
  1404. #endif /* QUEUE */
  1405. dropenvelope(CurEnv, TRUE);
  1406. #if DAEMON
  1407. p_flags = getrequests(CurEnv);
  1408. /* drop privileges */
  1409. (void) drop_privileges(FALSE);
  1410. /* at this point we are in a child: reset state */
  1411. (void) newenvelope(CurEnv, CurEnv);
  1412. /*
  1413. **  Get authentication data
  1414. */
  1415. authinfo = getauthinfo(fileno(InChannel), &forged);
  1416. define('_', authinfo, &BlankEnvelope);
  1417. #endif /* DAEMON */
  1418. }
  1419. if (LogLevel > 9)
  1420. {
  1421. /* log connection information */
  1422. sm_syslog(LOG_INFO, CurEnv->e_id,
  1423.   "connect from %.100s", authinfo);
  1424. }
  1425. #if SMTP
  1426. /*
  1427. **  If running SMTP protocol, start collecting and executing
  1428. **  commands.  This will never return.
  1429. */
  1430. if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
  1431. {
  1432. char pbuf[20];
  1433. /*
  1434. **  Save some macros for check_* rulesets.
  1435. */
  1436. if (forged)
  1437. {
  1438. char ipbuf[103];
  1439. (void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
  1440. anynet_ntoa(&RealHostAddr));
  1441. define(macid("{client_name}", NULL),
  1442.        newstr(ipbuf), &BlankEnvelope);
  1443. define(macid("{client_resolve}", NULL),
  1444.        "FORGED", &BlankEnvelope);
  1445. }
  1446. else
  1447. define(macid("{client_name}", NULL), RealHostName,
  1448.        &BlankEnvelope);
  1449. define(macid("{client_addr}", NULL),
  1450.        newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
  1451. (void)sm_getla(&BlankEnvelope);
  1452. switch(RealHostAddr.sa.sa_family)
  1453. {
  1454. # if NETINET
  1455.   case AF_INET:
  1456. (void) snprintf(pbuf, sizeof pbuf, "%d",
  1457. RealHostAddr.sin.sin_port);
  1458. break;
  1459. # endif /* NETINET */
  1460. # if NETINET6
  1461.   case AF_INET6:
  1462. (void) snprintf(pbuf, sizeof pbuf, "%d",
  1463. RealHostAddr.sin6.sin6_port);
  1464. break;
  1465. # endif /* NETINET6 */
  1466.   default:
  1467. (void) snprintf(pbuf, sizeof pbuf, "0");
  1468. break;
  1469. }
  1470. define(macid("{client_port}", NULL),
  1471.        newstr(pbuf), &BlankEnvelope);
  1472. #if SASL
  1473. /* give a syserr or just disable AUTH ? */
  1474. if (sasl_server_init(srvcallbacks, "Sendmail") != SASL_OK)
  1475. syserr("!sasl_server_init failed!");
  1476. #endif /* SASL */
  1477. if (OpMode == MD_DAEMON)
  1478. {
  1479. /* validate the connection */
  1480. HoldErrs = TRUE;
  1481. nullserver = validate_connection(&RealHostAddr,
  1482.  RealHostName, CurEnv);
  1483. HoldErrs = FALSE;
  1484. }
  1485. else if (p_flags == NULL)
  1486. {
  1487. p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
  1488. clrbitmap(p_flags);
  1489. }
  1490. smtp(nullserver, *p_flags, CurEnv);
  1491. }
  1492. #endif /* SMTP */
  1493. clearenvelope(CurEnv, FALSE);
  1494. if (OpMode == MD_VERIFY)
  1495. {
  1496. set_delivery_mode(SM_VERIFY, CurEnv);
  1497. PostMasterCopy = NULL;
  1498. }
  1499. else
  1500. {
  1501. /* interactive -- all errors are global */
  1502. CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
  1503. }
  1504. /*
  1505. **  Do basic system initialization and set the sender
  1506. */
  1507. initsys(CurEnv);
  1508. define(macid("{ntries}", NULL), "0", CurEnv);
  1509. setsender(from, CurEnv, NULL, '', FALSE);
  1510. if (warn_f_flag != '' && !wordinclass(RealUserName, 't') &&
  1511.     (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) ||
  1512.      strcmp(CurEnv->e_from.q_user, RealUserName) != 0))
  1513. {
  1514. auth_warning(CurEnv, "%s set sender to %s using -%c",
  1515. RealUserName, from, warn_f_flag);
  1516. #if SASL
  1517. auth = FALSE;
  1518. #endif /* SASL */
  1519. }
  1520. if (auth)
  1521. {
  1522. char *fv;
  1523. /* set the initial sender for AUTH= to $f@$j */
  1524. fv = macvalue('f', CurEnv);
  1525. if (fv == NULL || *fv == '')
  1526. CurEnv->e_auth_param = NULL;
  1527. else
  1528. {
  1529. if (strchr(fv, '@') == NULL)
  1530. {
  1531. i = strlen(fv) + strlen(macvalue('j', CurEnv))
  1532.     + 2;
  1533. p = xalloc(i);
  1534. (void) snprintf(p, i, "%s@%s", fv,
  1535. macvalue('j', CurEnv));
  1536. }
  1537. else
  1538. p = newstr(fv);
  1539. CurEnv->e_auth_param = newstr(xtextify(p, NULL));
  1540. }
  1541. }
  1542. if (macvalue('s', CurEnv) == NULL)
  1543. define('s', RealHostName, CurEnv);
  1544. if (*av == NULL && !GrabTo)
  1545. {
  1546. CurEnv->e_to = NULL;
  1547. CurEnv->e_flags |= EF_GLOBALERRS;
  1548. HoldErrs = FALSE;
  1549. usrerr("Recipient names must be specified");
  1550. /* collect body for UUCP return */
  1551. if (OpMode != MD_VERIFY)
  1552. collect(InChannel, FALSE, NULL, CurEnv);
  1553. finis(TRUE, EX_USAGE);
  1554. }
  1555. /*
  1556. **  Scan argv and deliver the message to everyone.
  1557. */
  1558. sendtoargv(av, CurEnv);
  1559. /* if we have had errors sofar, arrange a meaningful exit stat */
  1560. if (Errors > 0 && ExitStat == EX_OK)
  1561. ExitStat = EX_USAGE;
  1562. #if _FFR_FIX_DASHT
  1563. /*
  1564. **  If using -t, force not sending to argv recipients, even
  1565. **  if they are mentioned in the headers.
  1566. */
  1567. if (GrabTo)
  1568. {
  1569. ADDRESS *q;
  1570. for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
  1571. q->q_state = QS_REMOVED;
  1572. }
  1573. #endif /* _FFR_FIX_DASHT */
  1574. /*
  1575. **  Read the input mail.
  1576. */
  1577. CurEnv->e_to = NULL;
  1578. if (OpMode != MD_VERIFY || GrabTo)
  1579. {
  1580. int savederrors = Errors;
  1581. long savedflags = CurEnv->e_flags & EF_FATALERRS;
  1582. CurEnv->e_flags |= EF_GLOBALERRS;
  1583. CurEnv->e_flags &= ~EF_FATALERRS;
  1584. Errors = 0;
  1585. buffer_errors();
  1586. collect(InChannel, FALSE, NULL, CurEnv);
  1587. /* header checks failed */
  1588. if (Errors > 0)
  1589. {
  1590. /* Log who the mail would have gone to */
  1591. if (LogLevel > 8 && CurEnv->e_message != NULL &&
  1592.     !GrabTo)
  1593. {
  1594. ADDRESS *a;
  1595. for (a = CurEnv->e_sendqueue;
  1596.      a != NULL;
  1597.      a = a->q_next)
  1598. {
  1599. if (!QS_IS_UNDELIVERED(a->q_state))
  1600. continue;
  1601. CurEnv->e_to = a->q_paddr;
  1602. logdelivery(NULL, NULL,
  1603.     CurEnv->e_message,
  1604.     NULL, (time_t) 0, CurEnv);
  1605. }
  1606. CurEnv->e_to = NULL;
  1607. }
  1608. flush_errors(TRUE);
  1609. finis(TRUE, ExitStat);
  1610. /* NOTREACHED */
  1611. return -1;
  1612. }
  1613. /* bail out if message too large */
  1614. if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
  1615. {
  1616. finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR);
  1617. /* NOTREACHED */
  1618. return -1;
  1619. }
  1620. Errors = savederrors;
  1621. CurEnv->e_flags |= savedflags;
  1622. }
  1623. errno = 0;
  1624. if (tTd(1, 1))
  1625. dprintf("From person = "%s"n", CurEnv->e_from.q_paddr);
  1626. /*
  1627. **  Actually send everything.
  1628. ** If verifying, just ack.
  1629. */
  1630. CurEnv->e_from.q_state = QS_SENDER;
  1631. if (tTd(1, 5))
  1632. {
  1633. dprintf("main: QS_SENDER ");
  1634. printaddr(&CurEnv->e_from, FALSE);
  1635. }
  1636. CurEnv->e_to = NULL;
  1637. CurrentLA = sm_getla(CurEnv);
  1638. GrabTo = FALSE;
  1639. #if NAMED_BIND
  1640. _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
  1641. _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
  1642. #endif /* NAMED_BIND */
  1643. sendall(CurEnv, SM_DEFAULT);
  1644. /*
  1645. **  All done.
  1646. ** Don't send return error message if in VERIFY mode.
  1647. */
  1648. finis(TRUE, ExitStat);
  1649. /* NOTREACHED */
  1650. return ExitStat;
  1651. }
  1652. /* ARGSUSED */
  1653. SIGFUNC_DECL
  1654. quiesce(sig)
  1655. int sig;
  1656. {
  1657. clear_events();
  1658. finis(FALSE, EX_OK);
  1659. }
  1660. /* ARGSUSED */
  1661. SIGFUNC_DECL
  1662. intindebug(sig)
  1663. int sig;
  1664. {
  1665. longjmp(TopFrame, 1);
  1666. return SIGFUNC_RETURN;
  1667. }
  1668. /*
  1669. **  FINIS -- Clean up and exit.
  1670. **
  1671. ** Parameters:
  1672. ** drop -- whether or not to drop CurEnv envelope
  1673. ** exitstat -- exit status to use for exit() call
  1674. **
  1675. ** Returns:
  1676. ** never
  1677. **
  1678. ** Side Effects:
  1679. ** exits sendmail
  1680. */
  1681. void
  1682. finis(drop, exitstat)
  1683. bool drop;
  1684. volatile int exitstat;
  1685. {
  1686. if (tTd(2, 1))
  1687. {
  1688. dprintf("n====finis: stat %d e_id=%s e_flags=",
  1689. exitstat,
  1690. CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
  1691. printenvflags(CurEnv);
  1692. }
  1693. if (tTd(2, 9))
  1694. printopenfds(FALSE);
  1695. /* if we fail in finis(), just exit */
  1696. if (setjmp(TopFrame) != 0)
  1697. {
  1698. /* failed -- just give it up */
  1699. goto forceexit;
  1700. }
  1701. /* clean up temp files */
  1702. CurEnv->e_to = NULL;
  1703. if (drop)
  1704. {
  1705. if (CurEnv->e_id != NULL)
  1706. dropenvelope(CurEnv, TRUE);
  1707. else
  1708. poststats(StatFile);
  1709. }
  1710. /* flush any cached connections */
  1711. mci_flush(TRUE, NULL);
  1712. /* close maps belonging to this pid */
  1713. closemaps();
  1714. #if USERDB
  1715. /* close UserDatabase */
  1716. _udbx_close();
  1717. #endif /* USERDB */
  1718. #ifdef XLA
  1719. /* clean up extended load average stuff */
  1720. xla_all_end();
  1721. #endif /* XLA */
  1722. /* and exit */
  1723.   forceexit:
  1724. if (LogLevel > 78)
  1725. sm_syslog(LOG_DEBUG, CurEnv->e_id,
  1726.   "finis, pid=%d",
  1727.   getpid());
  1728. if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
  1729. exitstat = EX_OK;
  1730. sync_queue_time();
  1731. /* reset uid for process accounting */
  1732. endpwent();
  1733. (void) setuid(RealUid);
  1734. exit(exitstat);
  1735. }
  1736. /*
  1737. **  INTSIG -- clean up on interrupt
  1738. **
  1739. ** This just arranges to exit.  It pessimizes in that it
  1740. ** may resend a message.
  1741. **
  1742. ** Parameters:
  1743. ** none.
  1744. **
  1745. ** Returns:
  1746. ** none.
  1747. **
  1748. ** Side Effects:
  1749. ** Unlocks the current job.
  1750. */
  1751. /* ARGSUSED */
  1752. SIGFUNC_DECL
  1753. intsig(sig)
  1754. int sig;
  1755. {
  1756. bool drop = FALSE;
  1757. clear_events();
  1758. if (sig != 0 && LogLevel > 79)
  1759. sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
  1760. FileName = NULL;
  1761. closecontrolsocket(TRUE);
  1762. #ifdef XLA
  1763. xla_all_end();
  1764. #endif /* XLA */
  1765. /* Clean-up on aborted stdin message submission */
  1766. if (CurEnv->e_id != NULL &&
  1767.     (OpMode == MD_SMTP ||
  1768.      OpMode == MD_DELIVER ||
  1769.      OpMode == MD_ARPAFTP))
  1770. {
  1771. register ADDRESS *q;
  1772. /* don't return an error indication */
  1773. CurEnv->e_to = NULL;
  1774. CurEnv->e_flags &= ~EF_FATALERRS;
  1775. CurEnv->e_flags |= EF_CLRQUEUE;
  1776. /*
  1777. **  Spin through the addresses and
  1778. **  mark them dead to prevent bounces
  1779. */
  1780. for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
  1781. q->q_state = QS_DONTSEND;
  1782. /* and don't try to deliver the partial message either */
  1783. if (InChild)
  1784. ExitStat = EX_QUIT;
  1785. drop = TRUE;
  1786. }
  1787. else
  1788. unlockqueue(CurEnv);
  1789. finis(drop, EX_OK);
  1790. }
  1791. /*
  1792. **  INITMACROS -- initialize the macro system
  1793. **
  1794. ** This just involves defining some macros that are actually
  1795. ** used internally as metasymbols to be themselves.
  1796. **
  1797. ** Parameters:
  1798. ** none.
  1799. **
  1800. ** Returns:
  1801. ** none.
  1802. **
  1803. ** Side Effects:
  1804. ** initializes several macros to be themselves.
  1805. */
  1806. struct metamac MetaMacros[] =
  1807. {
  1808. /* LHS pattern matching characters */
  1809. { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE },
  1810. { '=', MATCHCLASS }, { '~', MATCHNCLASS },
  1811. /* these are RHS metasymbols */
  1812. { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER },
  1813. { '>', CALLSUBR },
  1814. /* the conditional operations */
  1815. { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI },
  1816. /* the hostname lookup characters */
  1817. { '[', HOSTBEGIN }, { ']', HOSTEND },
  1818. { '(', LOOKUPBEGIN }, { ')', LOOKUPEND },
  1819. /* miscellaneous control characters */
  1820. { '&', MACRODEXPAND },
  1821. { '' }
  1822. };
  1823. #define MACBINDING(name, mid) 
  1824. stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; 
  1825. MacroName[mid] = name;
  1826. void
  1827. initmacros(e)
  1828. register ENVELOPE *e;
  1829. {
  1830. register struct metamac *m;
  1831. register int c;
  1832. char buf[5];
  1833. extern char *MacroName[256];
  1834. for (m = MetaMacros; m->metaname != ''; m++)
  1835. {
  1836. buf[0] = m->metaval;
  1837. buf[1] = '';
  1838. define(m->metaname, newstr(buf), e);
  1839. }
  1840. buf[0] = MATCHREPL;
  1841. buf[2] = '';
  1842. for (c = '0'; c <= '9'; c++)
  1843. {
  1844. buf[1] = c;
  1845. define(c, newstr(buf), e);
  1846. }
  1847. /* set defaults for some macros sendmail will use later */
  1848. define('n', "MAILER-DAEMON", e);
  1849. /* set up external names for some internal macros */
  1850. MACBINDING("opMode", MID_OPMODE);
  1851. /*XXX should probably add equivalents for all short macros here XXX*/
  1852. }
  1853. /*
  1854. **  DISCONNECT -- remove our connection with any foreground process
  1855. **
  1856. ** Parameters:
  1857. ** droplev -- how "deeply" we should drop the line.
  1858. ** 0 -- ignore signals, mail back errors, make sure
  1859. **      output goes to stdout.
  1860. ** 1 -- also, make stdout go to /dev/null.
  1861. ** 2 -- also, disconnect from controlling terminal
  1862. **      (only for daemon mode).
  1863. ** e -- the current envelope.
  1864. **
  1865. ** Returns:
  1866. ** none
  1867. **
  1868. ** Side Effects:
  1869. ** Trys to insure that we are immune to vagaries of
  1870. ** the controlling tty.
  1871. */
  1872. void
  1873. disconnect(droplev, e)
  1874. int droplev;
  1875. register ENVELOPE *e;
  1876. {
  1877. int fd;
  1878. if (tTd(52, 1))
  1879. dprintf("disconnect: In %d Out %d, e=%lxn",
  1880. fileno(InChannel), fileno(OutChannel), (u_long) e);
  1881. if (tTd(52, 100))
  1882. {
  1883. dprintf("don'tn");
  1884. return;
  1885. }
  1886. if (LogLevel > 93)
  1887. sm_syslog(LOG_DEBUG, e->e_id,
  1888.   "disconnect level %d",
  1889.   droplev);
  1890. /* be sure we don't get nasty signals */
  1891. (void) setsignal(SIGINT, SIG_IGN);
  1892. (void) setsignal(SIGQUIT, SIG_IGN);
  1893. /* we can't communicate with our caller, so.... */
  1894. HoldErrs = TRUE;
  1895. CurEnv->e_errormode = EM_MAIL;
  1896. Verbose = 0;
  1897. DisConnected = TRUE;
  1898. /* all input from /dev/null */
  1899. if (InChannel != stdin)
  1900. {
  1901. (void) fclose(InChannel);
  1902. InChannel = stdin;
  1903. }
  1904. if (freopen("/dev/null", "r", stdin) == NULL)
  1905. sm_syslog(LOG_ERR, e->e_id,
  1906.   "disconnect: freopen("/dev/null") failed: %s",
  1907.   errstring(errno));
  1908. /* output to the transcript */
  1909. if (OutChannel != stdout)
  1910. {
  1911. (void) fclose(OutChannel);
  1912. OutChannel = stdout;
  1913. }
  1914. if (droplev > 0)
  1915. {
  1916. fd = open("/dev/null", O_WRONLY, 0666);
  1917. if (fd == -1)
  1918. sm_syslog(LOG_ERR, e->e_id,
  1919.   "disconnect: open("/dev/null") failed: %s",
  1920.   errstring(errno));
  1921. (void) fflush(stdout);
  1922. (void) dup2(fd, STDOUT_FILENO);
  1923. (void) dup2(fd, STDERR_FILENO);
  1924. (void) close(fd);
  1925. }
  1926. /* drop our controlling TTY completely if possible */
  1927. if (droplev > 1)
  1928. {
  1929. (void) setsid();
  1930. errno = 0;
  1931. }
  1932. #if XDEBUG
  1933. checkfd012("disconnect");
  1934. #endif /* XDEBUG */
  1935. if (LogLevel > 71)
  1936. sm_syslog(LOG_DEBUG, e->e_id,
  1937.   "in background, pid=%d",
  1938.   getpid());
  1939. errno = 0;
  1940. }
  1941. static void
  1942. obsolete(argv)
  1943. char *argv[];
  1944. {
  1945. register char *ap;
  1946. register char *op;
  1947. while ((ap = *++argv) != NULL)
  1948. {
  1949. /* Return if "--" or not an option of any form. */
  1950. if (ap[0] != '-' || ap[1] == '-')
  1951. return;
  1952. /* skip over options that do have a value */
  1953. op = strchr(OPTIONS, ap[1]);
  1954. if (op != NULL && *++op == ':' && ap[2] == '' &&
  1955.     ap[1] != 'd' &&
  1956. #if defined(sony_news)
  1957.     ap[1] != 'E' && ap[1] != 'J' &&
  1958. #endif /* defined(sony_news) */
  1959.     argv[1] != NULL && argv[1][0] != '-')
  1960. {
  1961. argv++;
  1962. continue;
  1963. }
  1964. /* If -C doesn't have an argument, use sendmail.cf. */
  1965. #define __DEFPATH "sendmail.cf"
  1966. if (ap[1] == 'C' && ap[2] == '')
  1967. {
  1968. *argv = xalloc(sizeof(__DEFPATH) + 2);
  1969. (void) snprintf(argv[0], sizeof(__DEFPATH) + 2, "-C%s",
  1970. __DEFPATH);
  1971. }
  1972. /* If -q doesn't have an argument, run it once. */
  1973. if (ap[1] == 'q' && ap[2] == '')
  1974. *argv = "-q0";
  1975. /* if -d doesn't have an argument, use 0-99.1 */
  1976. if (ap[1] == 'd' && ap[2] == '')
  1977. *argv = "-d0-99.1";
  1978. #if defined(sony_news)
  1979. /* if -E doesn't have an argument, use -EC */
  1980. if (ap[1] == 'E' && ap[2] == '')
  1981. *argv = "-EC";
  1982. /* if -J doesn't have an argument, use -JJ */
  1983. if (ap[1] == 'J' && ap[2] == '')
  1984. *argv = "-JJ";
  1985. #endif /* defined(sony_news) */
  1986. }
  1987. }
  1988. /*
  1989. **  AUTH_WARNING -- specify authorization warning
  1990. **
  1991. ** Parameters:
  1992. ** e -- the current envelope.
  1993. ** msg -- the text of the message.
  1994. ** args -- arguments to the message.
  1995. **
  1996. ** Returns:
  1997. ** none.
  1998. */
  1999. void
  2000. #ifdef __STDC__
  2001. auth_warning(register ENVELOPE *e, const char *msg, ...)
  2002. #else /* __STDC__ */
  2003. auth_warning(e, msg, va_alist)
  2004. register ENVELOPE *e;
  2005. const char *msg;
  2006. va_dcl
  2007. #endif /* __STDC__ */
  2008. {
  2009. char buf[MAXLINE];
  2010. VA_LOCAL_DECL
  2011. if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
  2012. {
  2013. register char *p;
  2014. static char hostbuf[48];
  2015. if (hostbuf[0] == '')
  2016. (void) myhostname(hostbuf, sizeof hostbuf);
  2017. (void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
  2018. p = &buf[strlen(buf)];
  2019. VA_START(msg);
  2020. vsnprintf(p, SPACELEFT(buf, p), msg, ap);
  2021. VA_END;
  2022. addheader("X-Authentication-Warning", buf, &e->e_header);
  2023. if (LogLevel > 3)
  2024. sm_syslog(LOG_INFO, e->e_id,
  2025.   "Authentication-Warning: %.400s",
  2026.   buf);
  2027. }
  2028. }
  2029. /*
  2030. **  GETEXTENV -- get from external environment
  2031. **
  2032. ** Parameters:
  2033. ** envar -- the name of the variable to retrieve
  2034. **
  2035. ** Returns:
  2036. ** The value, if any.
  2037. */
  2038. char *
  2039. getextenv(envar)
  2040. const char *envar;
  2041. {
  2042. char **envp;
  2043. int l;
  2044. l = strlen(envar);
  2045. for (envp = ExternalEnviron; *envp != NULL; envp++)
  2046. {
  2047. if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
  2048. return &(*envp)[l + 1];
  2049. }
  2050. return NULL;
  2051. }
  2052. /*
  2053. **  SETUSERENV -- set an environment in the propogated environment
  2054. **
  2055. ** Parameters:
  2056. ** envar -- the name of the environment variable.
  2057. ** value -- the value to which it should be set.  If
  2058. ** null, this is extracted from the incoming
  2059. ** environment.  If that is not set, the call
  2060. ** to setuserenv is ignored.
  2061. **
  2062. ** Returns:
  2063. ** none.
  2064. */
  2065. void
  2066. setuserenv(envar, value)
  2067. const char *envar;
  2068. const char *value;
  2069. {
  2070. int i, l;
  2071. char **evp = UserEnviron;
  2072. char *p;
  2073. if (value == NULL)
  2074. {
  2075. value = getextenv(envar);
  2076. if (value == NULL)
  2077. return;
  2078. }
  2079. i = strlen(envar) + 1;
  2080. l = strlen(value) + i + 1;
  2081. p = (char *) xalloc(l);
  2082. (void) snprintf(p, l, "%s=%s", envar, value);
  2083. while (*evp != NULL && strncmp(*evp, p, i) != 0)
  2084. evp++;
  2085. if (*evp != NULL)
  2086. {
  2087. *evp++ = p;
  2088. }
  2089. else if (evp < &UserEnviron[MAXUSERENVIRON])
  2090. {
  2091. *evp++ = p;
  2092. *evp = NULL;
  2093. }
  2094. /* make sure it is in our environment as well */
  2095. if (putenv(p) < 0)
  2096. syserr("setuserenv: putenv(%s) failed", p);
  2097. }
  2098. /*
  2099. **  DUMPSTATE -- dump state
  2100. **
  2101. ** For debugging.
  2102. */
  2103. void
  2104. dumpstate(when)
  2105. char *when;
  2106. {
  2107. register char *j = macvalue('j', CurEnv);
  2108. int rs;
  2109. extern int NextMacroId;
  2110. sm_syslog(LOG_DEBUG, CurEnv->e_id,
  2111.   "--- dumping state on %s: $j = %s ---",
  2112.   when,
  2113.   j == NULL ? "<NULL>" : j);
  2114. if (j != NULL)
  2115. {
  2116. if (!wordinclass(j, 'w'))
  2117. sm_syslog(LOG_DEBUG, CurEnv->e_id,
  2118.   "*** $j not in $=w ***");
  2119. }
  2120. sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
  2121. sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)n",
  2122.   NextMacroId, MAXMACROID);
  2123. sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
  2124. printopenfds(TRUE);
  2125. sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
  2126. mci_dump_all(TRUE);
  2127. rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
  2128. if (rs > 0)
  2129. {
  2130. int status;
  2131. register char **pvp;
  2132. char *pv[MAXATOM + 1];
  2133. pv[0] = NULL;
  2134. status = rewrite(pv, rs, 0, CurEnv);
  2135. sm_syslog(LOG_DEBUG, CurEnv->e_id,
  2136.   "--- ruleset debug_dumpstate returns stat %d, pv: ---",
  2137.   status);
  2138. for (pvp = pv; *pvp != NULL; pvp++)
  2139. sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
  2140. }
  2141. sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
  2142. }
  2143. /* ARGSUSED */
  2144. SIGFUNC_DECL
  2145. sigusr1(sig)
  2146. int sig;
  2147. {
  2148. dumpstate("user signal");
  2149. return SIGFUNC_RETURN;
  2150. }
  2151. /* ARGSUSED */
  2152. SIGFUNC_DECL
  2153. sighup(sig)
  2154. int sig;
  2155. {
  2156. int i;
  2157. extern int DtableSize;
  2158. clear_events();
  2159. (void) alarm(0);
  2160. if (SaveArgv[0][0] != '/')
  2161. {
  2162. if (LogLevel > 3)
  2163. sm_syslog(LOG_INFO, NOQID,
  2164.   "could not restart: need full path");
  2165. finis(FALSE, EX_OSFILE);
  2166. }
  2167. if (LogLevel > 3)
  2168. sm_syslog(LOG_INFO, NOQID, "restarting %s %s",
  2169.   sig == 0 ? "due to control command" : "on signal",
  2170.   SaveArgv[0]);
  2171. /* Control socket restart? */
  2172. if (sig != 0)
  2173. (void) releasesignal(SIGHUP);
  2174. closecontrolsocket(TRUE);
  2175. if (drop_privileges(TRUE) != EX_OK)
  2176. {
  2177. if (LogLevel > 0)
  2178. sm_syslog(LOG_ALERT, NOQID,
  2179.   "could not set[ug]id(%d, %d): %m",
  2180.   RunAsUid, RunAsGid);
  2181. finis(FALSE, EX_OSERR);
  2182. }
  2183. /* arrange for all the files to be closed */
  2184. for (i = 3; i < DtableSize; i++)
  2185. {
  2186. register int j;
  2187. if ((j = fcntl(i, F_GETFD, 0)) != -1)
  2188. (void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
  2189. }
  2190. (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
  2191. if (LogLevel > 0)
  2192. sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m",
  2193.   SaveArgv[0]);
  2194. finis(FALSE, EX_OSFILE);
  2195. }
  2196. /*
  2197. **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
  2198. **
  2199. ** Parameters:
  2200. ** to_real_uid -- if set, drop to the real uid instead
  2201. ** of the RunAsUser.
  2202. **
  2203. ** Returns:
  2204. ** EX_OSERR if the setuid failed.
  2205. ** EX_OK otherwise.
  2206. */
  2207. int
  2208. drop_privileges(to_real_uid)
  2209. bool to_real_uid;
  2210. {
  2211. int rval = EX_OK;
  2212. GIDSET_T emptygidset[1];
  2213. if (tTd(47, 1))
  2214. dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%dn",
  2215. (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
  2216. if (to_real_uid)
  2217. {
  2218. RunAsUserName = RealUserName;
  2219. RunAsUid = RealUid;
  2220. RunAsGid = RealGid;
  2221. }
  2222. /* make sure no one can grab open descriptors for secret files */
  2223. endpwent();
  2224. /* reset group permissions; these can be set later */
  2225. emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
  2226. if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
  2227. rval = EX_OSERR;
  2228. /* reset primary group and user id */
  2229. if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
  2230. rval = EX_OSERR;
  2231. if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
  2232. rval = EX_OSERR;
  2233. if (tTd(47, 5))
  2234. {
  2235. dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%dn",
  2236. (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
  2237. dprintf("drop_privileges: RunAsUser = %d:%dn",
  2238. (int)RunAsUid, (int)RunAsGid);
  2239. }
  2240. return rval;
  2241. }
  2242. /*
  2243. **  FILL_FD -- make sure a file descriptor has been properly allocated
  2244. **
  2245. ** Used to make sure that stdin/out/err are allocated on startup
  2246. **
  2247. ** Parameters:
  2248. ** fd -- the file descriptor to be filled.
  2249. ** where -- a string used for logging.  If NULL, this is
  2250. ** being called on startup, and logging should
  2251. ** not be done.
  2252. **
  2253. ** Returns:
  2254. ** none
  2255. */
  2256. void
  2257. fill_fd(fd, where)
  2258. int fd;
  2259. char *where;
  2260. {
  2261. int i;
  2262. struct stat stbuf;
  2263. if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
  2264. return;
  2265. if (where != NULL)
  2266. syserr("fill_fd: %s: fd %d not open", where, fd);
  2267. else
  2268. MissingFds |= 1 << fd;
  2269. i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
  2270. if (i < 0)
  2271. {
  2272. syserr("!fill_fd: %s: cannot open /dev/null",
  2273. where == NULL ? "startup" : where);
  2274. }
  2275. if (fd != i)
  2276. {
  2277. (void) dup2(i, fd);
  2278. (void) close(i);
  2279. }
  2280. }
  2281. /*
  2282. **  TESTMODELINE -- process a test mode input line
  2283. **
  2284. ** Parameters:
  2285. ** line -- the input line.
  2286. ** e -- the current environment.
  2287. ** Syntax:
  2288. ** #  a comment
  2289. ** .X process X as a configuration line
  2290. ** =X dump a configuration item (such as mailers)
  2291. ** $X dump a macro or class
  2292. ** /X try an activity
  2293. ** X  normal process through rule set X
  2294. */
  2295. static void
  2296. testmodeline(line, e)
  2297. char *line;
  2298. ENVELOPE *e;
  2299. {
  2300. register char *p;
  2301. char *q;
  2302. auto char *delimptr;
  2303. int mid;
  2304. int i, rs;
  2305. STAB *map;
  2306. char **s;
  2307. struct rewrite *rw;
  2308. ADDRESS a;
  2309. static int tryflags = RF_COPYNONE;
  2310. char exbuf[MAXLINE];
  2311. extern u_char TokTypeNoC[];
  2312. #if _FFR_ADDR_TYPE
  2313. define(macid("{addr_type}", NULL), "e r", e);
  2314. #endif /* _FFR_ADDR_TYPE */
  2315. switch (line[0])
  2316. {
  2317.   case '#':
  2318.   case '':
  2319. return;
  2320.   case '?':
  2321. help("-bt", e);
  2322. return;
  2323.   case '.': /* config-style settings */
  2324. switch (line[1])
  2325. {
  2326.   case 'D':
  2327. mid = macid(&line[2], &delimptr);
  2328. if (mid == '')
  2329. return;
  2330. translate_dollars(delimptr);
  2331. define(mid, newstr(delimptr), e);
  2332. break;
  2333.   case 'C':
  2334. if (line[2] == '') /* not to call syserr() */
  2335. return;
  2336. mid = macid(&line[2], &delimptr);
  2337. if (mid == '')
  2338. return;
  2339. translate_dollars(delimptr);
  2340. expand(delimptr, exbuf, sizeof exbuf, e);
  2341. p = exbuf;
  2342. while (*p != '')
  2343. {
  2344. register char *wd;
  2345. char delim;
  2346. while (*p != '' && isascii(*p) && isspace(*p))
  2347. p++;
  2348. wd = p;
  2349. while (*p != '' && !(isascii(*p) && isspace(*p)))
  2350. p++;
  2351. delim = *p;
  2352. *p = '';
  2353. if (wd[0] != '')
  2354. setclass(mid, wd);
  2355. *p = delim;
  2356. }
  2357. break;
  2358.   case '':
  2359. printf("Usage: .[DC]macro value(s)n");
  2360. break;
  2361.   default:
  2362. printf("Unknown "." command %sn", line);
  2363. break;
  2364. }
  2365. return;
  2366.   case '=': /* config-style settings */
  2367. switch (line[1])
  2368. {
  2369.   case 'S': /* dump rule set */
  2370. rs = strtorwset(&line[2], NULL, ST_FIND);
  2371. if (rs < 0)
  2372. {
  2373. printf("Undefined ruleset %sn", &line[2]);
  2374. return;
  2375. }
  2376. rw = RewriteRules[rs];
  2377. if (rw == NULL)
  2378. return;
  2379. do
  2380. {
  2381. (void) putchar('R');
  2382. s = rw->r_lhs;
  2383. while (*s != NULL)
  2384. {
  2385. xputs(*s++);
  2386. (void) putchar(' ');
  2387. }
  2388. (void) putchar('t');
  2389. (void) putchar('t');
  2390. s = rw->r_rhs;
  2391. while (*s != NULL)
  2392. {
  2393. xputs(*s++);
  2394. (void) putchar(' ');
  2395. }
  2396. (void) putchar('n');
  2397. } while ((rw = rw->r_next) != NULL);
  2398. break;
  2399.   case 'M':
  2400. for (i = 0; i < MAXMAILERS; i++)
  2401. {
  2402. if (Mailer[i] != NULL)
  2403. printmailer(Mailer[i]);
  2404. }
  2405. break;
  2406.   case '':
  2407. printf("Usage: =Sruleset or =Mn");
  2408. break;
  2409.   default:
  2410. printf("Unknown "=" command %sn", line);
  2411. break;
  2412. }
  2413. return;
  2414.   case '-': /* set command-line-like opts */
  2415. switch (line[1])
  2416. {
  2417.   case 'd':
  2418. tTflag(&line[2]);
  2419. break;
  2420.   case '':
  2421. printf("Usage: -d{debug arguments}n");
  2422. break;
  2423.   default:
  2424. printf("Unknown "-" command %sn", line);
  2425. break;
  2426. }
  2427. return;
  2428.   case '$':
  2429. if (line[1] == '=')
  2430. {
  2431. mid = macid(&line[2], NULL);
  2432. if (mid != '')
  2433. stabapply(dump_class, mid);
  2434. return;
  2435. }
  2436. mid = macid(&line[1], NULL);
  2437. if (mid == '')
  2438. return;
  2439. p = macvalue(mid, e);
  2440. if (p == NULL)
  2441. printf("Undefinedn");
  2442. else
  2443. {
  2444. xputs(p);
  2445. printf("n");
  2446. }
  2447. return;
  2448.   case '/': /* miscellaneous commands */
  2449. p = &line[strlen(line)];
  2450. while (--p >= line && isascii(*p) && isspace(*p))
  2451. *p = '';
  2452. p = strpbrk(line, " t");
  2453. if (p != NULL)
  2454. {
  2455. while (isascii(*p) && isspace(*p))
  2456. *p++ = '';
  2457. }
  2458. else
  2459. p = "";
  2460. if (line[1] == '')
  2461. {
  2462. printf("Usage: /[canon|map|mx|parse|try|tryflags]n");
  2463. return;
  2464. }
  2465. if (strcasecmp(&line[1], "quit") == 0)
  2466. {
  2467. CurEnv->e_id = NULL;
  2468. finis(TRUE, ExitStat);
  2469. }
  2470. if (strcasecmp(&line[1], "mx") == 0)
  2471. {
  2472. #if NAMED_BIND
  2473. /* look up MX records */
  2474. int nmx;
  2475. auto int rcode;
  2476. char *mxhosts[MAXMXHOSTS + 1];
  2477. if (*p == '')
  2478. {
  2479. printf("Usage: /mx addressn");
  2480. return;
  2481. }
  2482. nmx = getmxrr(p, mxhosts, NULL, FALSE, &rcode);
  2483. printf("getmxrr(%s) returns %d value(s):n", p, nmx);
  2484. for (i = 0; i < nmx; i++)
  2485. printf("t%sn", mxhosts[i]);
  2486. #else /* NAMED_BIND */
  2487. printf("No MX code compiled inn");
  2488. #endif /* NAMED_BIND */
  2489. }
  2490. else if (strcasecmp(&line[1], "canon") == 0)
  2491. {
  2492. char host[MAXHOSTNAMELEN];
  2493. if (*p == '')
  2494. {
  2495. printf("Usage: /canon addressn");
  2496. return;
  2497. }
  2498. else if (strlcpy(host, p, sizeof host) >= sizeof host)
  2499. {
  2500. printf("Name too longn");
  2501. return;
  2502. }
  2503. (void) getcanonname(host, sizeof host, HasWildcardMX);
  2504. printf("getcanonname(%s) returns %sn", p, host);
  2505. }
  2506. else if (strcasecmp(&line[1], "map") == 0)
  2507. {
  2508. auto int rcode = EX_OK;
  2509. char *av[2];
  2510. if (*p == '')
  2511. {
  2512. printf("Usage: /map mapname keyn");
  2513. return;
  2514. }
  2515. for (q = p; *q != '' && !(isascii(*q) && isspace(*q)); q++)
  2516. continue;
  2517. if (*q == '')
  2518. {
  2519. printf("No key specifiedn");
  2520. return;
  2521. }
  2522. *q++ = '';
  2523. map = stab(p, ST_MAP, ST_FIND);
  2524. if (map == NULL)
  2525. {
  2526. printf("Map named "%s" not foundn", p);
  2527. return;
  2528. }
  2529. if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
  2530.     !openmap(&(map->s_map)))
  2531. {
  2532. printf("Map named "%s" not openn", p);
  2533. return;
  2534. }
  2535. printf("map_lookup: %s (%s) ", p, q);
  2536. av[0] = q;
  2537. av[1] = NULL;
  2538. p = (*map->s_map.map_class->map_lookup)
  2539. (&map->s_map, q, av, &rcode);
  2540. if (p == NULL)
  2541. printf("no match (%d)n", rcode);
  2542. else
  2543. printf("returns %s (%d)n", p, rcode);
  2544. }
  2545. else if (strcasecmp(&line[1], "try") == 0)
  2546. {
  2547. MAILER *m;
  2548. STAB *st;
  2549. auto int rcode = EX_OK;
  2550. q = strpbrk(p, " t");
  2551. if (q != NULL)
  2552. {
  2553. while (isascii(*q) && isspace(*q))
  2554. *q++ = '';
  2555. }
  2556. if (q == NULL || *q == '')
  2557. {
  2558. printf("Usage: /try mailer addressn");
  2559. return;
  2560. }
  2561. st = stab(p, ST_MAILER, ST_FIND);
  2562. if (st == NULL)
  2563. {
  2564. printf("Unknown mailer %sn", p);
  2565. return;
  2566. }
  2567. m = st->s_mailer;
  2568. printf("Trying %s %s address %s for mailer %sn",
  2569. bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
  2570. bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
  2571. q, p);
  2572. p = remotename(q, m, tryflags, &rcode, CurEnv);
  2573. printf("Rcode = %d, addr = %sn",
  2574. rcode, p == NULL ? "<NULL>" : p);
  2575. e->e_to = NULL;
  2576. }
  2577. else if (strcasecmp(&line[1], "tryflags") == 0)
  2578. {
  2579. if (*p == '')
  2580. {
  2581. printf("Usage: /tryflags [Hh|Ee][Ss|Rr]n");
  2582. return;
  2583. }
  2584. for (; *p != ''; p++)
  2585. {
  2586. switch (*p)
  2587. {
  2588.   case 'H':
  2589.   case 'h':
  2590. tryflags |= RF_HEADERADDR;
  2591. break;
  2592.   case 'E':
  2593.   case 'e':
  2594. tryflags &= ~RF_HEADERADDR;
  2595. break;
  2596.   case 'S':
  2597.   case 's':
  2598. tryflags |= RF_SENDERADDR;
  2599. break;
  2600.   case 'R':
  2601.   case 'r':
  2602. tryflags &= ~RF_SENDERADDR;
  2603. break;
  2604. }
  2605. }
  2606. #if _FFR_ADDR_TYPE
  2607. exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
  2608. exbuf[1] = ' ';
  2609. exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
  2610. exbuf[3] = '';
  2611. define(macid("{addr_type}", NULL), newstr(exbuf), e);
  2612. #endif /* _FFR_ADDR_TYPE */
  2613. }
  2614. else if (strcasecmp(&line[1], "parse") == 0)
  2615. {
  2616. if (*p == '')
  2617. {
  2618. printf("Usage: /parse addressn");
  2619. return;
  2620. }
  2621. q = crackaddr(p);
  2622. printf("Cracked address = ");
  2623. xputs(q);
  2624. printf("nParsing %s %s addressn",
  2625. bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
  2626. bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
  2627. if (parseaddr(p, &a, tryflags, '', NULL, e) == NULL)
  2628. printf("Cannot parsen");
  2629. else if (a.q_host != NULL && a.q_host[0] != '')
  2630. printf("mailer %s, host %s, user %sn",
  2631. a.q_mailer->m_name, a.q_host, a.q_user);
  2632. else
  2633. printf("mailer %s, user %sn",
  2634. a.q_mailer->m_name, a.q_user);
  2635. e->e_to = NULL;
  2636. }
  2637. else
  2638. {
  2639. printf("Unknown "/" command %sn", line);
  2640. }
  2641. return;
  2642. }
  2643. for (p = line; isascii(*p) && isspace(*p); p++)
  2644. continue;
  2645. q = p;
  2646. while (*p != '' && !(isascii(*p) && isspace(*p)))
  2647. p++;
  2648. if (*p == '')
  2649. {
  2650. printf("No address!n");
  2651. return;
  2652. }
  2653. *p = '';
  2654. if (invalidaddr(p + 1, NULL))
  2655. return;
  2656. do
  2657. {
  2658. register char **pvp;
  2659. char pvpbuf[PSBUFSIZE];
  2660. pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
  2661.       &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL);
  2662. if (pvp == NULL)
  2663. continue;
  2664. p = q;
  2665. while (*p != '')
  2666. {
  2667. int status;
  2668. rs = strtorwset(p, NULL, ST_FIND);
  2669. if (rs < 0)
  2670. {
  2671. printf("Undefined ruleset %sn", p);
  2672. break;
  2673. }
  2674. status = rewrite(pvp, rs, 0, e);
  2675. if (status != EX_OK)
  2676. printf("== Ruleset %s (%d) status %dn",
  2677. p, rs, status);
  2678. while (*p != '' && *p++ != ',')
  2679. continue;
  2680. }
  2681. } while (*(p = delimptr) != '');
  2682. }
  2683. static void
  2684. dump_class(s, id)
  2685. register STAB *s;
  2686. int id;
  2687. {
  2688. if (s->s_type != ST_CLASS)
  2689. return;
  2690. if (bitnset(id & 0xff, s->s_class))
  2691. printf("%sn", s->s_name);
  2692. }