|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 40150 (0x9cd6) Types: TextFile Names: »main.c,v«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z« └─⟦f9e35cd84⟧ └─⟦this⟧ »sendmail/src/RCS/main.c,v«
head 5.29; branch 5.29.0; access; symbols UICSO:5.29.0 VANILLA:5.29; locks; strict; comment @ * @; 5.29 date 90.06.20.08.36.02; author paul; state Exp; branches 5.29.0.1; next ; 5.29.0.1 date 90.06.20.09.43.09; author paul; state Exp; branches; next 5.29.0.2; 5.29.0.2 date 90.06.25.09.20.57; author paul; state Exp; branches; next 5.29.0.3; 5.29.0.3 date 90.07.08.17.46.26; author paul; state Exp; branches; next 5.29.0.4; 5.29.0.4 date 90.07.12.08.01.34; author paul; state Exp; branches; next 5.29.0.5; 5.29.0.5 date 90.08.27.17.15.45; author paul; state Exp; branches; next 5.29.0.6; 5.29.0.6 date 90.09.21.14.48.32; author paul; state Exp; branches; next 5.29.0.7; 5.29.0.7 date 90.10.01.23.07.21; author paul; state Exp; branches; next 5.29.0.8; 5.29.0.8 date 90.10.13.18.42.53; author paul; state Exp; branches; next 5.29.0.9; 5.29.0.9 date 90.10.16.22.49.27; author paul; state Exp; branches; next 5.29.0.10; 5.29.0.10 date 90.10.25.20.19.27; author paul; state Exp; branches; next 5.29.0.11; 5.29.0.11 date 90.11.01.16.45.01; author paul; state Exp; branches; next 5.29.0.12; 5.29.0.12 date 90.11.07.13.55.16; author paul; state Exp; branches; next 5.29.0.13; 5.29.0.13 date 90.11.11.10.37.03; author paul; state Exp; branches; next 5.29.0.14; 5.29.0.14 date 90.11.13.15.29.28; author paul; state Exp; branches; next 5.29.0.15; 5.29.0.15 date 90.11.29.13.59.43; author paul; state Exp; branches; next 5.29.0.16; 5.29.0.16 date 90.12.18.14.57.22; author paul; state Exp; branches; next 5.29.0.17; 5.29.0.17 date 90.12.21.23.52.24; author paul; state Exp; branches; next 5.29.0.18; 5.29.0.18 date 91.01.19.19.26.02; author paul; state Exp; branches; next 5.29.0.19; 5.29.0.19 date 91.02.15.20.20.13; author paul; state Exp; branches; next 5.29.0.20; 5.29.0.20 date 91.02.17.04.30.19; author paul; state Exp; branches; next 5.29.0.21; 5.29.0.21 date 91.03.06.15.17.14; author paul; state Exp; branches; next ; desc @@ 5.29 log @5.64 Berkeley release @ text @/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted provided * that: (1) source distributions retain this entire copyright notice and * comment, and (2) distributions including binaries display the following * acknowledgement: ``This product includes software developed by the * University of California, Berkeley and its contributors'' in the * documentation or other materials provided with the distribution and in * all advertising materials mentioning features or use of this software. * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint char copyright[] = "@@(#) Copyright (c) 1988 Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@@(#)main.c 5.29 (Berkeley) 6/1/90"; #endif /* not lint */ #define _DEFINE #include <sys/file.h> #include <signal.h> #include <sgtty.h> #include "sendmail.h" #include <arpa/nameser.h> #include <resolv.h> # ifdef lint char 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) ** 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 */ { "", "", "" }; /* ** 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 SETPROCTITLE char **Argv = NULL; /* pointer to argument vector */ char *LastArgv = NULL; /* end of argv */ # endif SETPROCTITLE #ifdef DAEMON #ifndef SMTP ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR #endif SMTP #endif DAEMON main(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; static bool reenter = FALSE; char jbuf[30]; /* 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 **environ; /* ** 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; /* Enforce use of local time */ unsetenv("TZ"); /* ** Be sure we have enough file descriptors. ** But also be sure that 0, 1, & 2 are open. */ i = open("/dev/null", O_RDWR); while (i >= 0 && i < 2) i = dup(i); for (i = getdtablesize(); i > 2; --i) (void) close(i); errno = 0; #ifdef LOG_MAIL openlog("sendmail", LOG_PID, LOG_MAIL); #else openlog("sendmail", LOG_PID); #endif /* ** 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; 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); } } InChannel = stdin; OutChannel = stdout; 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 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"); errno = 0; from = NULL; if (readconfig) { /* initialize some macros, etc. */ initmacros(); /* hostname */ av = myhostname(jbuf, sizeof jbuf); if (jbuf[0] != '\0') { if (tTd(0, 4)) printf("canonical name: %s\n", jbuf); p = newstr(jbuf); define('w', p, CurEnv); setclass('w', p); } while (av != NULL && *av != NULL) { if (tTd(0, 4)) printf("\ta.k.a.: %s\n", *av); setclass('w', *av++); } /* 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: # ifdef DAEMON if (getuid() != 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_ARPAFTP: case MD_DELIVER: case MD_VERIFY: case MD_TEST: case MD_INITALIAS: case MD_PRINT: case MD_FREEZE: OpMode = p[2]; break; default: usrerr("Invalid operation mode %c", p[2]); ExitStat = EX_USAGE; break; } break; case 'C': /* select configuration file (already done) */ break; case 'd': /* debugging -- redo in case frozen */ tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(&p[2]); setbuf(stdout, (char *) NULL); #ifdef NAMED_BIND _res.options |= RES_DEBUG; #endif break; case 'f': /* from address */ case 'r': /* obsolete -f flag */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) { p = *++av; if (p == NULL || *p == '-') { usrerr("No \"from\" person"); ExitStat = EX_USAGE; av--; break; } } if (from != NULL) { usrerr("More than one \"from\" person"); ExitStat = EX_USAGE; break; } from = newstr(p); break; case 'F': /* set full name */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) { usrerr("Bad -F flag"); ExitStat = EX_USAGE; av--; break; } FullName = newstr(p); break; case 'h': /* hop count */ p += 2; if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p))) { usrerr("Bad hop count (%s)", p); ExitStat = EX_USAGE; 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 if (getuid() != 0) { usrerr("Permission denied"); exit (EX_USAGE); } (void) unsetenv("HOSTALIASES"); queuemode = TRUE; QueueIntvl = convtime(&p[2]); # else QUEUE usrerr("I don't know about queues"); ExitStat = EX_USAGE; # 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 } } /* ** Do basic initialization. ** Read system control file. ** Extract special fields for local use. */ if (OpMode == MD_FREEZE || readconfig) readcf(ConfFile); 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; /* 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; } if (tTd(0, 15)) { /* print configuration table (or at least part of it) */ printrules(); for (i = 0; i < MAXMAILERS; i++) { register struct mailer *m = Mailer[i]; int j; if (m == NULL) continue; printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name, m->m_mailer, m->m_s_rwset, m->m_r_rwset, m->m_maxsize); for (j = '\0'; j <= '\177'; j++) if (bitnset(j, m->m_flags)) (void) putchar(j); printf(" E="); xputs(m->m_eol); printf("\n"); } } /* ** Switch to the main envelope. */ CurEnv = newenvelope(&MainEnvelope); MainEnvelope.e_flags = BlankEnvelope.e_flags; /* ** If test mode, read addresses from stdin and process. */ if (OpMode == MD_TEST) { char buf[MAXLINE]; printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n"); for (;;) { register char **pvp; char *q; extern char *DelimChar; printf("> "); (void) fflush(stdout); if (fgets(buf, sizeof buf, stdin) == NULL) finis(); for (p = buf; isspace(*p); p++) continue; q = p; while (*p != '\0' && !isspace(*p)) p++; if (*p == '\0') continue; *p = '\0'; do { extern char **prescan(); char pvpbuf[PSBUFSIZE]; pvp = prescan(++p, ',', pvpbuf); if (pvp == NULL) continue; rewrite(pvp, 3); p = q; while (*p != '\0') { rewrite(pvp, atoi(p)); while (*p != '\0' && *p++ != ',') continue; } } while (*(p = DelimChar) != '\0'); } } # ifdef QUEUE /* ** If collecting stuff from the queue, go start doing that. */ if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) { runqueue(FALSE); finis(); } # endif QUEUE /* ** If a daemon, wait for a request. ** getrequests will always return in a child. ** If we should also be processing the queue, start ** doing it in background. ** We check for any errors that might have happened ** during startup. */ if (OpMode == MD_DAEMON || QueueIntvl != 0) { if (!tTd(0, 1)) { /* put us in background */ i = fork(); if (i < 0) syserr("daemon: cannot fork"); if (i != 0) exit(0); /* get our pid right */ MotherPid = getpid(); /* disconnect from our controlling tty */ disconnect(TRUE); } # ifdef QUEUE if (queuemode) { runqueue(TRUE); if (OpMode != MD_DAEMON) for (;;) pause(); } # endif QUEUE dropenvelope(CurEnv); #ifdef DAEMON getrequests(); /* at this point we are in a child: reset state */ OpMode = MD_SMTP; (void) newenvelope(CurEnv); openxscript(CurEnv); #endif DAEMON } # ifdef SMTP /* ** If running SMTP protocol, start collecting and executing ** commands. This will never return. */ if (OpMode == MD_SMTP) smtp(); # endif SMTP /* ** Do basic system initialization and set the sender */ initsys(); setsender(from); if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo) { usrerr("Recipient names must be specified"); /* collect body for UUCP return */ if (OpMode != MD_VERIFY) collect(FALSE); finis(); } if (OpMode == MD_VERIFY) SendMode = SM_VERIFY; /* ** Scan argv and deliver the message to everyone. */ sendtoargv(av); /* if we have had errors sofar, arrange a meaningful exit stat */ if (Errors > 0 && ExitStat == EX_OK) ExitStat = EX_USAGE; /* ** Read the input mail. */ CurEnv->e_to = NULL; if (OpMode != MD_VERIFY || GrabTo) collect(FALSE); errno = 0; /* collect statistics */ if (OpMode != MD_VERIFY) markstats(CurEnv, (ADDRESS *) NULL); if (tTd(1, 1)) printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); /* ** Actually send everything. ** If verifying, just ack. */ CurEnv->e_from.q_flags |= QDONTSEND; CurEnv->e_to = NULL; sendall(CurEnv, SM_DEFAULT); /* ** All done. */ finis(); } \f /* ** FINIS -- Clean up and exit. ** ** Parameters: ** none ** ** Returns: ** never ** ** Side Effects: ** exits sendmail */ finis() { if (tTd(2, 1)) printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags); /* clean up temp files */ CurEnv->e_to = NULL; dropenvelope(CurEnv); /* post statistics */ poststats(StatFile); /* and exit */ # ifdef LOG if (LogLevel > 11) syslog(LOG_DEBUG, "finis, pid=%d", getpid()); # endif LOG if (ExitStat == EX_TEMPFAIL) ExitStat = EX_OK; exit(ExitStat); } \f /* ** INTSIG -- clean up on interrupt ** ** This just arranges to exit. It pessimises in that it ** may resend a message. ** ** Parameters: ** none. ** ** Returns: ** none. ** ** Side Effects: ** Unlocks the current job. */ intsig() { FileName = NULL; unlockqueue(CurEnv); exit(EX_OK); } \f /* ** INITMACROS -- initialize the macro system ** ** This just involves defining some macros that are actually ** used internally as metasymbols to be themselves. ** ** Parameters: ** none. ** ** Returns: ** none. ** ** Side Effects: ** initializes several macros to be themselves. */ struct metamac { char metaname; char metaval; }; struct metamac MetaMacros[] = { /* LHS pattern matching characters */ '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS, '~', MATCHNCLASS, /* these are RHS metasymbols */ '#', CANONNET, '@@', CANONHOST, ':', CANONUSER, '>', CALLSUBR, /* the conditional operations */ '?', CONDIF, '|', CONDELSE, '.', CONDFI, /* and finally the hostname lookup characters */ '[', HOSTBEGIN, ']', HOSTEND, '\0' }; initmacros() { register struct metamac *m; char buf[5]; register int c; for (m = MetaMacros; m->metaname != '\0'; m++) { buf[0] = m->metaval; buf[1] = '\0'; define(m->metaname, newstr(buf), CurEnv); } buf[0] = MATCHREPL; buf[2] = '\0'; for (c = '0'; c <= '9'; c++) { buf[1] = c; define(c, newstr(buf), CurEnv); } } \f /* ** FREEZE -- freeze BSS & allocated memory ** ** This will be used to efficiently load the configuration file. ** ** Parameters: ** freezefile -- the name of the file to freeze to. ** ** Returns: ** none. ** ** Side Effects: ** Writes BSS and malloc'ed memory to freezefile */ union frz { char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */ struct { time_t frzstamp; /* timestamp on this freeze */ char *frzbrk; /* the current break */ char *frzedata; /* address of edata */ char *frzend; /* address of end */ char frzver[252]; /* sendmail version */ } frzinfo; }; freeze(freezefile) char *freezefile; { int f; union frz fhdr; extern char edata, end; extern char *sbrk(); extern char Version[]; if (freezefile == NULL) return; /* try to open the freeze file */ f = creat(freezefile, FileMode); if (f < 0) { syserr("Cannot freeze %s", freezefile); errno = 0; return; } /* build the freeze header */ fhdr.frzinfo.frzstamp = curtime(); fhdr.frzinfo.frzbrk = sbrk(0); fhdr.frzinfo.frzedata = &edata; fhdr.frzinfo.frzend = &end; (void) strcpy(fhdr.frzinfo.frzver, Version); /* write out the freeze header */ if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr || write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != (int) (fhdr.frzinfo.frzbrk - &edata)) { syserr("Cannot freeze %s", freezefile); } /* fine, clean up */ (void) close(f); } \f /* ** THAW -- read in the frozen configuration file. ** ** Parameters: ** freezefile -- the name of the file to thaw from. ** ** Returns: ** TRUE if it successfully read the freeze file. ** FALSE otherwise. ** ** Side Effects: ** reads freezefile in to BSS area. */ thaw(freezefile) char *freezefile; { int f; union frz fhdr; extern char edata, end; extern char Version[]; extern caddr_t brk(); if (freezefile == NULL) return (FALSE); /* open the freeze file */ f = open(freezefile, 0); if (f < 0) { syslog(LOG_WARNING, "Cannot open frozen config file %s: %m", freezefile); errno = 0; return (FALSE); } /* read in the header */ if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr) { syserr("Cannot read frozen config file"); (void) close(f); return (FALSE); } if ( fhdr.frzinfo.frzedata != &edata || fhdr.frzinfo.frzend != &end || strcmp(fhdr.frzinfo.frzver, Version) != 0) { syslog(LOG_WARNING, "Wrong version of frozen config file"); (void) close(f); return (FALSE); } /* arrange to have enough space */ if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1) { syserr("Cannot break to %x", fhdr.frzinfo.frzbrk); (void) close(f); return (FALSE); } /* now read in the freeze file */ if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != (int) (fhdr.frzinfo.frzbrk - &edata)) { syserr("Cannot read frozen config file"); /* oops! we have trashed memory..... */ (void) write(2, "Cannot read freeze file\n", 24); _exit(EX_SOFTWARE); } (void) close(f); return (TRUE); } \f /* ** DISCONNECT -- remove our connection with any foreground process ** ** Parameters: ** fulldrop -- if set, we should also drop the controlling ** TTY if possible -- this should only be done when ** setting up the daemon since otherwise UUCP can ** leave us trying to open a dialin, and we will ** wait for the carrier. ** ** Returns: ** none ** ** Side Effects: ** Trys to insure that we are immune to vagaries of ** the controlling tty. */ disconnect(fulldrop) bool fulldrop; { int fd; if (tTd(52, 1)) printf("disconnect: In %d Out %d\n", fileno(InChannel), fileno(OutChannel)); if (tTd(52, 5)) { printf("don't\n"); return; } /* be sure we don't get nasty signals */ (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); /* we can't communicate with our caller, so.... */ HoldErrs = TRUE; ErrorMode = EM_MAIL; Verbose = FALSE; /* all input from /dev/null */ if (InChannel != stdin) { (void) fclose(InChannel); InChannel = stdin; } (void) freopen("/dev/null", "r", stdin); /* output to the transcript */ if (OutChannel != stdout) { (void) fclose(OutChannel); OutChannel = stdout; } if (CurEnv->e_xfp == NULL) CurEnv->e_xfp = fopen("/dev/null", "w"); (void) fflush(stdout); (void) close(1); (void) close(2); while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0) continue; #ifdef TIOCNOTTY /* drop our controlling TTY completely if possible */ if (fulldrop) { fd = open("/dev/tty", 2); if (fd >= 0) { (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); (void) close(fd); } (void) setpgrp(0, 0); errno = 0; } #endif TIOCNOTTY # ifdef LOG if (LogLevel > 11) syslog(LOG_DEBUG, "in background, pid=%d", getpid()); # endif LOG errno = 0; } @ 5.29.0.1 log @IDA patches @ text @d118 1 a118 1 char jbuf[60]; /* holds MyHostName */ a125 1 extern char *index(); d142 1 a142 1 (void) unsetenv("TZ"); a143 3 /* Make mail act uniformly (resolver recursion disabled elsewhere) */ (void) unsetenv("HOSTALIASES"); a200 8 else if (strncmp(p, "-Z", 2) == 0) { FreezeFile = &p[2]; if (FreezeFile[0] == '\0') FreezeFile = "sendmail.fc"; (void) setgid(getrgid()); (void) setuid(getruid()); } d205 1 a205 1 setlinebuf(stdout); a261 4 if ((p = index(jbuf, '.')) != NULL) *p = '\0'; makelower(jbuf); define('k', newstr(jbuf), CurEnv); a290 2 else if (strcmp(p, "bsmtp") == 0) OpMode = MD_BSMTP; d304 1 a310 1 case MD_BSMTP: a335 3 case 'Z': /* select frozen config file (already done) */ break; d339 1 a339 1 setlinebuf(stdout); a340 1 if (tTd(8, 8)) d406 1 d518 1 a518 1 initaliases(TRUE); d527 1 a527 1 initaliases(FALSE); d542 3 a544 4 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name, m->m_mailer, m->m_se_rwset, m->m_sh_rwset, m->m_re_rwset, m->m_rh_rwset, m->m_maxsize); a569 1 printf("[Note: No initial ruleset 3 call]\n"); d596 1 a596 1 /* rewrite(pvp, 3); */ d674 2 a675 11 if (OpMode == MD_SMTP || OpMode == MD_BSMTP) { bool batched = (OpMode == MD_BSMTP); OpMode = MD_SMTP; #ifdef notdef /* test without this first */ /* have to run unbuffered or else will lose synchronization */ if (batched) setbuf(InChannel, (char *) NULL); #endif notdef smtp(batched); } d810 6 d828 1 a828 1 /* and finally the hostname and database lookup characters */ a829 1 '(', KEYBEGIN, ')', KEYEND, a830 7 #ifdef MACVALUE /* run-time macro expansion, not at freeze time */ '&', MACVALUE, #endif #ifdef QUOTE822 '!', QUOTE822, /* quote next macro if RFC822 requires it */ #endif a878 1 char frzdatecompiled[64]; /* sendmail compilation date */ a889 1 extern char datecompiled[]; a908 1 (void) strcpy(fhdr.frzinfo.frzdatecompiled, datecompiled); a941 1 extern char datecompiled[]; d966 1 a966 2 strcmp(fhdr.frzinfo.frzver, Version) != 0 || strcmp(fhdr.frzinfo.frzdatecompiled, datecompiled) != 0) d1033 1 a1033 1 setoption('e', "m", TRUE, TRUE); @ 5.29.0.2 log @Patches for HP-UX from Andy Linton <root@@comp.vuw.ac.nz>. Thanks Andy! @ text @a141 1 #if !defined(hpux) a143 1 #endif /* hpux */ a216 3 #if defined(hpux) setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ); #else a217 1 #endif /* hpux */ a359 4 tTflag(&p[2]); #if defined(hpux) setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ); #else a360 1 #endif /* hpux */ @ 5.29.0.3 log @Some syslog() and the openlog() calls were not #ifdef LOG. @ text @a161 1 #ifdef LOG a166 1 #endif /* LOG */ a999 1 #ifdef LOG a1001 1 #endif /* LOG */ a1017 1 #ifdef LOG a1018 1 #endif /* LOG */ @ 5.29.0.4 log @From: kessler@@hacketorium.Eng.Sun.COM (Tom Kessler) Newsgroups: comp.bugs.4bsd,comp.mail.sendmail Subject: bug in sendmail 5.64 Date: 11 Jul 90 20:52:35 GMT Organization: Rocket Scientists Anonymous In sendmail 5.64 a new field name q_ruser was added to the address structure (found in sendmail.h). The initialization of the variable NullAddress (in main.c) was not updated to reflect this. This can cause some problems when you go to look at the q_host field or expect the q_ruser field to be NULL. @ text @d81 1 a81 1 { "", "", NULL, "" }; @ 5.29.0.5 log @Use MAXHOSTNAMELEN from sys/param.h instead of a hardwired 64. Provide a default value for older systems. Don't set FullName in either daemon (-bd) or queue-run (-q) mode. Unsetenv(LOCALDOMAIN) as well as HOSTALIASES. From suggestions by Charles Seeger, Neil Rickert, and Mark D. Baushke. @ text @a38 4 #include <sys/param.h> #ifndef MAXHOSTNAMELEN # define MAXHOSTNAMELEN 64 #endif /* !MAXHOSTNAMELEN */ a115 1 bool NoName = FALSE; d118 1 a118 1 char jbuf[MAXHOSTNAMELEN+1]; /* holds MyHostName */ a148 1 (void) unsetenv("LOCALDOMAIN"); a208 2 else if (strncmp(p, "-bd", 3) == 0 || strncmp(p, "-q", 2) == 0) NoName = TRUE; d263 1 a263 1 FullName = (NoName) ? NULL : getenv("NAME"); @ 5.29.0.6 log @Changed delimiter character in prescan() call during address test mode (-bt) to '\0' from ','. Otherwise checking internal rulesets with comma separated pieces becomes dicey. @ text @d637 1 a637 1 pvp = prescan(++p, '\0', pvpbuf); @ 5.29.0.7 log @Changes from Berkeley's 5.64 to 5.65 release (main.c, savemail.c, and version.c) @ text @d28 1 a28 1 static char sccsid[] = "@@(#)main.c 5.31 (Berkeley) 7/20/90"; a32 1 #include <sys/param.h> d46 1 a46 1 # endif /* lint */ d97 1 a97 1 # endif /* SETPROCTITLE */ d102 2 a103 2 #endif /* SMTP */ #endif /* DAEMON */ d173 1 a173 1 #endif /* LOG_MAIL */ d260 1 a260 1 # endif /* SETPROCTITLE */ d342 1 a342 1 # endif /* DAEMON */ d349 1 a349 1 # endif /* SMTP */ d385 1 a385 1 #endif /* NAMED_BIND */ d451 1 a451 1 # else /* !QUEUE */ d454 1 a454 1 # endif /* QUEUE */ d479 1 a479 1 # endif /* DBM */ d553 1 a553 1 #else /* !QUEUE */ d556 1 a556 1 #endif /* QUEUE */ d662 1 a662 1 # endif /* QUEUE */ d699 1 a699 1 # endif /* QUEUE */ d709 1 a709 1 #endif /* DAEMON */ d726 1 a726 1 #endif /* notdef */ d729 1 a729 1 # endif /* SMTP */ d820 1 a820 1 # endif /* LOG */ d882 1 a882 1 #endif /* MACVALUE */ d885 1 a885 1 #endif /* QUOTE822 */ d1122 1 a1125 4 #if BSD > 43 daemon(1, 1); #else /* BSD <= 43 */ #ifdef TIOCNOTTY a1132 2 #endif /* TIOCNOTTY */ #endif /* BSD */ d1135 1 d1140 1 a1140 1 # endif /* LOG */ @ 5.29.0.8 log @Neil Rickert's (rickert@@cs.niu.edu) res_init() fix. Other bug fixes and System 5 changes from Bruce Lilly (bruce%balilly@@sonyd1.broadcast.sony.com). @ text @d25 3 a28 3 # ifdef __GNUC__ static char compiled[] = "@@(#)compiled by gcc version "__VERSION__; # endif /* __GNUC__ */ d33 2 d38 3 a40 5 #include <sys/file.h> #ifdef NAMED_BIND # include <arpa/nameser.h> # include <resolv.h> #endif /* NAMED_BIND */ d132 1 a250 5 #ifdef NAMED_BIND /* Make sure the resolver library is initialized */ res_init(); #endif /* NAMED_BIND */ d770 4 a785 4 /* collect statistics (done after sendall, since sendall may fork) */ if (OpMode != MD_VERIFY) markstats(CurEnv, (ADDRESS *) NULL); d1129 1 a1129 1 # ifdef TIOCNOTTY d1137 1 a1137 1 # endif /* TIOCNOTTY */ a1138 5 #if !defined(BSD) && !defined(TIOCNOTTY) && defined(SYSTEM5) setpgrp(); if (fork() != 0) exit(0); #endif /* !BSD && !TIOCNOTTY && SYSTEM5 */ @ 5.29.0.9 log @To: paul-pomes@@uiuc.edu Subject: sendmail-5.65 incorrectly handles MX records with equal precedence Date: Tue, 16 Oct 90 23:10:18 EDT From: "David Edelsohn" <edelsohn@@nova.npac.syr.edu> Description: I was just looking up the source to sendmail-5.61 to see why the mail load is not being evenly distributed between my two hosts pointed to by MX records with the same preference level. In domain.c: getmxrr(), the MX records are sorted by preference with a special case if the preferences are identical. The condition is as follows: if (prefer[i] > prefer[j] || (prefer[i] == prefer[j] && rand() % 1 == 0)) { ...SWAP ENTRIES... } Should not the test be (rand() & 01) or (rand() % 2)? (rand() % 1) is always 0! rand() is not guaranteed to be random in the lowest bits as random() is suppose to be, but even regularly alternating between swapping and not swapping would be better than always swapping when preferences are equal. Not only does rand() % 1 always return 0, not only does rand() & 1 alternate between 0 and 1 regularly at each call (as long as the load is balanced it doesn't really matter), but since sendmail is called directly by Mail, the random number generator is reset to the same value each time (for both rand() and random()), i.e there is no call to srandom() with the PID or time-of-day or some other seed. This appears to be the only use of a random number generator within sendmail so only one MX record of equal precedence will be used assuming that the records are always returned in the same order at each DNS resolver call. The only saving grace would be if a queued message has the MX host re-calculated by the daemonized sendmail if the message is ever queued, but with (rand % 1) this is irrelevent in sendmail-5.61. Fix: 1) Change "rand % 1" to "rand & 1" 2) No matter which random number generator is used (rand() or random()), use the appropriate seed initializer call during the initial startup (in main.c?). The seed must be set post-thaw. @ text @a275 1 srand(MotherPid); @ 5.29.0.10 log @Added unixpc specific setbuf() call to unbuffer stdout. @ text @d231 1 a231 4 #else /* !hpux */ # if defined(unixpc) setbuf(stdout, (char *)NULL); # else /* !unixpc */ a232 1 # endif /* unixpc */ d384 2 a385 5 setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ); #else /* !hpux */ # if defined(unixpc) setbuf(stdout, (char *)NULL); # else /* !unixpc */ a386 1 # endif /* unixpc */ @ 5.29.0.11 log @Systems like Next machines don't have brk()/sbrk() so freeze()/thaw() become no-ops #ifdef NeXT. Made signal() usage more baroque. @ text @d271 1 a271 1 if (signal(SIGINT, SIG_IGN) != (SIG_TYPE (*)()) SIG_IGN) d273 1 a273 1 if (signal(SIGHUP, SIG_IGN) != (SIG_TYPE (*)()) SIG_IGN) a954 5 #if defined(NeXT) syserr("Cannot freeze %s on systems w.o. brk/sbrk", freezefile); errno = 0; return; #else /* !NeXT */ a991 1 #endif /* NeXT */ a1009 4 #if defined(NeXT) errno = 0; return (FALSE); #else /* !NeXT */ a1070 1 #endif /* NeXT */ @ 5.29.0.12 log @Relocate IN_SCCS_ID @ text @a21 1 # define IN_SCCS_ID d31 1 a31 1 #define _DEFINE @ 5.29.0.13 log @From: forys@@snake.utah.edu (Jeff Forys) Newsgroups: comp.mail.sendmail Date: 10 Nov 90 01:48:40 MST Organization: University of Utah CS Dept Subject: Sendmail 5.65 can loop on certain addresses +FIX Index: usr.lib/sendmail/src/parseaddr.c 4.3BSD This applies to all known versions of sendmail (through "5.65"). Description: Sendmail reserves characters in the range 020 - 036 for coding its rewrite rules. If one of these characters shows up in an address, the results are unpredictable (from a user's point of view). Specifically, an address containing a "replacement on RHS" rule can cause sendmail to go into an infinite loop while processing various rewrite rules. I suppose this could be used for a denial-of-service attack; if an evil-minded person fired off a bunch of these in your direction, you would end up with an equal number of sendmail processes churning endlessly away on your CPU. Of course, whence such an "attack" originates would be painfully obvious! @ text @a646 2 if (invalidaddr(p+1)) continue; @ 5.29.0.14 log @Changed hpux to XPG3 (X-Open Portability Guide 3) that's set in sendmail.h. From Andy Linton (andy.linton@@comp.vuw.ac.nz). @ text @d37 1 a164 3 #if defined(XPG3) for (i = (int) sysconf (_SC_OPEN_MAX); i > 2; --i) #else a165 1 #endif /* XPG3 */ d230 1 a230 1 #if defined(XPG3) d232 1 a232 1 #else /* !XPG3 */ d238 1 a238 1 #endif /* XPG3 */ d256 1 a256 4 /* ** Make sure the resolver library is initialized and that enough time ** is allowed for non-local servers. */ a257 1 _res.retrans = 30; d388 1 a388 1 #if defined(XPG3) d390 1 a390 1 #else /* !XPG3 */ d396 1 a396 1 #endif /* XPG3 */ d1153 1 a1153 10 #if defined(XPG3) /* * setsid will provide a new session w/o any tty associated at all. * STANDARDS CONFORMANCE * setpgrp: SVID2, XPG2 * setsid: XPG3, POSIX.1, FIPS 151-1 */ (void) setsid(); #else /* !XPG3 */ # if BSD > 43 d1155 2 a1156 2 # else /* BSD <= 43 */ # ifdef TIOCNOTTY d1164 3 a1166 3 # endif /* TIOCNOTTY */ # endif /* BSD */ # if !defined(BSD) && !defined(TIOCNOTTY) && defined(SYSV) d1170 1 a1170 2 # endif /* !BSD && !TIOCNOTTY && SYSV */ #endif /* XPG3 */ @ 5.29.0.15 log @Freeze/thaw code now included only if _PATH_SENDMAILFC is #define'd in pathnames.h . Print the loadaverage for -d3.1. Change intsig() declaration to SIG_TYPE. @ text @d129 1 a129 1 extern SIG_TYPE intsig(); a222 1 #ifdef _PATH_SENDMAILFC a227 4 #else /* !_PATH_SENDMAILFC */ /* Use printf since OutChannel isn't assigned yet */ printf("Frozen configuration files not available\n"); #endif /* _PATH_SENDMAILFC */ a245 2 if (tTd(3, 1)) (void) getla(); /* prints load average in getla() */ a248 1 #ifdef _PATH_SENDMAILFC a250 1 #endif /* _PATH_SENDMAILFC */ a516 1 #ifdef _PATH_SENDMAILFC a523 4 #else /* !_PATH_SENDMAILFC */ usrerr("Frozen configuration files not available"); exit(EX_USAGE); #endif /* _PATH_SENDMAILFC */ a864 1 SIG_TYPE d933 1 a933 3 \f #ifdef _PATH_SENDMAILFC /* d965 5 d1007 1 d1026 4 d1044 1 a1044 1 # ifdef LOG d1047 1 a1047 1 # endif /* LOG */ d1064 1 a1064 1 # ifdef LOG d1066 1 a1066 1 # endif /* LOG */ d1091 1 a1092 1 #endif /* _PATH_SENDMAILFC */ @ 5.29.0.16 log @NIS (nee YP) state is saved in the freeze, the readback of the freeze file destroys similar information. This causes strange results later due to the unexpected closing of a file descriptor using a stale copy. Roger D. Roles rdr@@Alliant.COM Rob McMahon cudcv@@warwick.ac.uk @ text @a990 8 # ifdef YP { /* * NIS (nee YP) state is saved in the freeze, the readback * of the freeze file destroys similar information. This * causes strange results later due to the unexpected closing * of a file descriptor using a stale copy. */ a991 6 char *domain; if (yp_get_default_domain(&domain) == 0) yp_unbind(domain); } # endif /* YP */ a1057 14 # ifdef YP { /* * NIS (nee YP) state is saved in the freeze, the readback * of the freeze file destroys similar information. This * causes strange results later due to the unexpected closing * of a file descriptor using a stale copy. */ char *domain; if (yp_get_default_domain(&domain) == 0) yp_unbind(domain); } # endif /* YP */ @ 5.29.0.17 log @Only reset the environment after a successful thaw. Previously the environment was always reset which used a lot of newstr() calls and inflated the size of sendmail.fc. Found by Piet Beertema (piet@@mcsun.eu.net). @ text @d257 3 d261 5 a265 9 /* Reset the environment only after a successful thaw() */ if (!nothaw && (readconfig = !thaw(FreezeFile)) == FALSE) { for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++) UserEnviron[i] = newstr(envp[i]); UserEnviron[i] = NULL; environ = UserEnviron; } #endif /* _PATH_SENDMAILFC */ @ 5.29.0.18 log @Deleted #include <sys/types.h> as it's already included via sendmail.h from useful.h. #include "sendmail.h" relocated to top of #include list. @ text @a33 1 #include "sendmail.h" d36 1 @ 5.29.0.19 log @End of environment incorrectly determined when frozen config file not used. Found by Piet Beertema. @ text @a265 3 else for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++) ; @ 5.29.0.20 log @Added static keyword to declarations of intsig(), initmacros(), freeze(), and thaw(). @ text @d129 1 a129 2 static SIG_TYPE intsig(); static initmacros(), freeze(), thaw(); d883 1 a883 1 static SIG_TYPE a931 1 static a982 1 static a1051 1 static @ 5.29.0.21 log @ANSIfied @ text @a48 12 #ifdef __STDC__ static void intsig(); static void initmacros(); static void freeze(const char *); static thaw(const char *); #else /* !__STDC__ */ static void intsig(); static void initmacros(); static void freeze(); static thaw(); #endif /* __STDC__ */ d113 1 d125 8 d677 1 a846 1 void d884 1 a884 1 static void d933 1 a933 1 static void d985 1 a985 1 static void d987 1 a987 1 const char *freezefile; d1057 1 a1057 1 const char *freezefile; a1153 1 void @