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

Defined functions

disconnect defined in line 983; used 1 times
freeze defined in line 862; used 1 times
initmacros defined in line 814; used 1 times
intsig defined in line 768; used 4 times
main defined in line 86; never used
thaw defined in line 915; used 1 times

Defined variables

Argv defined in line 80; used 1 times
BlankEnvelope defined in line 67; used 6 times
FullName defined in line 66; used 2 times
LastArgv defined in line 81; used 2 times
MainEnvelope defined in line 68; used 3 times
MetaMacros defined in line 796; used 1 times
NextMailer defined in line 65; never used
NullAddress defined in line 69; used 2 times
SccsId defined in line 18; never used
copyright defined in line 12; never used
edata defined in line 27; used 12 times
end defined in line 27; used 5 times

Defined struct's

metamac defined in line 790; used 4 times

Defined union's

frz defined in line 849; used 4 times

Defined macros

_DEFINE defined in line 21; never used
Last modified: 1986-01-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2501
Valid CSS Valid XHTML 1.0 Strict