1: /*
   2: **  Sendmail
   3: **  Copyright (c) 1983  Eric P. Allman
   4: **  Berkeley, California
   5: **
   6: **  Copyright (c) 1983 Regents of the University of California.
   7: **  All rights reserved.  The Berkeley software License Agreement
   8: **  specifies the terms and conditions for redistribution.
   9: */
  10: 
  11: #if !defined(lint) && !defined(NOSCCS)
  12: char copyright[] =
  13: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  14:  All rights reserved.\n";
  15: 
  16: static char SccsId[] = "@(#)main.c	5.11.3 (2.11BSD GTE) 1996/10/24";
  17: #endif
  18: 
  19: # define  _DEFINE
  20: # include <signal.h>
  21: # include <sgtty.h>
  22: # include "sendmail.h"
  23: 
  24: # ifdef lint
  25: char    edata, end;
  26: # endif lint
  27: 
  28: /*
  29: **  SENDMAIL -- Post mail to a set of destinations.
  30: **
  31: **	This is the basic mail router.  All user mail programs should
  32: **	call this routine to actually deliver mail.  Sendmail in
  33: **	turn calls a bunch of mail servers that do the real work of
  34: **	delivering the mail.
  35: **
  36: **	Sendmail is driven by tables read in from /etc/sendmail.cf
  37: **	(read by readcf.c).  Some more static configuration info,
  38: **	including some code that you may want to tailor for your
  39: **	installation, is in conf.c.  You may also want to touch
  40: **	daemon.c (if you have some other IPC mechanism), acct.c
  41: **	(to change your accounting), names.c (to adjust the name
  42: **	server mechanism).
  43: **
  44: **	Usage:
  45: **		/usr/sbin/sendmail [flags] addr ...
  46: **
  47: **		See the associated documentation for details.
  48: **
  49: **	Author:
  50: **		Eric Allman, UCB/INGRES (until 10/81)
  51: **			     Britton-Lee, Inc., purveyors of fine
  52: **				database computers (from 11/81)
  53: **		The support of the INGRES Project and Britton-Lee is
  54: **			gratefully acknowledged.  Britton-Lee in
  55: **			particular had absolutely nothing to gain from
  56: **			my involvement in this project.
  57: */
  58: 
  59: 
  60: 
  61: 
  62: 
  63: int     NextMailer; /* "free" index into Mailer struct */
  64: char        *FullName;  /* sender's full name */
  65: ENVELOPE    BlankEnvelope;  /* a "blank" envelope */
  66: ENVELOPE    MainEnvelope;   /* the envelope around the basic letter */
  67: ADDRESS     NullAddress =   /* a null address */
  68:         { "", "", "" };
  69: 
  70: /*
  71: **  Pointers for setproctitle.
  72: **	This allows "ps" listings to give more useful information.
  73: **	These must be kept out of BSS for frozen configuration files
  74: **		to work.
  75: */
  76: 
  77: # ifdef SETPROCTITLE
  78: char        **Argv = NULL;      /* pointer to argument vector */
  79: char        *LastArgv = NULL;   /* end of argv */
  80: # endif SETPROCTITLE
  81: 
  82: #ifdef DAEMON
  83: #ifndef SMTP
  84: ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
  85: #endif SMTP
  86: #endif DAEMON
  87: 
  88: 
  89: 
  90: 
  91: 
  92: 
  93: main(argc, argv, envp)
  94:     int argc;
  95:     char **argv;
  96:     char **envp;
  97: {
  98:     register char *p;
  99:     char **av;
 100:     extern int finis();
 101:     char *from;
 102:     typedef int (*fnptr)();
 103:     STAB *st;
 104:     register int i;
 105:     bool readconfig = TRUE;
 106:     bool queuemode = FALSE;     /* process queue requests */
 107:     bool nothaw;
 108:     static bool reenter = FALSE;
 109:     char jbuf[30];          /* holds MyHostName */
 110:     extern bool safefile();
 111:     extern time_t convtime();
 112:     extern putheader(), putbody();
 113:     extern ENVELOPE *newenvelope();
 114:     extern intsig();
 115:     extern char **myhostname();
 116:     extern char *arpadate();
 117:     extern char **environ;
 118: 
 119:     /*
 120: 	**  Check to see if we reentered.
 121: 	**	This would normally happen if e_putheader or e_putbody
 122: 	**	were NULL when invoked.
 123: 	*/
 124: 
 125:     if (reenter)
 126:     {
 127:         syserr("main: reentered!");
 128:         abort();
 129:     }
 130:     reenter = TRUE;
 131: 
 132:     /* Enforce use of local time */
 133:     unsetenv("TZ");
 134: 
 135:     /*
 136: 	**  Be sure we have enough file descriptors.
 137: 	*/
 138: 
 139:     for (i = 3; i < 50; i++)
 140:         (void) close(i);
 141:     errno = 0;
 142: 
 143:     /*
 144: 	**  Set default values for variables.
 145: 	**	These cannot be in initialized data space.
 146: 	*/
 147: 
 148:     setdefaults();
 149: 
 150:     /* set up the blank envelope */
 151:     BlankEnvelope.e_puthdr = putheader;
 152:     BlankEnvelope.e_putbody = putbody;
 153:     BlankEnvelope.e_xfp = NULL;
 154:     STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
 155:     CurEnv = &BlankEnvelope;
 156:     STRUCTCOPY(NullAddress, MainEnvelope.e_from);
 157: 
 158:     /*
 159: 	**  Do a quick prescan of the argument list.
 160: 	**	We do this to find out if we can potentially thaw the
 161: 	**	configuration file.  If not, we do the thaw now so that
 162: 	**	the argument processing applies to this run rather than
 163: 	**	to the run that froze the configuration.
 164: 	*/
 165: 
 166:     argv[argc] = NULL;
 167:     av = argv;
 168:     nothaw = FALSE;
 169:     while ((p = *++av) != NULL)
 170:     {
 171:         if (strncmp(p, "-C", 2) == 0)
 172:         {
 173:             ConfFile = &p[2];
 174:             if (ConfFile[0] == '\0')
 175:                 ConfFile = "sendmail.cf";
 176:             (void) setgid(getrgid());
 177:             (void) setuid(getruid());
 178:             nothaw = TRUE;
 179:         }
 180:         else if (strncmp(p, "-bz", 3) == 0)
 181:             nothaw = TRUE;
 182: # ifdef DEBUG
 183:         else if (strncmp(p, "-d", 2) == 0)
 184:         {
 185:             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
 186:             tTflag(&p[2]);
 187:             setbuf(stdout, (char *) NULL);
 188:             printf("Version %s\n", Version);
 189:         }
 190: # endif DEBUG
 191:     }
 192:     if (!nothaw)
 193:         readconfig = !thaw(FreezeFile);
 194: 
 195:     /* reset the environment after the thaw */
 196:     for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++)
 197:         UserEnviron[i] = newstr(envp[i]);
 198:     UserEnviron[i] = NULL;
 199:     environ = UserEnviron;
 200: 
 201: # ifdef SETPROCTITLE
 202:     /*
 203: 	**  Save start and extent of argv for setproctitle.
 204: 	*/
 205: 
 206:     Argv = argv;
 207:     if (i > 0)
 208:         LastArgv = envp[i - 1] + strlen(envp[i - 1]);
 209:     else
 210:         LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
 211: # endif SETPROCTITLE
 212: 
 213:     /*
 214: 	**  Now do basic initialization
 215: 	*/
 216: 
 217:     InChannel = stdin;
 218:     OutChannel = stdout;
 219:     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 220:         (void) signal(SIGINT, intsig);
 221:     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
 222:         (void) signal(SIGHUP, intsig);
 223:     (void) signal(SIGTERM, intsig);
 224:     (void) signal(SIGPIPE, SIG_IGN);
 225:     OldUmask = umask(0);
 226:     OpMode = MD_DELIVER;
 227:     MotherPid = getpid();
 228:     FullName = getenv("NAME");
 229: 
 230: # ifdef LOG
 231:     openlog("sendmail", LOG_PID, LOG_MAIL);
 232: # endif LOG
 233:     errno = 0;
 234:     from = NULL;
 235: 
 236:     if (readconfig)
 237:     {
 238:         /* initialize some macros, etc. */
 239:         initmacros();
 240: 
 241:         /* hostname */
 242:         av = myhostname(jbuf, sizeof jbuf);
 243:         if (jbuf[0] != '\0')
 244:         {
 245: #ifdef DEBUG
 246:             if (tTd(0, 4))
 247:                 printf("canonical name: %s\n", jbuf);
 248: #endif DEBUG
 249:             p = newstr(jbuf);
 250:             define('w', p, CurEnv);
 251:             setclass('w', p);
 252:         }
 253:         while (av != NULL && *av != NULL)
 254:         {
 255: #ifdef DEBUG
 256:             if (tTd(0, 4))
 257:                 printf("\ta.k.a.: %s\n", *av);
 258: #endif DEBUG
 259:             setclass('w', *av++);
 260:         }
 261: 
 262:         /* version */
 263:         define('v', Version, CurEnv);
 264:     }
 265: 
 266:     /* current time */
 267:     define('b', arpadate((char *) NULL), CurEnv);
 268: 
 269:     /*
 270: 	** Crack argv.
 271: 	*/
 272: 
 273:     av = argv;
 274:     p = rindex(*av, '/');
 275:     if (p++ == NULL)
 276:         p = *av;
 277:     if (strcmp(p, "newaliases") == 0)
 278:         OpMode = MD_INITALIAS;
 279:     else if (strcmp(p, "mailq") == 0)
 280:         OpMode = MD_PRINT;
 281:     else if (strcmp(p, "smtpd") == 0)
 282:         OpMode = MD_DAEMON;
 283:     while ((p = *++av) != NULL && p[0] == '-')
 284:     {
 285:         switch (p[1])
 286:         {
 287:           case 'b': /* operations mode */
 288:             switch (p[2])
 289:             {
 290:               case MD_DAEMON:
 291: # ifndef DAEMON
 292:                 syserr("Daemon mode not implemented");
 293:                 break;
 294: # endif DAEMON
 295:               case MD_SMTP:
 296: # ifndef SMTP
 297:                 syserr("I don't speak SMTP");
 298:                 break;
 299: # endif SMTP
 300:               case MD_ARPAFTP:
 301:               case MD_DELIVER:
 302:               case MD_VERIFY:
 303:               case MD_TEST:
 304:               case MD_INITALIAS:
 305:               case MD_PRINT:
 306:               case MD_FREEZE:
 307:                 OpMode = p[2];
 308:                 break;
 309: 
 310:               default:
 311:                 syserr("Invalid operation mode %c", p[2]);
 312:                 break;
 313:             }
 314:             break;
 315: 
 316:           case 'C': /* select configuration file (already done) */
 317:             break;
 318: 
 319: # ifdef DEBUG
 320:           case 'd': /* debugging -- redo in case frozen */
 321:             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
 322:             tTflag(&p[2]);
 323:             setbuf(stdout, (char *) NULL);
 324:             break;
 325: # endif DEBUG
 326: 
 327:           case 'f': /* from address */
 328:           case 'r': /* obsolete -f flag */
 329:             p += 2;
 330:             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
 331:             {
 332:                 p = *++av;
 333:                 if (p == NULL || *p == '-')
 334:                 {
 335:                     syserr("No \"from\" person");
 336:                     av--;
 337:                     break;
 338:                 }
 339:             }
 340:             if (from != NULL)
 341:             {
 342:                 syserr("More than one \"from\" person");
 343:                 break;
 344:             }
 345:             from = newstr(denlstring(p));
 346:             break;
 347: 
 348:           case 'F': /* set full name */
 349:             p += 2;
 350:             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
 351:             {
 352:                 syserr("Bad -F flag");
 353:                 av--;
 354:                 break;
 355:             }
 356:             FullName = newstr(p);
 357:             break;
 358: 
 359:           case 'h': /* hop count */
 360:             p += 2;
 361:             if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
 362:             {
 363:                 syserr("Bad hop count (%s)", p);
 364:                 av--;
 365:                 break;
 366:             }
 367:             CurEnv->e_hopcount = atoi(p);
 368:             break;
 369: 
 370:           case 'n': /* don't alias */
 371:             NoAlias = TRUE;
 372:             break;
 373: 
 374:           case 'o': /* set option */
 375:             setoption(p[2], &p[3], FALSE, TRUE);
 376:             break;
 377: 
 378:           case 'q': /* run queue files at intervals */
 379: # ifdef QUEUE
 380:             FullName = NULL;
 381:             queuemode = TRUE;
 382:             QueueIntvl = convtime(&p[2]);
 383: # else QUEUE
 384:             syserr("I don't know about queues");
 385: # endif QUEUE
 386:             break;
 387: 
 388:           case 't': /* read recipients from message */
 389:             GrabTo = TRUE;
 390:             break;
 391: 
 392:             /* compatibility flags */
 393:           case 'c': /* connect to non-local mailers */
 394:           case 'e': /* error message disposition */
 395:           case 'i': /* don't let dot stop me */
 396:           case 'm': /* send to me too */
 397:           case 'T': /* set timeout interval */
 398:           case 'v': /* give blow-by-blow description */
 399:             setoption(p[1], &p[2], FALSE, TRUE);
 400:             break;
 401: 
 402:           case 's': /* save From lines in headers */
 403:             setoption('f', &p[2], FALSE, TRUE);
 404:             break;
 405: 
 406: # ifdef DBM
 407:           case 'I': /* initialize alias DBM file */
 408:             OpMode = MD_INITALIAS;
 409:             break;
 410: # endif DBM
 411:         }
 412:     }
 413: 
 414:     /*
 415: 	**  Do basic initialization.
 416: 	**	Read system control file.
 417: 	**	Extract special fields for local use.
 418: 	*/
 419: 
 420:     if (OpMode == MD_FREEZE || readconfig)
 421:         readcf(ConfFile);
 422: 
 423:     switch (OpMode)
 424:     {
 425:       case MD_FREEZE:
 426:         /* this is critical to avoid forgeries of the frozen config */
 427:         (void) setgid(getgid());
 428:         (void) setuid(getuid());
 429: 
 430:         /* freeze the configuration */
 431:         freeze(FreezeFile);
 432:         exit(EX_OK);
 433: 
 434:       case MD_INITALIAS:
 435:         Verbose = TRUE;
 436:         break;
 437: 
 438:       case MD_DAEMON:
 439:         /* remove things that don't make sense in daemon mode */
 440:         FullName = NULL;
 441:         break;
 442:     }
 443: 
 444:     /* full names can't have newlines */
 445:     if (FullName != NULL && strchr(FullName, '\n') != NULL)
 446:         FullName = newstr(denlstring(FullName));
 447: 
 448:     /* do heuristic mode adjustment */
 449:     if (Verbose)
 450:     {
 451:         /* turn off noconnect option */
 452:         setoption('c', "F", TRUE, FALSE);
 453: 
 454:         /* turn on interactive delivery */
 455:         setoption('d', "", TRUE, FALSE);
 456:     }
 457: 
 458:     /* our name for SMTP codes */
 459:     expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
 460:     MyHostName = jbuf;
 461: 
 462:     /* the indices of local and program mailers */
 463:     st = stab("local", ST_MAILER, ST_FIND);
 464:     if (st == NULL)
 465:         syserr("No local mailer defined");
 466:     else
 467:         LocalMailer = st->s_mailer;
 468:     st = stab("prog", ST_MAILER, ST_FIND);
 469:     if (st == NULL)
 470:         syserr("No prog mailer defined");
 471:     else
 472:         ProgMailer = st->s_mailer;
 473: 
 474:     /* operate in queue directory */
 475:     if (chdir(QueueDir) < 0)
 476:     {
 477:         syserr("cannot chdir(%s)", QueueDir);
 478:         exit(EX_SOFTWARE);
 479:     }
 480: 
 481:     /*
 482: 	**  Do operation-mode-dependent initialization.
 483: 	*/
 484: 
 485:     switch (OpMode)
 486:     {
 487:       case MD_PRINT:
 488:         /* print the queue */
 489: #ifdef QUEUE
 490:         dropenvelope(CurEnv);
 491:         printqueue();
 492:         exit(EX_OK);
 493: #else QUEUE
 494:         usrerr("No queue to print");
 495:         finis();
 496: #endif QUEUE
 497: 
 498:       case MD_INITALIAS:
 499:         /* initialize alias database */
 500:         initaliases(AliasFile, TRUE);
 501:         exit(EX_OK);
 502: 
 503:       case MD_DAEMON:
 504:         /* don't open alias database -- done in srvrsmtp */
 505:         break;
 506: 
 507:       default:
 508:         /* open the alias database */
 509:         initaliases(AliasFile, FALSE);
 510:         break;
 511:     }
 512: 
 513: # ifdef DEBUG
 514:     if (tTd(0, 15))
 515:     {
 516:         /* print configuration table (or at least part of it) */
 517:         printrules();
 518:         for (i = 0; i < MAXMAILERS; i++)
 519:         {
 520:             register struct mailer *m = Mailer[i];
 521:             int j;
 522: 
 523:             if (m == NULL)
 524:                 continue;
 525:             printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name,
 526:                 m->m_mailer, m->m_s_rwset, m->m_r_rwset,
 527:                 m->m_maxsize);
 528:             for (j = '\0'; j <= '\177'; j++)
 529:                 if (bitnset(j, m->m_flags))
 530:                     (void) putchar(j);
 531:             printf(" E=");
 532:             xputs(m->m_eol);
 533:             printf("\n");
 534:         }
 535:     }
 536: # endif DEBUG
 537: 
 538:     /*
 539: 	**  Switch to the main envelope.
 540: 	*/
 541: 
 542:     CurEnv = newenvelope(&MainEnvelope);
 543:     MainEnvelope.e_flags = BlankEnvelope.e_flags;
 544: 
 545:     /*
 546: 	**  If test mode, read addresses from stdin and process.
 547: 	*/
 548: 
 549:     if (OpMode == MD_TEST)
 550:     {
 551:         char buf[MAXLINE];
 552: 
 553:         printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
 554:         for (;;)
 555:         {
 556:             register char **pvp;
 557:             char *q;
 558:             extern char *DelimChar;
 559: 
 560:             printf("> ");
 561:             (void) fflush(stdout);
 562:             if (fgets(buf, sizeof buf, stdin) == NULL)
 563:                 finis();
 564:             for (p = buf; isspace(*p); *p++)
 565:                 continue;
 566:             q = p;
 567:             while (*p != '\0' && !isspace(*p))
 568:                 p++;
 569:             if (*p == '\0')
 570:                 continue;
 571:             *p = '\0';
 572:             do
 573:             {
 574:                 extern char **prescan();
 575:                 char pvpbuf[PSBUFSIZE];
 576: 
 577:                 pvp = prescan(++p, ',', pvpbuf);
 578:                 if (pvp == NULL)
 579:                     continue;
 580:                 rewrite(pvp, 3);
 581:                 p = q;
 582:                 while (*p != '\0')
 583:                 {
 584:                     rewrite(pvp, atoi(p));
 585:                     while (*p != '\0' && *p++ != ',')
 586:                         continue;
 587:                 }
 588:             } while (*(p = DelimChar) != '\0');
 589:         }
 590:     }
 591: 
 592: # ifdef QUEUE
 593:     /*
 594: 	**  If collecting stuff from the queue, go start doing that.
 595: 	*/
 596: 
 597:     if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
 598:     {
 599:         runqueue(FALSE);
 600:         finis();
 601:     }
 602: # endif QUEUE
 603: 
 604:     /*
 605: 	**  If a daemon, wait for a request.
 606: 	**	getrequests will always return in a child.
 607: 	**	If we should also be processing the queue, start
 608: 	**		doing it in background.
 609: 	**	We check for any errors that might have happened
 610: 	**		during startup.
 611: 	*/
 612: 
 613:     if (OpMode == MD_DAEMON || QueueIntvl != 0)
 614:     {
 615:         if (!tTd(0, 1))
 616:         {
 617:             /* put us in background */
 618:             i = fork();
 619:             if (i < 0)
 620:                 syserr("daemon: cannot fork");
 621:             if (i != 0)
 622:                 exit(0);
 623: 
 624:             /* get our pid right */
 625:             MotherPid = getpid();
 626: 
 627:             /* disconnect from our controlling tty */
 628:             disconnect(TRUE);
 629:         }
 630: 
 631: # ifdef QUEUE
 632:         if (queuemode)
 633:         {
 634:             runqueue(TRUE);
 635:             if (OpMode != MD_DAEMON)
 636:                 for (;;)
 637:                     pause();
 638:         }
 639: # endif QUEUE
 640:         dropenvelope(CurEnv);
 641: 
 642: #ifdef DAEMON
 643:         getrequests();
 644: 
 645:         /* at this point we are in a child: reset state */
 646:         OpMode = MD_SMTP;
 647:         (void) newenvelope(CurEnv);
 648:         openxscript(CurEnv);
 649: #endif DAEMON
 650:     }
 651: 
 652: # ifdef SMTP
 653:     /*
 654: 	**  If running SMTP protocol, start collecting and executing
 655: 	**  commands.  This will never return.
 656: 	*/
 657: 
 658:     if (OpMode == MD_SMTP)
 659:         smtp();
 660: # endif SMTP
 661: 
 662:     /*
 663: 	**  Do basic system initialization and set the sender
 664: 	*/
 665: 
 666:     initsys();
 667:     setsender(from);
 668: 
 669:     if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
 670:     {
 671:         usrerr("Recipient names must be specified");
 672: 
 673:         /* collect body for UUCP return */
 674:         if (OpMode != MD_VERIFY)
 675:             collect(FALSE);
 676:         finis();
 677:     }
 678:     if (OpMode == MD_VERIFY)
 679:         SendMode = SM_VERIFY;
 680: 
 681:     /*
 682: 	**  Scan argv and deliver the message to everyone.
 683: 	*/
 684: 
 685:     sendtoargv(av);
 686: 
 687:     /* if we have had errors sofar, arrange a meaningful exit stat */
 688:     if (Errors > 0 && ExitStat == EX_OK)
 689:         ExitStat = EX_USAGE;
 690: 
 691:     /*
 692: 	**  Read the input mail.
 693: 	*/
 694: 
 695:     CurEnv->e_to = NULL;
 696:     if (OpMode != MD_VERIFY || GrabTo)
 697:         collect(FALSE);
 698:     errno = 0;
 699: 
 700:     /* collect statistics */
 701:     if (OpMode != MD_VERIFY)
 702:         markstats(CurEnv, (ADDRESS *) NULL);
 703: 
 704: # ifdef DEBUG
 705:     if (tTd(1, 1))
 706:         printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
 707: # endif DEBUG
 708: 
 709:     /*
 710: 	**  Actually send everything.
 711: 	**	If verifying, just ack.
 712: 	*/
 713: 
 714:     CurEnv->e_from.q_flags |= QDONTSEND;
 715:     CurEnv->e_to = NULL;
 716:     sendall(CurEnv, SM_DEFAULT);
 717: 
 718:     /*
 719: 	** All done.
 720: 	*/
 721: 
 722:     finis();
 723: }
 724: /*
 725: **  FINIS -- Clean up and exit.
 726: **
 727: **	Parameters:
 728: **		none
 729: **
 730: **	Returns:
 731: **		never
 732: **
 733: **	Side Effects:
 734: **		exits sendmail
 735: */
 736: 
 737: finis()
 738: {
 739: # ifdef DEBUG
 740:     if (tTd(2, 1))
 741:         printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
 742: # endif DEBUG
 743: 
 744:     /* clean up temp files */
 745:     CurEnv->e_to = NULL;
 746:     dropenvelope(CurEnv);
 747: 
 748:     /* post statistics */
 749:     poststats(StatFile);
 750: 
 751:     /* and exit */
 752: # ifdef LOG
 753:     if (LogLevel > 11)
 754:         syslog(LOG_DEBUG, "finis, pid=%d", getpid());
 755: # endif LOG
 756:     if (ExitStat == EX_TEMPFAIL)
 757:         ExitStat = EX_OK;
 758:     exit(ExitStat);
 759: }
 760: /*
 761: **  INTSIG -- clean up on interrupt
 762: **
 763: **	This just arranges to exit.  It pessimises in that it
 764: **	may resend a message.
 765: **
 766: **	Parameters:
 767: **		none.
 768: **
 769: **	Returns:
 770: **		none.
 771: **
 772: **	Side Effects:
 773: **		Unlocks the current job.
 774: */
 775: 
 776: intsig()
 777: {
 778:     FileName = NULL;
 779:     unlockqueue(CurEnv);
 780:     exit(EX_OK);
 781: }
 782: /*
 783: **  INITMACROS -- initialize the macro system
 784: **
 785: **	This just involves defining some macros that are actually
 786: **	used internally as metasymbols to be themselves.
 787: **
 788: **	Parameters:
 789: **		none.
 790: **
 791: **	Returns:
 792: **		none.
 793: **
 794: **	Side Effects:
 795: **		initializes several macros to be themselves.
 796: */
 797: 
 798: struct metamac
 799: {
 800:     char    metaname;
 801:     char    metaval;
 802: };
 803: 
 804: struct metamac  MetaMacros[] =
 805: {
 806:     /* LHS pattern matching characters */
 807:     '*', MATCHZANY, '+', MATCHANY,  '-', MATCHONE,  '=', MATCHCLASS,
 808:     '~', MATCHNCLASS,
 809: 
 810:     /* these are RHS metasymbols */
 811:     '#', CANONNET,  '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR,
 812: 
 813:     /* the conditional operations */
 814:     '?', CONDIF,    '|', CONDELSE,  '.', CONDFI,
 815: 
 816:     /* and finally the hostname lookup characters */
 817:     '[', HOSTBEGIN, ']', HOSTEND,
 818: 
 819:     '\0'
 820: };
 821: 
 822: initmacros()
 823: {
 824:     register struct metamac *m;
 825:     char buf[5];
 826:     register int c;
 827: 
 828:     for (m = MetaMacros; m->metaname != '\0'; m++)
 829:     {
 830:         buf[0] = m->metaval;
 831:         buf[1] = '\0';
 832:         define(m->metaname, newstr(buf), CurEnv);
 833:     }
 834:     buf[0] = MATCHREPL;
 835:     buf[2] = '\0';
 836:     for (c = '0'; c <= '9'; c++)
 837:     {
 838:         buf[1] = c;
 839:         define(c, newstr(buf), CurEnv);
 840:     }
 841: }
 842: /*
 843: **  FREEZE -- freeze BSS & allocated memory
 844: **
 845: **	This will be used to efficiently load the configuration file.
 846: **
 847: **	Parameters:
 848: **		freezefile -- the name of the file to freeze to.
 849: **
 850: **	Returns:
 851: **		none.
 852: **
 853: **	Side Effects:
 854: **		Writes BSS and malloc'ed memory to freezefile
 855: */
 856: 
 857: union frz
 858: {
 859:     char        frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
 860:     struct
 861:     {
 862:         time_t  frzstamp;   /* timestamp on this freeze */
 863:         char    *frzbrk;    /* the current break */
 864:         char    *frzedata;  /* address of edata */
 865:         char    *frzend;    /* address of end */
 866:         char    frzver[252];    /* sendmail version */
 867:     } frzinfo;
 868: };
 869: 
 870: freeze(freezefile)
 871:     char *freezefile;
 872: {
 873:     int f;
 874:     union frz fhdr;
 875:     extern char edata, end;
 876:     extern char *sbrk();
 877: 
 878:     if (freezefile == NULL)
 879:         return;
 880: 
 881:     /* try to open the freeze file */
 882:     f = creat(freezefile, FileMode);
 883:     if (f < 0)
 884:     {
 885:         syserr("Cannot freeze");
 886:         errno = 0;
 887:         return;
 888:     }
 889: 
 890:     /* build the freeze header */
 891:     fhdr.frzinfo.frzstamp = curtime();
 892:     fhdr.frzinfo.frzbrk = sbrk(0);
 893:     fhdr.frzinfo.frzedata = &edata;
 894:     fhdr.frzinfo.frzend = &end;
 895:     (void) strcpy(fhdr.frzinfo.frzver, Version);
 896: 
 897:     /* write out the freeze header */
 898:     if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
 899:         write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
 900:                     (int) (fhdr.frzinfo.frzbrk - &edata))
 901:     {
 902:         syserr("Cannot freeze");
 903:     }
 904: 
 905:     /* fine, clean up */
 906:     (void) close(f);
 907: }
 908: /*
 909: **  THAW -- read in the frozen configuration file.
 910: **
 911: **	Parameters:
 912: **		freezefile -- the name of the file to thaw from.
 913: **
 914: **	Returns:
 915: **		TRUE if it successfully read the freeze file.
 916: **		FALSE otherwise.
 917: **
 918: **	Side Effects:
 919: **		reads freezefile in to BSS area.
 920: */
 921: 
 922: thaw(freezefile)
 923:     char *freezefile;
 924: {
 925:     int f;
 926:     union frz fhdr;
 927:     extern char edata, end;
 928:     extern caddr_t brk();
 929: 
 930:     if (freezefile == NULL)
 931:         return (FALSE);
 932: 
 933:     /* open the freeze file */
 934:     f = open(freezefile, 0);
 935:     if (f < 0)
 936:     {
 937:         errno = 0;
 938:         return (FALSE);
 939:     }
 940: 
 941:     /* read in the header */
 942:     if (read(f, (char *) &fhdr, sizeof fhdr) < (int)sizeof fhdr ||
 943:         fhdr.frzinfo.frzedata != &edata ||
 944:         fhdr.frzinfo.frzend != &end ||
 945:         strcmp(fhdr.frzinfo.frzver, Version) != 0)
 946:     {
 947:         (void) close(f);
 948:         return (FALSE);
 949:     }
 950: 
 951:     /* arrange to have enough space */
 952:     if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1)
 953:     {
 954:         syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
 955:         (void) close(f);
 956:         return (FALSE);
 957:     }
 958: 
 959:     /* now read in the freeze file */
 960:     if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
 961:                     (int) (fhdr.frzinfo.frzbrk - &edata))
 962:     {
 963:         /* oops!  we have trashed memory..... */
 964:         (void) write(2, "Cannot read freeze file\n", 24);
 965:         _exit(EX_SOFTWARE);
 966:     }
 967: 
 968:     (void) close(f);
 969:     return (TRUE);
 970: }
 971: /*
 972: **  DISCONNECT -- remove our connection with any foreground process
 973: **
 974: **	Parameters:
 975: **		fulldrop -- if set, we should also drop the controlling
 976: **			TTY if possible -- this should only be done when
 977: **			setting up the daemon since otherwise UUCP can
 978: **			leave us trying to open a dialin, and we will
 979: **			wait for the carrier.
 980: **
 981: **	Returns:
 982: **		none
 983: **
 984: **	Side Effects:
 985: **		Trys to insure that we are immune to vagaries of
 986: **		the controlling tty.
 987: */
 988: 
 989: disconnect(fulldrop)
 990:     bool fulldrop;
 991: {
 992:     int fd;
 993: 
 994: #ifdef DEBUG
 995:     if (tTd(52, 1))
 996:         printf("disconnect: In %d Out %d\n", fileno(InChannel),
 997:                         fileno(OutChannel));
 998:     if (tTd(52, 5))
 999:     {
1000:         printf("don't\n");
1001:         return;
1002:     }
1003: #endif DEBUG
1004: 
1005:     /* be sure we don't get nasty signals */
1006:     (void) signal(SIGHUP, SIG_IGN);
1007:     (void) signal(SIGINT, SIG_IGN);
1008:     (void) signal(SIGQUIT, SIG_IGN);
1009: 
1010:     /* we can't communicate with our caller, so.... */
1011:     HoldErrs = TRUE;
1012:     ErrorMode = EM_MAIL;
1013:     Verbose = FALSE;
1014: 
1015:     /* all input from /dev/null */
1016:     if (InChannel != stdin)
1017:     {
1018:         (void) fclose(InChannel);
1019:         InChannel = stdin;
1020:     }
1021:     (void) freopen("/dev/null", "r", stdin);
1022: 
1023:     /* output to the transcript */
1024:     if (OutChannel != stdout)
1025:     {
1026:         (void) fclose(OutChannel);
1027:         OutChannel = stdout;
1028:     }
1029:     if (CurEnv->e_xfp == NULL)
1030:         CurEnv->e_xfp = fopen("/dev/null", "w");
1031:     (void) fflush(stdout);
1032:     (void) close(1);
1033:     (void) close(2);
1034:     while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
1035:         continue;
1036: 
1037:     XXctime();  /* XXX - close pipes to ctimed */
1038: 
1039: #ifdef TIOCNOTTY
1040:     /* drop our controlling TTY completely if possible */
1041:     if (fulldrop)
1042:     {
1043:         fd = open("/dev/tty", 2);
1044:         if (fd >= 0)
1045:         {
1046:             (void) ioctl(fd, TIOCNOTTY, (char *) 0);
1047:             (void) close(fd);
1048:         }
1049:         (void) setpgrp(0, 0);
1050:         errno = 0;
1051:     }
1052: #endif TIOCNOTTY
1053: 
1054: # ifdef LOG
1055:     if (LogLevel > 11)
1056:         syslog(LOG_DEBUG, "in background, pid=%d", getpid());
1057: # endif LOG
1058: 
1059:     errno = 0;
1060: }

Defined functions

disconnect defined in line 989; used 2 times
freeze defined in line 870; used 1 times
initmacros defined in line 822; used 1 times
intsig defined in line 776; used 4 times
main defined in line 84; never used
thaw defined in line 922; used 1 times

Defined variables

Argv defined in line 78; used 1 times
BlankEnvelope defined in line 65; used 6 times
FullName defined in line 64; used 8 times
LastArgv defined in line 79; used 2 times
MainEnvelope defined in line 66; used 3 times
MetaMacros defined in line 804; used 1 times
NextMailer defined in line 63; never used
NullAddress defined in line 67; used 2 times
SccsId defined in line 16; never used
copyright defined in line 12; never used
edata defined in line 25; used 10 times
end defined in line 25; used 4 times

Defined struct's

metamac defined in line 798; used 4 times

Defined union's

frz defined in line 857; used 4 times

Defined macros

_DEFINE defined in line 19; never used
Last modified: 1996-10-25
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6407
Valid CSS Valid XHTML 1.0 Strict