📄 main.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. * * Sendmail * Copyright (c) 1983 Eric P. Allman * Berkeley, California */# define _DEFINE# include <signal.h># include <sys/ioctl.h># include "sendmail.h"SCCSID(@(#)main.c 1.1 92/07/30 SMI); /* from UCB 5.17 4/19/88 */# ifdef lintchar edata, end;# endif lint/*** SENDMAIL -- Post mail to a set of destinations.**** This is the basic mail router. All user mail programs should** call this routine to actually deliver mail. Sendmail in** turn calls a bunch of mail servers that do the real work of** delivering the mail.**** Sendmail is driven by tables read in from /etc/sendmail.cf** (read by readcf.c). Some more static configuration info,** including some code that you may want to tailor for your** installation, is in conf.c. You may also want to touch** daemon.c (if you have some other IPC mechanism), acct.c** (to change your accounting), names.c (to adjust the name** server mechanism).**** Usage:** /usr/lib/sendmail [flags] addr ...**** See the associated documentation for details.**** Author:** Eric Allman, UCB/INGRES (until 10/81)** Britton-Lee, Inc., purveyors of fine** database computers (from 11/81)** The support of the INGRES Project and Britton-Lee is** gratefully acknowledged. Britton-Lee in** particular had absolutely nothing to gain from** my involvement in this project.*/int NextMailer; /* "free" index into Mailer struct */char *FullName; /* sender's full name */ENVELOPE BlankEnvelope; /* a "blank" envelope */ENVELOPE MainEnvelope; /* the envelope around the basic letter */ADDRESS NullAddress = /* a null address */ { "", "", NULL, "" };/*** Pointers for setproctitle.** This allows "ps" listings to give more useful information.** These must be kept out of BSS for frozen configuration files** to work.*/# ifdef SETPROCTITLEchar **Argv = NULL; /* pointer to argument vector */char *LastArgv = NULL; /* end of argv */# endif SETPROCTITLE# ifdef QUEUEint OnlyRunId; /* Queue ID from -M to run, or zero */char *OnlyRunRecip; /* Recipient name from -R to run, or zero */# endif QUEUE#ifdef DAEMON#ifndef SMTPERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR#endif SMTP#endif DAEMONmain(argc, argv, envp) int argc; char **argv; char **envp;{ register char *p; char **av; extern int finis(); extern char Version[]; char *from; typedef int (*fnptr)(); STAB *st; register int i; bool readconfig = TRUE; bool queuemode = FALSE; /* process queue requests */ bool nothaw;#ifdef vax static bool reenter = FALSE;#endif vax char jbuf[65]; /* holds MyHostName */ extern bool safefile(); extern time_t convtime(); extern putheader(), putbody(); extern ENVELOPE *newenvelope(); extern intsig(); extern char **myhostname(); extern char *arpadate(); extern char *macvalue(); extern char **environ; extern int DtableSize;#ifdef INTER setlocale(LC_ALL, "");#endif#ifdef vax /* ** Check to see if we reentered. ** This would normally happen if e_putheader or e_putbody ** were NULL when invoked. */ if (reenter) { syserr("main: reentered!"); abort(); } reenter = TRUE;#endif vax /* ** Be sure we have enough file descriptors. */ DtableSize = getdtablesize(); for (i = 3; i < DtableSize; i++) (void) close(i); errno = 0; /* ** Set default values for variables. ** These cannot be in initialized data space. */ setdefaults(); /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; BlankEnvelope.e_putbody = putbody; BlankEnvelope.e_xfp = NULL; STRUCTCOPY(NullAddress, BlankEnvelope.e_from); CurEnv = &BlankEnvelope; STRUCTCOPY(NullAddress, MainEnvelope.e_from); /* ** Do a quick prescan of the argument list. ** We do this to find out if we can potentially thaw the ** configuration file. If not, we do the thaw now so that ** the argument processing applies to this run rather than ** to the run that froze the configuration. */ argv[argc] = NULL; av = argv; nothaw = FALSE; while ((p = *++av) != NULL) { if (strncmp(p, "-C", 2) == 0) { ConfFile = &p[2]; if (ConfFile[0] == '\0') ConfFile = "sendmail.cf"; (void) setgid(getrgid()); (void) setuid(getruid()); nothaw = TRUE; } else if (strncmp(p, "-bz", 3) == 0) nothaw = TRUE;# ifdef DEBUG else if (strncmp(p, "-d", 2) == 0) { tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(&p[2]); setbuf(stdout, (char *) NULL); printf("Version %s\n", Version); }# endif DEBUG } if (!nothaw) readconfig = !thaw(FreezeFile); /* reset the environment after the thaw */ for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++) UserEnviron[i] = newstr(envp[i]); UserEnviron[i] = NULL; environ = UserEnviron;# ifdef SETPROCTITLE /* ** Save start and extent of argv for setproctitle. */ Argv = argv; if (i > 0) LastArgv = envp[i - 1] + strlen(envp[i - 1]); else LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);# endif SETPROCTITLE /* ** Now do basic initialization */ InChannel = stdin; OutChannel = stdout; if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void) signal(SIGINT, intsig); if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void) signal(SIGHUP, intsig); (void) signal(SIGTERM, intsig); (void) signal(SIGPIPE, SIG_IGN); OldUmask = umask(0); OpMode = MD_DELIVER; MotherPid = getpid(); FullName = getenv("NAME");# ifdef LOG openlog("sendmail", LOG_PID, LOG_MAIL);# endif LOG errno = 0; from = NULL; if (readconfig) { /* initialize some macros, etc. */ initmacros(); initdomain(); /* hostname */ av = myhostname(jbuf, sizeof jbuf); if (jbuf[0] != '\0') {#ifdef DEBUG if (tTd(0, 4)) printf("canonical name: %s\n", jbuf);#endif DEBUG p = newstr(jbuf); define('w', p, CurEnv); setclass('w', p); } while (av != NULL && *av != NULL) {#ifdef DEBUG if (tTd(0, 4)) printf("\ta.k.a.: %s\n", *av);#endif DEBUG setclass('w', *av++); } if ((p = index(jbuf, '.')) != NULL) { /* * If the full domain name is used, then make sure that * the unqualified name is also recognized. */ *p = '\0'; st = stab(jbuf, ST_CLASS, ST_FIND); if (st == NULL || !bitnset('w', st->s_class)) setclass('w', jbuf); } /* version */ define('v', Version, CurEnv); } /* current time */ define('b', arpadate((char *) NULL), CurEnv); /* ** Crack argv. */ av = argv; p = rindex(*av, '/'); if (p++ == NULL) p = *av; if (strcmp(p, "newaliases") == 0) OpMode = MD_INITALIAS; else if (strcmp(p, "mailq") == 0) OpMode = MD_PRINT; else if (strcmp(p, "smtpd") == 0) OpMode = MD_DAEMON; while ((p = *++av) != NULL && p[0] == '-') { switch (p[1]) { case 'b': /* operations mode */ switch (p[2]) { case MD_DAEMON:# ifndef DAEMON syserr("Daemon mode not implemented"); break;# endif DAEMON case MD_SMTP:# ifndef SMTP syserr("I don't speak SMTP"); break;# endif SMTP case MD_ARPAFTP: case MD_DELIVER: case MD_VERIFY: case MD_TEST: case MD_INITALIAS: case MD_PRINT: case MD_FREEZE: OpMode = p[2]; break; default: syserr("Invalid operation mode %c", p[2]); break; } break; case 'C': /* select configuration file (already done) */ break;#ifdef DEBUG case 'd': /* debugging -- redo in case frozen */ tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(&p[2]); setbuf(stdout, (char *) NULL); break;#endif case 'f': /* from address */ case 'r': /* obsolete -f flag */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) { errno = 0; syserr("No \"from\" person"); av--; break; } if (from != NULL) { errno = 0; syserr("More than one \"from\" person"); break; } from = newstr(p); break; case 'F': /* set full name */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) { syserr("Bad -F flag"); av--; break; } FullName = newstr(p); break; case 'h': /* hop count */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p))) { syserr("Bad hop count (%s)", p); av--; break; } CurEnv->e_hopcount = atoi(p); break; case 'n': /* don't alias */ NoAlias = TRUE; break; case 'o': /* set option */ setoption(p[2], &p[3], FALSE, TRUE); break; case 'q': /* run queue files at intervals */# ifdef QUEUE queuemode = TRUE; QueueIntvl = convtime(&p[2]);# else QUEUE syserr("I don't know about queues");# endif QUEUE break; case 't': /* read recipients from message */ GrabTo = TRUE; break; /* compatibility flags */ case 'c': /* connect to non-local mailers */ case 'e': /* error message disposition */ case 'i': /* don't let dot stop me */ case 'm': /* send to me too */ case 'T': /* set timeout interval */ case 'v': /* give blow-by-blow description */ setoption(p[1], &p[2], FALSE, TRUE); break; case 's': /* save From lines in headers */ setoption('f', &p[2], FALSE, TRUE); break;# ifdef DBM case 'I': /* initialize alias DBM file */ OpMode = MD_INITALIAS; break;# endif DBM# ifdef QUEUE case 'M': /* Queue run takes Mail queue Id only */ p += 2; if ((*p == '\0' && (p = *++av) == NULL) || !isdigit(*p)) { errno = 0; syserr("Mail-queue Id (%s) must be numeric", p); if (p == NULL) av--; break; } OnlyRunId = atoi(p); queuemode = TRUE; break; case 'R': /* Queue run takes certain Recipients only */ OnlyRunRecip = newstr(p+2); queuemode = TRUE; break;# endif QUEUE } } /* ** Do basic initialization. ** Read system control file. ** Extract special fields for local use. */ if (OpMode == MD_FREEZE || readconfig) readcf(ConfFile); /* * Set the domain class here, in case it was re-defined in the cf */ p = macvalue('m', CurEnv); if (p) setclass('m', p); switch (OpMode) { case MD_FREEZE: /* this is critical to avoid forgeries of the frozen config */ (void) setgid(getgid()); (void) setuid(getuid()); /* freeze the configuration */ freeze(FreezeFile); exit(EX_OK); case MD_INITALIAS: Verbose = TRUE; break; } /* do heuristic mode adjustment */ if (Verbose) { /* turn off noconnect option */ setoption('c', "F", TRUE, FALSE); /* turn on interactive delivery */ setoption('d', "", TRUE, FALSE); } /* our name for SMTP codes */ expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); MyHostName = jbuf; /* the indices of local and program mailers */ st = stab("local", ST_MAILER, ST_FIND); if (st == NULL) syserr("No local mailer defined"); else LocalMailer = st->s_mailer; st = stab("prog", ST_MAILER, ST_FIND); if (st == NULL) syserr("No prog mailer defined"); else ProgMailer = st->s_mailer; /* enable remote delivery mode if requested */ if (RemoteServer && RemoteServer[0]=='\0') { RemoteDefault(); } if (RemoteServer && OpMode == MD_DELIVER && !queuemode && !GrabTo && av[0] != NULL) { int r; r = RemoteMode(from, av, NULL); exit(r); } /* operate in queue directory */ if (chdir(QueueDir) < 0) { syserr("cannot chdir(%s)", QueueDir); exit(EX_SOFTWARE); } /* ** Do operation-mode-dependent initialization. */ switch (OpMode) { case MD_PRINT: /* print the queue */#ifdef QUEUE dropenvelope(CurEnv); printqueue(); exit(EX_OK);#else QUEUE usrerr("No queue to print"); finis();#endif QUEUE case MD_INITALIAS: /* initialize alias database */ initaliases(AliasFile, TRUE); exit(EX_OK); case MD_DAEMON: /* don't open alias database -- done in srvrsmtp */ break; default: /* open the alias database */ initaliases(AliasFile, FALSE); break; }# ifdef DEBUG if (tTd(0, 15)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -