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

Defined functions

disconnect defined in line 985; used 2 times
freeze defined in line 866; used 1 times
initmacros defined in line 818; used 1 times
intsig defined in line 772; used 4 times
main defined in line 90; never used
thaw defined in line 918; used 1 times

Defined variables

Argv defined in line 84; used 1 times
BlankEnvelope defined in line 71; used 6 times
FullName defined in line 70; used 2 times
LastArgv defined in line 85; used 2 times
MainEnvelope defined in line 72; used 3 times
MetaMacros defined in line 800; used 1 times
NextMailer defined in line 69; never used
NullAddress defined in line 73; used 2 times
copyright defined in line 18; never used
edata defined in line 34; used 10 times
end defined in line 34; used 4 times
sccsid defined in line 22; never used

Defined struct's

metamac defined in line 794; used 4 times

Defined union's

frz defined in line 853; used 4 times

Defined macros

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