📄 main.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)main.c 8.55 (Berkeley) 4/15/94";#endif /* not lint */#define _DEFINE#include "sendmail.h"#if NAMED_BIND#include <arpa/nameser.h>#include <resolv.h>#endif#include <pwd.h># 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 /usr/lib/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)** Now back at UCB at the Mammoth project.** 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, "" };char *UserEnviron[MAXUSERENVIRON + 2]; /* saved user environment */char RealUserName[256]; /* the actual user id on this host */char *CommandLineArgs; /* command line args for pid file */bool Warn_Q_option = FALSE; /* warn about Q option use *//*** Pointers for setproctitle.** This allows "ps" listings to give more useful information.*/# ifdef SETPROCTITLEchar **Argv = NULL; /* pointer to argument vector */char *LastArgv = NULL; /* end of argv */# endif /* SETPROCTITLE */static void obsolete();#ifdef DAEMON#ifndef SMTPERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR#endif /* SMTP */#endif /* DAEMON */#define MAXCONFIGLEVEL 5 /* highest config version level known */main(argc, argv, envp) int argc; char **argv; char **envp;{ register char *p; char **av; extern int finis(); extern char Version[]; char *ep, *from; typedef int (*fnptr)(); STAB *st; register int i; int j; bool queuemode = FALSE; /* process queue requests */ bool safecf = TRUE; bool warn_C_flag = FALSE; char warn_f_flag = '\0'; static bool reenter = FALSE; char *argv0 = argv[0]; struct passwd *pw; struct stat stb; char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ extern int DtableSize; extern int optind; extern time_t convtime(); extern putheader(), putbody(); extern void intsig(); extern char **myhostname(); extern char *arpadate(); extern char *getauthinfo(); extern char *getcfname(); extern char *optarg; extern char **environ; extern void sigusr1(); /* ** 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; /* do machine-dependent initializations */ init_md(argc, argv); /* arrange to dump state on signal */#ifdef SIGUSR1 setsignal(SIGUSR1, sigusr1);#endif /* in 4.4BSD, the table can be huge; impose a reasonable limit */ DtableSize = getdtsize(); if (DtableSize > 256) DtableSize = 256; /* ** Be sure we have enough file descriptors. ** But also be sure that 0, 1, & 2 are open. */ i = open("/dev/null", O_RDWR, 0); if (fstat(STDIN_FILENO, &stb) < 0 && errno != EOPNOTSUPP) (void) dup2(i, STDIN_FILENO); if (fstat(STDOUT_FILENO, &stb) < 0 && errno != EOPNOTSUPP) (void) dup2(i, STDOUT_FILENO); if (fstat(STDERR_FILENO, &stb) < 0 && errno != EOPNOTSUPP) (void) dup2(i, STDERR_FILENO); if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) (void) close(i); i = DtableSize; while (--i > 0) { if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) (void) close(i); } errno = 0;#ifdef LOG# ifdef LOG_MAIL openlog("sendmail", LOG_PID, LOG_MAIL);# else openlog("sendmail", LOG_PID);# endif#endif /* 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); /* ** Set default values for variables. ** These cannot be in initialized data space. */ setdefaults(&BlankEnvelope); RealUid = getuid(); RealGid = getgid(); pw = getpwuid(RealUid); if (pw != NULL) (void) strcpy(RealUserName, pw->pw_name); else (void) sprintf(RealUserName, "Unknown UID %d", RealUid); /* save command line arguments */ i = 0; for (av = argv; *av != NULL; ) i += strlen(*av++) + 1; CommandLineArgs = xalloc(i); p = CommandLineArgs; for (av = argv; *av != NULL; ) { if (av != argv) *p++ = ' '; strcpy(p, *av++); p += strlen(p); } /* Handle any non-getoptable constructions. */ obsolete(argv); /* ** Do a quick prescan of the argument list. */#if defined(__osf__) || defined(_AIX3)# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:x"#endif#if defined(ultrix)# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mno:p:q:r:sTtvX:"#endif#if defined(NeXT)# define OPTIONS "B:b:C:cd:e:F:f:h:IimnOo:p:q:r:sTtvX:"#endif#ifndef OPTIONS# define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:"#endif while ((j = getopt(argc, argv, OPTIONS)) != EOF) { switch (j) { case 'd': tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(optarg); setbuf(stdout, (char *) NULL); printf("Version %s\n", Version); break; } } InChannel = stdin; OutChannel = stdout; /* ** Move the environment so setproctitle can use the space at ** the top of memory. */ for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++) { if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0) continue; UserEnviron[j++] = newstr(p); } UserEnviron[j] = 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 */ if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) (void) setsignal(SIGINT, intsig); if (setsignal(SIGHUP, SIG_IGN) != SIG_IGN) (void) setsignal(SIGHUP, intsig); (void) setsignal(SIGTERM, intsig); (void) setsignal(SIGPIPE, SIG_IGN); OldUmask = umask(022); OpMode = MD_DELIVER; FullName = getenv("NAME");#if NAMED_BIND if (tTd(8, 8)) _res.options |= RES_DEBUG;#endif errno = 0; from = NULL; /* initialize some macros, etc. */ initmacros(CurEnv); /* version */ define('v', Version, CurEnv); /* hostname */ av = myhostname(jbuf, sizeof jbuf); if (jbuf[0] != '\0') { struct utsname utsname; if (tTd(0, 4)) printf("canonical name: %s\n", jbuf); define('w', newstr(jbuf), CurEnv); /* must be new string */ define('j', newstr(jbuf), CurEnv); setclass('w', jbuf); p = strchr(jbuf, '.'); if (p != NULL) { if (p[1] != '\0') { define('m', newstr(&p[1]), CurEnv); setclass('m', &p[1]); } while (p != NULL && strchr(&p[1], '.') != NULL) { *p = '\0'; setclass('w', jbuf); *p++ = '.'; p = strchr(p, '.'); } } if (uname(&utsname) >= 0) p = utsname.nodename; else { if (tTd(0, 22)) printf("uname failed (%s)\n", errstring(errno)); makelower(jbuf); p = jbuf; } if (tTd(0, 4)) printf("UUCP nodename: %s\n", p); p = newstr(p); define('k', p, CurEnv); setclass('k', p); setclass('w', p); } while (av != NULL && *av != NULL) { if (tTd(0, 4)) printf("\ta.k.a.: %s\n", *av); setclass('w', *av++); } /* current time */ define('b', arpadate((char *) NULL), CurEnv); /* ** Find our real host name for future logging. */ p = getauthinfo(STDIN_FILENO); define('_', p, CurEnv); /* ** Crack argv. */ av = argv; p = strrchr(*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; optind = 1; while ((j = getopt(argc, argv, OPTIONS)) != EOF) { switch (j) { case 'b': /* operations mode */ switch (j = *optarg) { case MD_DAEMON:# ifdef DAEMON if (RealUid != 0) { usrerr("Permission denied"); exit (EX_USAGE); } (void) unsetenv("HOSTALIASES");# else usrerr("Daemon mode not implemented"); ExitStat = EX_USAGE; break;# endif /* DAEMON */ case MD_SMTP:# ifndef SMTP usrerr("I don't speak SMTP"); ExitStat = EX_USAGE; break;# endif /* SMTP */ case MD_DELIVER: case MD_VERIFY: case MD_TEST: case MD_INITALIAS: case MD_PRINT:#ifdef MAYBE_NEXT_RELEASE case MD_ARPAFTP:#endif OpMode = j; break; case MD_FREEZE: usrerr("Frozen configurations unsupported"); ExitStat = EX_USAGE; break; default: usrerr("Invalid operation mode %c", j); ExitStat = EX_USAGE; break; } break; case 'B': /* body type */ CurEnv->e_bodytype = newstr(optarg); break; case 'C': /* select configuration file (already done) */ if (RealUid != 0) warn_C_flag = TRUE; ConfFile = optarg; (void) setgid(RealGid); (void) setuid(RealUid); safecf = FALSE; break; case 'd': /* debugging -- already done */ break; case 'f': /* from address */ case 'r': /* obsolete -f flag */ if (from != NULL) { usrerr("More than one \"from\" person"); ExitStat = EX_USAGE; break; } from = newstr(optarg); if (strcmp(RealUserName, from) != 0) warn_f_flag = j; break; case 'F': /* set full name */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -