|
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 d
Length: 50880 (0xc6c0) Types: TextFile Names: »deliver.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/deliver.c,v«
head 5.38; branch 5.38.0; access; symbols UICSO:5.38.0 VANILLA:5.38; locks; strict; comment @ * @; 5.38 date 90.06.20.08.35.40; author paul; state Exp; branches 5.38.0.1; next ; 5.38.0.1 date 90.06.20.09.42.49; author paul; state Exp; branches; next 5.38.0.2; 5.38.0.2 date 90.06.21.13.47.24; author paul; state Exp; branches; next 5.38.0.3; 5.38.0.3 date 90.06.25.09.20.43; author paul; state Exp; branches; next 5.38.0.4; 5.38.0.4 date 90.07.09.10.06.16; author paul; state Exp; branches; next 5.38.0.5; 5.38.0.5 date 90.08.02.12.44.33; author paul; state Exp; branches; next 5.38.0.6; 5.38.0.6 date 90.09.22.18.40.25; author paul; state Exp; branches; next 5.38.0.7; 5.38.0.7 date 90.09.25.09.45.07; author paul; state Exp; branches; next 5.38.0.8; 5.38.0.8 date 90.10.13.18.18.14; author paul; state Exp; branches; next 5.38.0.9; 5.38.0.9 date 90.11.01.17.14.47; author paul; state Exp; branches; next 5.38.0.10; 5.38.0.10 date 90.11.19.16.16.28; author paul; state Exp; branches; next 5.38.0.11; 5.38.0.11 date 90.11.24.02.47.45; author paul; state Exp; branches; next 5.38.0.12; 5.38.0.12 date 90.11.26.20.39.58; author paul; state Exp; branches; next 5.38.0.13; 5.38.0.13 date 90.12.30.19.27.12; author paul; state Exp; branches; next 5.38.0.14; 5.38.0.14 date 91.01.19.19.26.02; author paul; state Exp; branches; next 5.38.0.15; 5.38.0.15 date 91.02.15.16.59.22; author paul; state Exp; branches; next 5.38.0.16; 5.38.0.16 date 91.02.17.04.04.34; author paul; state Exp; branches; next 5.38.0.17; 5.38.0.17 date 91.03.04.21.48.23; author paul; state Exp; branches; next 5.38.0.18; 5.38.0.18 date 91.03.06.13.58.47; author paul; state Exp; branches; next ; desc @@ 5.38 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 static char sccsid[] = "@@(#)deliver.c 5.38 (Berkeley) 6/1/90"; #endif /* not lint */ #include "sendmail.h" #include <sys/signal.h> #include <sys/stat.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> #ifdef NAMED_BIND #include <arpa/nameser.h> #include <resolv.h> #endif /* ** DELIVER -- Deliver a message to a list of addresses. ** ** This routine delivers to everyone on the same host as the ** user on the head of the list. It is clever about mailers ** that don't handle multiple users. It is NOT guaranteed ** that it will deliver to all these addresses however -- so ** deliver should be called once for each address on the ** list. ** ** Parameters: ** e -- the envelope to deliver. ** firstto -- head of the address list to deliver to. ** ** Returns: ** zero -- successfully delivered. ** else -- some failure, see ExitStat for more info. ** ** Side Effects: ** The standard input is passed off to someone. */ deliver(e, firstto) register ENVELOPE *e; ADDRESS *firstto; { char *host; /* host being sent to */ char *user; /* user being sent to */ char **pvp; register char **mvp; register char *p; register MAILER *m; /* mailer for this recipient */ ADDRESS *ctladdr; register ADDRESS *to = firstto; bool clever = FALSE; /* running user smtp to this mailer */ ADDRESS *tochain = NULL; /* chain of users in this mailer call */ int rcode; /* response code */ char *pv[MAXPV+1]; char tobuf[MAXLINE-50]; /* text line of to people */ char buf[MAXNAME]; char tfrombuf[MAXNAME]; /* translated from person */ extern bool checkcompat(); extern ADDRESS *getctladdr(); extern char *remotename(); errno = 0; if (bitset(QDONTSEND, to->q_flags)) return (0); #ifdef NAMED_BIND /* unless interactive, try twice, over a minute */ if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { _res.retrans = 30; _res.retry = 2; } #endif m = to->q_mailer; host = to->q_host; if (tTd(10, 1)) printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", m->m_mno, host, to->q_user); /* ** If this mailer is expensive, and if we don't want to make ** connections now, just mark these addresses and return. ** This is useful if we want to batch connections to ** reduce load. This will cause the messages to be ** queued up, and a daemon will come along to send the ** messages later. ** This should be on a per-mailer basis. */ if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) { for (; to != NULL; to = to->q_next) { if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) continue; to->q_flags |= QQUEUEUP|QDONTSEND; e->e_to = to->q_paddr; message(Arpa_Info, "queued"); if (LogLevel > 4) logdelivery("queued"); } e->e_to = NULL; return (0); } /* ** Do initial argv setup. ** Insert the mailer name. Notice that $x expansion is ** NOT done on the mailer name. Then, if the mailer has ** a picky -f flag, we insert it as appropriate. This ** code does not check for 'pv' overflow; this places a ** manifest lower limit of 4 for MAXPV. ** The from address rewrite is expected to make ** the address relative to the other end. */ /* rewrite from address, using rewriting rules */ expand("\001f", buf, &buf[sizeof buf - 1], e); (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); define('g', tfrombuf, e); /* translated sender address */ define('h', host, e); /* to host */ Errors = 0; pvp = pv; *pvp++ = m->m_argv[0]; /* insert -f or -r flag as appropriate */ if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) { if (bitnset(M_FOPT, m->m_flags)) *pvp++ = "-f"; else *pvp++ = "-r"; expand("\001g", buf, &buf[sizeof buf - 1], e); *pvp++ = newstr(buf); } /* ** Append the other fixed parts of the argv. These run ** up to the first entry containing "$u". There can only ** be one of these, and there are only a few more slots ** in the pv after it. */ for (mvp = m->m_argv; (p = *++mvp) != NULL; ) { while ((p = index(p, '\001')) != NULL) if (*++p == 'u') break; if (p != NULL) break; /* this entry is safe -- go ahead and process it */ expand(*mvp, buf, &buf[sizeof buf - 1], e); *pvp++ = newstr(buf); if (pvp >= &pv[MAXPV - 3]) { syserr("Too many parameters to %s before $u", pv[0]); return (-1); } } /* ** If we have no substitution for the user name in the argument ** list, we know that we must supply the names otherwise -- and ** SMTP is the answer!! */ if (*mvp == NULL) { /* running SMTP */ # ifdef SMTP clever = TRUE; *pvp = NULL; # else SMTP /* oops! we don't implement SMTP */ syserr("SMTP style mailer"); return (EX_SOFTWARE); # endif SMTP } /* ** At this point *mvp points to the argument with $u. We ** run through our address list and append all the addresses ** we can. If we run out of space, do not fret! We can ** always send another copy later. */ tobuf[0] = '\0'; e->e_to = tobuf; ctladdr = NULL; for (; to != NULL; to = to->q_next) { /* avoid sending multiple recipients to dumb mailers */ if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) break; /* if already sent or not for this host, don't send */ if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) continue; /* avoid overflowing tobuf */ if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) break; if (tTd(10, 1)) { printf("\nsend to "); printaddr(to, FALSE); } /* compute effective uid/gid when sending */ if (to->q_mailer == ProgMailer) ctladdr = getctladdr(to); user = to->q_user; e->e_to = to->q_paddr; to->q_flags |= QDONTSEND; /* ** Check to see that these people are allowed to ** talk to each other. */ if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) { NoReturn = TRUE; usrerr("Message is too large; %ld bytes max", m->m_maxsize); giveresponse(EX_UNAVAILABLE, m, e); continue; } if (!checkcompat(to)) { giveresponse(EX_UNAVAILABLE, m, e); continue; } /* ** Strip quote bits from names if the mailer is dumb ** about them. */ if (bitnset(M_STRIPQ, m->m_flags)) { stripquotes(user, TRUE); stripquotes(host, TRUE); } else { stripquotes(user, FALSE); stripquotes(host, FALSE); } /* hack attack -- delivermail compatibility */ if (m == ProgMailer && *user == '|') user++; /* ** If an error message has already been given, don't ** bother to send to this address. ** ** >>>>>>>>>> This clause assumes that the local mailer ** >> NOTE >> cannot do any further aliasing; that ** >>>>>>>>>> function is subsumed by sendmail. */ if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) continue; /* save statistics.... */ markstats(e, to); /* ** See if this user name is "special". ** If the user name has a slash in it, assume that this ** is a file -- send it off without further ado. Note ** that this type of addresses is not processed along ** with the others, so we fudge on the To person. */ if (m == LocalMailer) { if (user[0] == '/') { rcode = mailfile(user, getctladdr(to)); giveresponse(rcode, m, e); continue; } } /* ** Address is verified -- add this user to mailer ** argv, and add it to the print list of recipients. */ /* link together the chain of recipients */ to->q_tchain = tochain; tochain = to; /* create list of users for error messages */ (void) strcat(tobuf, ","); (void) strcat(tobuf, to->q_paddr); define('u', user, e); /* to user */ define('z', to->q_home, e); /* user's home */ /* ** Expand out this user into argument list. */ if (!clever) { expand(*mvp, buf, &buf[sizeof buf - 1], e); *pvp++ = newstr(buf); if (pvp >= &pv[MAXPV - 2]) { /* allow some space for trailing parms */ break; } } } /* see if any addresses still exist */ if (tobuf[0] == '\0') { define('g', (char *) NULL, e); return (0); } /* print out messages as full list */ e->e_to = tobuf + 1; /* ** Fill out any parameters after the $u parameter. */ while (!clever && *++mvp != NULL) { expand(*mvp, buf, &buf[sizeof buf - 1], e); *pvp++ = newstr(buf); if (pvp >= &pv[MAXPV]) syserr("deliver: pv overflow after $u for %s", pv[0]); } *pvp++ = NULL; /* ** Call the mailer. ** The argument vector gets built, pipes ** are created as necessary, and we fork & exec as ** appropriate. ** If we are running SMTP, we just need to clean up. */ if (ctladdr == NULL) ctladdr = &e->e_from; #ifdef NAMED_BIND _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ #endif #ifdef SMTP if (clever) { rcode = EX_OK; #ifdef NAMED_BIND if (host[0] && host[0] != '[') { expand("\001w", buf, &buf[sizeof(buf) - 1], e); Nmx = getmxrr(host, MxHosts, buf, &rcode); } else #endif { Nmx = 1; MxHosts[0] = host; } if (Nmx >= 0) { message(Arpa_Info, "Connecting to %s (%s)...", MxHosts[0], m->m_name); if ((rcode = smtpinit(m, pv)) == EX_OK) { register char *t = tobuf; register int i; /* send the recipient list */ tobuf[0] = '\0'; for (to = tochain; to; to = to->q_tchain) { e->e_to = to->q_paddr; if ((i = smtprcpt(to, m)) != EX_OK) { markfailure(e, to, i); giveresponse(i, m, e); } else { *t++ = ','; for (p = to->q_paddr; *p; *t++ = *p++); } } /* now send the data */ if (tobuf[0] == '\0') e->e_to = NULL; else { e->e_to = tobuf + 1; rcode = smtpdata(m, e); } /* now close the connection */ smtpquit(m); } } } else #endif /* SMTP */ { message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name); rcode = sendoff(e, m, pv, ctladdr); } #ifdef NAMED_BIND _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ #endif /* ** Do final status disposal. ** We check for something in tobuf for the SMTP case. ** If we got a temporary failure, arrange to queue the ** addressees. */ if (tobuf[0] != '\0') giveresponse(rcode, m, e); if (rcode != EX_OK) for (to = tochain; to != NULL; to = to->q_tchain) markfailure(e, to, rcode); errno = 0; define('g', (char *) NULL, e); return (rcode); } \f /* ** MARKFAILURE -- mark a failure on a specific address. ** ** Parameters: ** e -- the envelope we are sending. ** q -- the address to mark. ** rcode -- the code signifying the particular failure. ** ** Returns: ** none. ** ** Side Effects: ** marks the address (and possibly the envelope) with the ** failure so that an error will be returned or ** the message will be queued, as appropriate. */ markfailure(e, q, rcode) register ENVELOPE *e; register ADDRESS *q; int rcode; { if (rcode == EX_OK) return; else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) q->q_flags |= QBADADDR; else if (curtime() > e->e_ctime + TimeOut) { extern char *pintvl(); char buf[MAXLINE]; if (!bitset(EF_TIMEOUT, e->e_flags)) { (void) sprintf(buf, "Cannot send message for %s", pintvl(TimeOut, FALSE)); if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(buf); message(Arpa_Info, buf); } q->q_flags |= QBADADDR; e->e_flags |= EF_TIMEOUT; } else q->q_flags |= QQUEUEUP; } \f /* ** DOFORK -- do a fork, retrying a couple of times on failure. ** ** This MUST be a macro, since after a vfork we are running ** two processes on the same stack!!! ** ** Parameters: ** none. ** ** Returns: ** From a macro??? You've got to be kidding! ** ** Side Effects: ** Modifies the ==> LOCAL <== variable 'pid', leaving: ** pid of child in parent, zero in child. ** -1 on unrecoverable error. ** ** Notes: ** I'm awfully sorry this looks so awful. That's ** vfork for you..... */ # define NFORKTRIES 5 # ifdef VMUNIX # define XFORK vfork # else VMUNIX # define XFORK fork # endif VMUNIX # define DOFORK(fORKfN) \ {\ register int i;\ \ for (i = NFORKTRIES; --i >= 0; )\ {\ pid = fORKfN();\ if (pid >= 0)\ break;\ if (i > 0)\ sleep((unsigned) NFORKTRIES - i);\ }\ } \f /* ** DOFORK -- simple fork interface to DOFORK. ** ** Parameters: ** none. ** ** Returns: ** pid of child in parent. ** zero in child. ** -1 on error. ** ** Side Effects: ** returns twice, once in parent and once in child. */ dofork() { register int pid; DOFORK(fork); return (pid); } \f /* ** SENDOFF -- send off call to mailer & collect response. ** ** Parameters: ** e -- the envelope to mail. ** m -- mailer descriptor. ** pvp -- parameter vector to send to it. ** ctladdr -- an address pointer controlling the ** user/groupid etc. of the mailer. ** ** Returns: ** exit status of mailer. ** ** Side Effects: ** none. */ static sendoff(e, m, pvp, ctladdr) register ENVELOPE *e; MAILER *m; char **pvp; ADDRESS *ctladdr; { auto FILE *mfile; auto FILE *rfile; register int i; int pid; /* ** Create connection to mailer. */ pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); if (pid < 0) return (-1); /* ** Format and send message. */ putfromline(mfile, m); (*e->e_puthdr)(mfile, m, e); putline("\n", mfile, m); (*e->e_putbody)(mfile, m, e); (void) fclose(mfile); if (rfile != NULL) (void) fclose(rfile); i = endmailer(pid, pvp[0]); /* arrange a return receipt if requested */ if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) { e->e_flags |= EF_SENDRECEIPT; /* do we want to send back more info? */ } return (i); } \f /* ** ENDMAILER -- Wait for mailer to terminate. ** ** We should never get fatal errors (e.g., segmentation ** violation), so we report those specially. For other ** errors, we choose a status message (into statmsg), ** and if it represents an error, we print it. ** ** Parameters: ** pid -- pid of mailer. ** name -- name of mailer (for error messages). ** ** Returns: ** exit code of mailer. ** ** Side Effects: ** none. */ endmailer(pid, name) int pid; char *name; { int st; /* in the IPC case there is nothing to wait for */ if (pid == 0) return (EX_OK); /* wait for the mailer process to die and collect status */ st = waitfor(pid); if (st == -1) { syserr("endmailer %s: wait", name); return (EX_SOFTWARE); } /* see if it died a horrid death */ if ((st & 0377) != 0) { syserr("mailer %s died with signal %o", name, st); ExitStat = EX_TEMPFAIL; return (EX_TEMPFAIL); } /* normal death -- return status */ st = (st >> 8) & 0377; return (st); } \f /* ** OPENMAILER -- open connection to mailer. ** ** Parameters: ** m -- mailer descriptor. ** pvp -- parameter vector to pass to mailer. ** ctladdr -- controlling address for user. ** clever -- create a full duplex connection. ** pmfile -- pointer to mfile (to mailer) connection. ** prfile -- pointer to rfile (from mailer) connection. ** ** Returns: ** pid of mailer ( > 0 ). ** -1 on error. ** zero on an IPC connection. ** ** Side Effects: ** creates a mailer in a subprocess. */ openmailer(m, pvp, ctladdr, clever, pmfile, prfile) MAILER *m; char **pvp; ADDRESS *ctladdr; bool clever; FILE **pmfile; FILE **prfile; { int pid; int mpvect[2]; int rpvect[2]; FILE *mfile = NULL; FILE *rfile = NULL; extern FILE *fdopen(); if (tTd(11, 1)) { printf("openmailer:"); printav(pvp); } errno = 0; CurHostName = m->m_mailer; /* ** Deal with the special case of mail handled through an IPC ** connection. ** In this case we don't actually fork. We must be ** running SMTP for this to work. We will return a ** zero pid to indicate that we are running IPC. ** We also handle a debug version that just talks to stdin/out. */ /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { *pmfile = stdout; *prfile = stdin; return (0); } if (strcmp(m->m_mailer, "[IPC]") == 0) { #ifdef HOSTINFO register STAB *st; extern STAB *stab(); #endif HOSTINFO #ifdef DAEMON register int i, j; register u_short port; CurHostName = pvp[1]; if (!clever) syserr("non-clever IPC"); if (pvp[2] != NULL) port = atoi(pvp[2]); else port = 0; for (j = 0; j < Nmx; j++) { CurHostName = MxHosts[j]; #ifdef HOSTINFO /* see if we have already determined that this host is fried */ st = stab(MxHosts[j], ST_HOST, ST_FIND); if (st == NULL || st->s_host.ho_exitstat == EX_OK) { if (j > 1) message(Arpa_Info, "Connecting to %s (%s)...", MxHosts[j], m->m_name); i = makeconnection(MxHosts[j], port, pmfile, prfile); } else { i = st->s_host.ho_exitstat; errno = st->s_host.ho_errno; } #else HOSTINFO i = makeconnection(MxHosts[j], port, pmfile, prfile); #endif HOSTINFO if (i != EX_OK) { #ifdef HOSTINFO /* enter status of this host */ if (st == NULL) st = stab(MxHosts[j], ST_HOST, ST_ENTER); st->s_host.ho_exitstat = i; st->s_host.ho_errno = errno; #endif HOSTINFO ExitStat = i; continue; } else return (0); } return (-1); #else DAEMON syserr("openmailer: no IPC"); return (-1); #endif DAEMON } /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { syserr("openmailer: pipe (to mailer)"); return (-1); } #ifdef SMTP /* if this mailer speaks smtp, create a return pipe */ if (clever && pipe(rpvect) < 0) { syserr("openmailer: pipe (from mailer)"); (void) close(mpvect[0]); (void) close(mpvect[1]); return (-1); } #endif SMTP /* ** Actually fork the mailer process. ** DOFORK is clever about retrying. ** ** Dispose of SIGCHLD signal catchers that may be laying ** around so that endmail will get it. */ if (CurEnv->e_xfp != NULL) (void) fflush(CurEnv->e_xfp); /* for debugging */ (void) fflush(stdout); # ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL); # endif SIGCHLD DOFORK(XFORK); /* pid is set by DOFORK */ if (pid < 0) { /* failure */ syserr("openmailer: cannot fork"); (void) close(mpvect[0]); (void) close(mpvect[1]); #ifdef SMTP if (clever) { (void) close(rpvect[0]); (void) close(rpvect[1]); } #endif SMTP return (-1); } else if (pid == 0) { int i; extern int DtableSize; /* child -- set up input & exec mailer */ /* make diagnostic output be standard output */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGTERM, SIG_DFL); /* arrange to filter standard & diag output of command */ if (clever) { (void) close(rpvect[0]); (void) close(1); (void) dup(rpvect[1]); (void) close(rpvect[1]); } else if (OpMode == MD_SMTP || HoldErrs) { /* put mailer output in transcript */ (void) close(1); (void) dup(fileno(CurEnv->e_xfp)); } (void) close(2); (void) dup(1); /* arrange to get standard input */ (void) close(mpvect[1]); (void) close(0); if (dup(mpvect[0]) < 0) { syserr("Cannot dup to zero!"); _exit(EX_OSERR); } (void) close(mpvect[0]); if (!bitnset(M_RESTR, m->m_flags)) { if (ctladdr == NULL || ctladdr->q_uid == 0) { (void) setgid(DefGid); (void) initgroups(DefUser, DefGid); (void) setuid(DefUid); } else { (void) setgid(ctladdr->q_gid); (void) initgroups(ctladdr->q_ruser? ctladdr->q_ruser: ctladdr->q_user, ctladdr->q_gid); (void) setuid(ctladdr->q_uid); } } /* arrange for all the files to be closed */ for (i = 3; i < DtableSize; i++) { register int j; if ((j = fcntl(i, F_GETFD, 0)) != -1) (void)fcntl(i, F_SETFD, j|1); } /* try to execute the mailer */ execve(m->m_mailer, pvp, UserEnviron); syserr("Cannot exec %s", m->m_mailer); if (m == LocalMailer || errno == EIO || errno == EAGAIN || errno == ENOMEM || errno == EPROCLIM) _exit(EX_TEMPFAIL); else _exit(EX_UNAVAILABLE); } /* ** Set up return value. */ (void) close(mpvect[0]); mfile = fdopen(mpvect[1], "w"); if (clever) { (void) close(rpvect[1]); rfile = fdopen(rpvect[0], "r"); } else rfile = NULL; *pmfile = mfile; *prfile = rfile; return (pid); } \f /* ** GIVERESPONSE -- Interpret an error response from a mailer ** ** Parameters: ** stat -- the status code from the mailer (high byte ** only; core dumps must have been taken care of ** already). ** m -- the mailer descriptor for this mailer. ** ** Returns: ** none. ** ** Side Effects: ** Errors may be incremented. ** ExitStat may be set. */ giveresponse(stat, m, e) int stat; register MAILER *m; ENVELOPE *e; { register char *statmsg; extern char *SysExMsg[]; register int i; extern int N_SysEx; #ifdef NAMED_BIND extern int h_errno; #endif char buf[MAXLINE]; #ifdef lint if (m == NULL) return; #endif lint /* ** Compute status message from code. */ i = stat - EX__BASE; if (stat == 0) statmsg = "250 Sent"; else if (i < 0 || i > N_SysEx) { (void) sprintf(buf, "554 unknown mailer error %d", stat); stat = EX_UNAVAILABLE; statmsg = buf; } else if (stat == EX_TEMPFAIL) { (void) strcpy(buf, SysExMsg[i]); #ifdef NAMED_BIND if (h_errno == TRY_AGAIN) { extern char *errstring(); statmsg = errstring(h_errno+MAX_ERRNO); } else #endif { if (errno != 0) { extern char *errstring(); statmsg = errstring(errno); } else { #ifdef SMTP extern char SmtpError[]; statmsg = SmtpError; #else SMTP statmsg = NULL; #endif SMTP } } if (statmsg != NULL && statmsg[0] != '\0') { (void) strcat(buf, ": "); (void) strcat(buf, statmsg); } statmsg = buf; } else { statmsg = SysExMsg[i]; } /* ** Print the message as appropriate */ if (stat == EX_OK || stat == EX_TEMPFAIL) message(Arpa_Info, &statmsg[4]); else { Errors++; usrerr(statmsg); } /* ** Final cleanup. ** Log a record of the transaction. Compute the new ** ExitStat -- if we already had an error, stick with ** that. */ if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) logdelivery(&statmsg[4]); if (stat != EX_TEMPFAIL) setstat(stat); if (stat != EX_OK) { if (e->e_message != NULL) free(e->e_message); e->e_message = newstr(&statmsg[4]); } errno = 0; #ifdef NAMED_BIND h_errno = 0; #endif } \f /* ** LOGDELIVERY -- log the delivery in the system log ** ** Parameters: ** stat -- the message to print for the status ** ** Returns: ** none ** ** Side Effects: ** none */ logdelivery(stat) char *stat; { extern char *pintvl(); # ifdef LOG syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); # endif LOG } \f /* ** PUTFROMLINE -- output a UNIX-style from line (or whatever) ** ** This can be made an arbitrary message separator by changing $l ** ** One of the ugliest hacks seen by human eyes is contained herein: ** UUCP wants those stupid "remote from <host>" lines. Why oh why ** does a well-meaning programmer such as myself have to deal with ** this kind of antique garbage???? ** ** Parameters: ** fp -- the file to output to. ** m -- the mailer describing this entry. ** ** Returns: ** none ** ** Side Effects: ** outputs some text to fp. */ putfromline(fp, m) register FILE *fp; register MAILER *m; { char *template = "\001l\n"; char buf[MAXLINE]; if (bitnset(M_NHDR, m->m_flags)) return; # ifdef UGLYUUCP if (bitnset(M_UGLYUUCP, m->m_flags)) { char *bang; char xbuf[MAXLINE]; expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); bang = index(buf, '!'); if (bang == NULL) syserr("No ! in UUCP! (%s)", buf); else { *bang++ = '\0'; (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); template = xbuf; } } # endif UGLYUUCP expand(template, buf, &buf[sizeof buf - 1], CurEnv); putline(buf, fp, m); } \f /* ** PUTBODY -- put the body of a message. ** ** Parameters: ** fp -- file to output onto. ** m -- a mailer descriptor to control output format. ** e -- the envelope to put out. ** ** Returns: ** none. ** ** Side Effects: ** The message is written onto fp. */ putbody(fp, m, e) FILE *fp; MAILER *m; register ENVELOPE *e; { char buf[MAXLINE]; /* ** Output the body of the message */ if (e->e_dfp == NULL) { if (e->e_df != NULL) { e->e_dfp = fopen(e->e_df, "r"); if (e->e_dfp == NULL) syserr("putbody: Cannot open %s for %s from %s", e->e_df, e->e_to, e->e_from); } else putline("<<< No Message Collected >>>", fp, m); } if (e->e_dfp != NULL) { rewind(e->e_dfp); while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) { if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && strncmp(buf, "From ", 5) == 0) (void) putc('>', fp); putline(buf, fp, m); } if (ferror(e->e_dfp)) { syserr("putbody: read error"); ExitStat = EX_IOERR; } } (void) fflush(fp); if (ferror(fp) && errno != EPIPE) { syserr("putbody: write error"); ExitStat = EX_IOERR; } errno = 0; } \f /* ** MAILFILE -- Send a message to a file. ** ** If the file has the setuid/setgid bits set, but NO execute ** bits, sendmail will try to become the owner of that file ** rather than the real user. Obviously, this only works if ** sendmail runs as root. ** ** This could be done as a subordinate mailer, except that it ** is used implicitly to save messages in ~/dead.letter. We ** view this as being sufficiently important as to include it ** here. For example, if the system is dying, we shouldn't have ** to create another process plus some pipes to save the message. ** ** Parameters: ** filename -- the name of the file to send to. ** ctladdr -- the controlling address header -- includes ** the userid/groupid to be when sending. ** ** Returns: ** The exit code associated with the operation. ** ** Side Effects: ** none. */ mailfile(filename, ctladdr) char *filename; ADDRESS *ctladdr; { register FILE *f; register int pid; ENVELOPE *e = CurEnv; /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of ** the complications of calling subroutines, etc. */ DOFORK(fork); if (pid < 0) return (EX_OSERR); else if (pid == 0) { /* child -- actually write to file */ struct stat stb; (void) signal(SIGINT, SIG_DFL); (void) signal(SIGHUP, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); (void) umask(OldUmask); if (stat(filename, &stb) < 0) { errno = 0; stb.st_mode = 0666; } if (bitset(0111, stb.st_mode)) exit(EX_CANTCREAT); if (ctladdr == NULL) ctladdr = &e->e_from; /* we have to open the dfile BEFORE setuid */ if (e->e_dfp == NULL && e->e_df != NULL) { e->e_dfp = fopen(e->e_df, "r"); if (e->e_dfp == NULL) { syserr("mailfile: Cannot open %s for %s from %s", e->e_df, e->e_to, e->e_from); } } if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) { if (ctladdr->q_uid == 0) { (void) setgid(DefGid); (void) initgroups(DefUser, DefGid); } else { (void) setgid(ctladdr->q_gid); (void) initgroups(ctladdr->q_ruser? ctladdr->q_ruser: ctladdr->q_user, ctladdr->q_gid); } } if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) { if (ctladdr->q_uid == 0) (void) setuid(DefUid); else (void) setuid(ctladdr->q_uid); } f = dfopen(filename, "a"); if (f == NULL) exit(EX_CANTCREAT); putfromline(f, ProgMailer); (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); putline("\n", f, ProgMailer); (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); putline("\n", f, ProgMailer); (void) fclose(f); (void) fflush(stdout); /* reset ISUID & ISGID bits for paranoid systems */ (void) chmod(filename, (int) stb.st_mode); exit(EX_OK); /*NOTREACHED*/ } else { /* parent -- wait for exit status */ int st; st = waitfor(pid); if ((st & 0377) != 0) return (EX_UNAVAILABLE); else return ((st >> 8) & 0377); /*NOTREACHED*/ } } \f /* ** SENDALL -- actually send all the messages. ** ** Parameters: ** e -- the envelope to send. ** mode -- the delivery mode to use. If SM_DEFAULT, use ** the current SendMode. ** ** Returns: ** none. ** ** Side Effects: ** Scans the send lists and sends everything it finds. ** Delivers any appropriate error messages. ** If we are running in a non-interactive mode, takes the ** appropriate action. */ sendall(e, mode) ENVELOPE *e; char mode; { register ADDRESS *q; bool oldverbose; int pid; FILE *lockfp = NULL, *queueup(); /* determine actual delivery mode */ if (mode == SM_DEFAULT) { extern bool shouldqueue(); if (shouldqueue(e->e_msgpriority)) mode = SM_QUEUE; else mode = SendMode; } if (tTd(13, 1)) { printf("\nSENDALL: mode %c, sendqueue:\n", mode); printaddr(e->e_sendqueue, TRUE); } /* ** Do any preprocessing necessary for the mode we are running. ** Check to make sure the hop count is reasonable. ** Delete sends to the sender in mailing lists. */ CurEnv = e; if (e->e_hopcount > MAXHOP) { errno = 0; syserr("sendall: too many hops %d (%d max): from %s, to %s", e->e_hopcount, MAXHOP, e->e_from, e->e_to); return; } if (!MeToo) { extern ADDRESS *recipient(); e->e_from.q_flags |= QDONTSEND; (void) recipient(&e->e_from, &e->e_sendqueue); } # ifdef QUEUE if ((mode == SM_QUEUE || mode == SM_FORK || (mode != SM_VERIFY && SuperSafe)) && !bitset(EF_INQUEUE, e->e_flags)) lockfp = queueup(e, TRUE, mode == SM_QUEUE); #endif QUEUE oldverbose = Verbose; switch (mode) { case SM_VERIFY: Verbose = TRUE; break; case SM_QUEUE: e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; return; case SM_FORK: if (e->e_xfp != NULL) (void) fflush(e->e_xfp); pid = fork(); if (pid < 0) { mode = SM_DELIVER; break; } else if (pid > 0) { /* be sure we leave the temp files to our child */ e->e_id = e->e_df = NULL; if (lockfp != NULL) (void) fclose(lockfp); return; } /* double fork to avoid zombies */ if (fork() > 0) exit(EX_OK); /* be sure we are immune from the terminal */ disconnect(FALSE); break; } /* ** Run through the list and send everything. */ for (q = e->e_sendqueue; q != NULL; q = q->q_next) { if (mode == SM_VERIFY) { e->e_to = q->q_paddr; if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) message(Arpa_Info, "deliverable"); } else (void) deliver(e, q); } Verbose = oldverbose; /* ** Now run through and check for errors. */ if (mode == SM_VERIFY) { if (lockfp != NULL) (void) fclose(lockfp); return; } for (q = e->e_sendqueue; q != NULL; q = q->q_next) { register ADDRESS *qq; if (tTd(13, 3)) { printf("Checking "); printaddr(q, FALSE); } /* only send errors if the message failed */ if (!bitset(QBADADDR, q->q_flags)) continue; /* we have an address that failed -- find the parent */ for (qq = q; qq != NULL; qq = qq->q_alias) { char obuf[MAXNAME + 6]; extern char *aliaslookup(); /* we can only have owners for local addresses */ if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) continue; /* see if the owner list exists */ (void) strcpy(obuf, "owner-"); if (strncmp(qq->q_user, "owner-", 6) == 0) (void) strcat(obuf, "owner"); else (void) strcat(obuf, qq->q_user); makelower(obuf); if (aliaslookup(obuf) == NULL) continue; if (tTd(13, 4)) printf("Errors to %s\n", obuf); /* owner list exists -- add it to the error queue */ sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); ErrorMode = EM_MAIL; break; } /* if we did not find an owner, send to the sender */ if (qq == NULL && bitset(QBADADDR, q->q_flags)) sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); } /* this removes the lock on the file */ if (lockfp != NULL) (void) fclose(lockfp); if (mode == SM_FORK) finis(); } @ 5.38.0.1 log @IDA patches @ text @d34 1 a34 1 #endif /* NAMED_BIND */ a36 53 ** Status error messages */ #define MAXENDERR (sizeof(Enderr) / sizeof(*Enderr)) char *Enderr[] = { "IMPOSSIBLE", /* SIGHUP */ "hangup", /* SIGINT */ "interrupt", /* SIGQUIT */ "quit", /* SIGILL */ "illegal instruction", /* SIGTRAP */ "trace trap", /* SIGIOT */ "IOT instruction", /* SIGEMT */ "EMT instruction", /* SIGFPE */ "floating point exception", /* SIGKILL */ "kill", /* SIGBUS */ "bus error", /* SIGSEGV */ "segmentation violation", /* SIGSYS */ "bad argument to system call", /* SIGPIPE */ "write on a pipe with no one to read it", /* SIGALRM */ "alarm clock", /* SIGTERM */ "software termination signal", /* SIGURG */ "urgent condition present on socket", /* SIGSTOP */ "stop", /* SIGTSTP */ "stop signal generated from keyboard", /* SIGCONT */ "continue after stop", /* SIGCHLD */ "child status has changed", /* SIGTTIN */ "background read attempted from control terminal", /* SIGTTOU */ "background write attempted to control terminal", /* SIGIO */ "I/O is possible on a descriptor", /* SIGXCPU */ "cpu time limit exceeded", /* SIGXFSZ */ "file size limit exceeded", /* SIGVTALRM */ "virtual time alarm", /* SIGPROF */ "profiling timer alarm", /* SIGWINCH */ "window changed", /* SIGLOST */ "resource lost", /* SIGUSR1 */ "user-defined signal 1", /* SIGUSR2 */ "user-defined signal 2" }; #ifdef NAMED_BIND /* ** Name server error messages */ #define MAXH_ERR (sizeof(H_Errmsg) / sizeof(*H_Errmsg)) char *H_Errmsg[] = { /* XXX */ "[Unknown error]", /* HOST_NOT_FOUND */ "Authoritative answer from name server", /* TRY_AGAIN */ "Non-authoritiatve answer or name server failure", /* NO_RECOVERY */ "Non recoverable name server error", /* NO_DATA */ "Valid name but no data [address]" }; #endif /* NAMED_BIND */ /* d91 1 a91 1 #endif /* NAMED_BIND */ d140 1 a140 1 (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE, FALSE)); d196 1 a196 1 # else /* !SMTP */ d200 1 a200 1 # endif /* SMTP */ d379 2 a380 2 /* _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ #endif /* NAMED_BIND */ d392 1 a392 1 #endif /* NAMED_BIND */ d413 1 a413 2 else { d422 1 a422 2 else { d439 2 a440 2 /* _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ #endif /* NAMED_BIND */ d530 1 a530 1 # else /* !VMUNIX */ d532 1 a532 1 # endif /* VMUNIX */ d668 1 a668 3 syserr("%s died because of %s (%d)--requeueing message", name, ((st >= 0) && (st < MAXENDERR)) ? Enderr[st] : "unknown error code", st); d743 1 a743 1 #endif /* HOSTINFO */ d773 1 a773 1 #else /* !HOSTINFO */ d775 1 a775 1 #endif /* HOSTINFO */ a777 16 /* * Consider the case of multiple MX entries * for a given host where the last entry refers * to non-existent host. On occasions when * none of the hosts are reachable, the mail * will bounce if the last ExitStat is * EX_NOHOST. Handle this by resetting i to * EX_TEMPFAIL if it's not the primary MX entry * and it's the last MX entry. -pbp */ #ifdef LOG if (i == EX_NOHOST) syslog(LOG_WARNING, "Found non-existent host %s in MX records for %s", CurHostName, pvp[1]); #endif /* LOG */ if (j != 0 && j == (Nmx - 1)) i = EX_TEMPFAIL; d784 1 a784 1 #endif /* HOSTINFO */ d792 1 a792 1 #else /* !DAEMON */ d795 1 a795 1 #endif /* DAEMON */ d814 1 a814 1 #endif /* SMTP */ d829 1 a829 1 # endif /* SIGCHLD */ d844 1 a844 1 #endif /* SMTP */ d965 1 a965 1 #endif /* NAMED_BIND */ d971 1 a971 1 #endif /* lint */ d997 1 a997 1 #endif /* NAMED_BIND */ d1011 1 a1011 1 #else /* !SMTP */ d1013 1 a1013 1 #endif /* SMTP */ a1035 2 extern char Arpa_Usrerr[]; d1037 1 a1037 7 #ifdef NAMED_BIND if (stat == EX_NOHOST && h_errno != 0) usrerr("%s (%s)", statmsg, H_Errmsg[h_errno > MAXH_ERR ? 0 : h_errno]); else #endif /* NAMED_BIND */ usrerr(statmsg); d1061 1 a1061 1 #endif /* NAMED_BIND */ d1084 1 a1084 1 # endif /* LOG */ d1111 1 a1111 4 extern char *macvalue(); char *oldg = macvalue('g', CurEnv); char template[MAXLINE]; char newg[MAXLINE]; a1113 2 strcpy(template, "\001l\n"); a1116 12 /* construct path through us if needed */ if (bitnset(M_FROMPATH, m->m_flags)) { char myname[MAXLINE]; expand("\001k", myname, &myname[sizeof myname - 1], CurEnv); if (index(oldg, '!') == NULL || strncmp(oldg, myname, strlen(myname)) != 0) { sprintf(newg, "%s!%s", myname, oldg); define('g', newg, CurEnv); } } d1121 1 d1126 1 a1126 2 syserr("No `!' in UUCP envelope \"from\" address! (%s)", buf); d1130 2 a1131 2 (void) sprintf(template, "From %s \001d remote from %s\n", bang, buf); d1134 1 a1134 1 # endif /* UGLYUUCP */ a1136 4 /* redefine old from address */ if (bitnset(M_FROMPATH, m->m_flags)) define('g', oldg, CurEnv); d1396 1 a1396 1 #endif /* QUEUE */ @ 5.38.0.2 log @Date: Wed, 20 Jun 90 15:39:37 -0400 (EDT) From: Craig_Everhart@@transarc.com To: paul@@uxc.cso.uiuc.edu (Paul Pomes - UofIllinois CSO) Subject: Re: Sendmail V5.64 + IDA enhancements available for anon-FTP Here's a sendmail patch for you that I've been sending around. I've been running it for years, and it was only when Peter Neumann had such trouble with RISKS duplications that I decided to try to propagate it. The problem addressed by the fix is that if sendmail delivers to a long address list (in a single request) but crashes in the middle, it has no record of the successful deliveries that it has made so far, so when it eventually gets around to retrying that request, it re-delivers to all the addresses to which it had been able to deliver earlier. Not only does this generate duplicate mail, but the re-delivery process also requires additional queue processing time, so that it might continue to take a long time even to attempt delivery to the last address in the list. The solution that this patch builds is simple and not very expensive: after every successful mail delivery, the qf* file is rewritten, omitting the recipient to whom delivery was successful. The qf* file gets shorter even as the request is processed. A crash in the middle of processing the list will result in duplicate delivery to at most one host. It doesn't require that much time to rewrite the qf* file; certainly less time than the delivery itself takes. The only real disadvantage I can imagine is that my sendmail sources have diverged in many ways from a UCB version of about 1986. Nonetheless, it shouldn't be difficult to install this change. As you can see, this change works by adding an additional flag parameter to queueup(), then calling queueup() (from sendall()) with this parameter set sometimes. The queueup() flag parameter controls which addresses are rewritten, looking at different flags. So here's the patch. I hope that you find it useful. I look forward to your reply. Thanks, Craig Everhart @ text @d1448 1 a1448 1 bool oldverbose, DoingMore; d1497 1 a1497 1 lockfp = queueup(e, TRUE, mode == SM_QUEUE, FALSE); a1542 1 DoingMore = FALSE; d1551 2 a1552 10 else if (!bitset(QDONTSEND, q->q_flags)) { int estat; if (DoingMore) lockfp = queueup(e, TRUE, FALSE, TRUE); DoingMore = FALSE; estat = deliver(e, q); /* Queueup if any delivered */ if (estat == EX_OK) DoingMore = TRUE; } @ 5.38.0.3 log @Patches for HP-UX from Andy Linton <root@@comp.vuw.ac.nz>. Thanks Andy! @ text @d985 2 a986 6 if (m == LocalMailer || errno == EIO || errno == EAGAIN || #if !defined(hpux) errno == EPROCLIM || #endif /* hpux */ errno == ENOMEM) @ 5.38.0.4 log @Un-do queue file re-writing. @ text @d1452 1 a1452 1 bool oldverbose; d1501 1 a1501 1 lockfp = queueup(e, TRUE, mode == SM_QUEUE); d1547 1 d1556 10 a1565 2 else (void) deliver(e, q); @ 5.38.0.5 log @Change comparison for a local MX record to use $j instead of $w. Suggested by Neil Rickert, NIU. @ text @d441 1 a441 2 /* Compare MX records against $j and not $w */ expand("\001j", buf, &buf[sizeof(buf) - 1], e); @ 5.38.0.6 log @First revisions to support HEAD and MULT extensions to SMTP for DEC's mail11v3 program. @ text @d432 1 a432 1 _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ d455 1 a455 6 #ifdef MAIL11V3 if ((rcode = smtpinit(m, pv, e)) == EX_OK) #else /* ! MAIL11V3 */ if ((rcode = smtpinit(m, pv)) == EX_OK) #endif /* MAIL11V3 */ { d461 1 a461 2 for (to = tochain; to; to = to->q_tchain) { d463 1 a463 2 if ((i = smtprcpt(to, m)) != EX_OK) { a480 27 #ifdef MAIL11V3 SmtpPhase = "result wait"; setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase); if (rcode == EX_OK) { if (!SmtpManyStatus) rcode = smtpstat(m); else for (tobuf[0] = '\0', to = tochain; to != NULL; to = to->q_tchain) { int j; e->e_to = to->q_paddr; j = smtpstat(m); if (j != EX_OK) { markfailure(e, to, j); giveresponse(j, m, e); } else { (void) strcat(tobuf, ","); (void) strcat(tobuf, to->q_paddr); } } } #endif /* MAIL11V3 */ d495 1 a495 1 _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ @ 5.38.0.7 log @Suppress call to getmxrr() for the case of a non-IPC mailer as well as for domain literals. @ text @d439 1 a439 5 /* ** Don't do MX lookups on domain literals or for non-IPC ** mailers. */ if (host[0] && host[0] != '[' && *m->m_mailer != '/') @ 5.38.0.8 log @Deleted newlines from putline calls (Bruce Lilly), added Convex share scheduler support (Jon Roma). @ text @d25 1 a26 1 #include "sendmail.h" d32 2 a33 2 # include <arpa/nameser.h> # include <resolv.h> a34 3 #if defined(__convex__) && defined(SHARE) # include <shares.h> #endif /* __convex__ && SHARE */ a132 1 static sendoff(); d658 1 a658 1 register int pid = 0; d705 1 a705 1 putline("", mfile, m); d801 1 a801 1 int pid = 0; a999 4 #if defined(__convex__) && defined(SHARE) if (setupshares(DefShareUid, syserr)) syserr("Can't install shares!\n"); #endif /* __convex__ && SHARE */ a1005 4 #if defined(__convex__) && defined(SHARE) if (setupshares(DefShareUid, syserr)) syserr("Can't install shares!\n"); #endif /* __convex__ && SHARE */ d1025 3 a1027 3 #if defined(EPROCLIM) errno == EPROCLIM || # endif /* EPROCLIM */ d1378 1 a1378 1 register int pid = 0; d1444 1 a1444 1 putline("", f, ProgMailer); d1446 1 a1446 1 putline("", f, ProgMailer); @ 5.38.0.9 log @Don't pass constant strings to putline(). @ text @d1253 1 a1253 1 (void) strcpy(template, "\001l\n"); d1331 1 a1331 4 { (void) strcpy(buf, "<<< No Message Collected >>>"); putline(buf, fp, m); } @ 5.38.0.10 log @Fixed lockf()/fcntl() emulation of flock() across fork() calls. In the case of emulated flock(), the lock is released prior to the fork() and re-locked afterwards. If the re-lock fails, which should be rare, do nothing and return. Andy Linton (andy.linton@@comp.vuw.ac.nz), provided the X-Open Portability Guide #3 changes (#ifdef XPG3) plus a fix to limit the size of syslog() arguments. @ text @d82 1 a82 1 # define MAXH_ERR (sizeof(H_Errmsg) / sizeof(*H_Errmsg)) d250 1 a250 1 #ifdef SMTP d253 1 a253 1 #else /* !SMTP */ d257 1 a257 1 #endif /* SMTP */ d442 1 a442 1 # ifdef NAMED_BIND d454 1 a454 1 # endif /* NAMED_BIND */ d463 1 a463 1 # ifdef MAIL11V3 d465 1 a465 1 # else /* ! MAIL11V3 */ d467 1 a467 1 # endif /* MAIL11V3 */ d496 1 a496 1 # ifdef MAIL11V3 d522 1 a522 1 # endif /* MAIL11V3 */ d625 2 a626 2 #define NFORKTRIES 5 #ifdef VMUNIX d628 1 a628 1 #else /* !VMUNIX */ d630 1 a630 1 #endif /* VMUNIX */ d632 1 a632 1 #define DOFORK(fORKfN) \ d858 1 a858 1 # ifdef HOSTINFO d873 1 a873 1 # else /* !HOSTINFO */ d875 1 a875 1 # endif /* HOSTINFO */ d888 1 a888 1 # ifdef LOG d891 1 a891 1 # endif /* LOG */ d894 1 a894 1 # ifdef HOSTINFO d900 1 a900 1 # endif /* HOSTINFO */ d943 1 a943 1 #ifdef SIGCHLD d945 1 a945 1 #endif /* SIGCHLD */ d966 1 d1027 1 a1027 5 #if defined(XPG3) for (i = (int) sysconf (_SC_OPEN_MAX); i > 2; --i) { #else for (i = getdtablesize(); i > 2; --i) { #endif /* XPG3 */ d1039 1 a1039 1 #endif /* EPROCLIM */ a1215 2 # define TBUFLEN 128 char tbuf[TBUFLEN]; a1216 9 /* ** If there's a very long To: line the buffer in syslog() on HPUX ** (and others?) isn't large enough. Truncate long To: lines since ** they are likely to be of little use anyway. */ if (strlen (CurEnv->e_to) >= TBUFLEN) sprintf(tbuf, "%.*s ...", TBUFLEN-5, CurEnv->e_to); else (void) strcpy(tbuf, CurEnv->e_to); d1219 1 a1219 1 tbuf, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); d1270 1 a1270 1 #ifdef UGLYUUCP d1287 1 a1287 1 #endif /* UGLYUUCP */ d1551 1 a1551 1 #ifdef QUEUE a1571 10 #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK) /* ** lockf()/fcntl() emulation of flock() breaks down here as ** locks are not inherited across fork(). release lock so ** child can re-lock. **/ if (lockfp != NULL) (void) flock(fileno(lockfp), LOCK_UN); #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */ a1589 12 #if defined(FCNTL_FLOCK) || defined(LOCKF_FLOCK) /* ** re-lock tf file in child (again for flock() as lockf()) */ if (lockfp != NULL && flock(fileno(lockfp), LOCK_EX|LOCK_NB) <0) { /* someone else got in before us */ (void) fclose(lockfp); return; } #endif /* (FCNTL_FLOCK) || (LOCKF_FLOCK) */ @ 5.38.0.11 log @Fixed forward declaration of sendoff(). @ text @a112 1 int sendoff(); d136 1 @ 5.38.0.12 log @Deleted un-needed initialization. @ text @d808 2 a809 1 FILE *mfile, *rfile; @ 5.38.0.13 log @Replaced logdelivery() with version from Piet Beertema that folds rather than truncates long lines. @ text @d1218 2 a1219 3 # ifdef LOG # define LOGSPLIT 900 register char *p, *q; d1222 3 a1224 2 ** Split up long To: lines, since the buffer in ** syslog() on various systems isn't large enough. d1226 5 a1230 13 p = CurEnv->e_to; while (strlen(p) >= LOGSPLIT) { if ((q = index(p + LOGSPLIT, ',')) != NULL) { syslog(LOG_INFO, "%s: to=%.*s(cont'd), delay=%s, stat=%s", CurEnv->e_id, q - p + 1, p, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); p = q + 1; } else break; } d1232 1 a1232 1 p, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); @ 5.38.0.14 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 @d25 1 a26 1 #include <sys/signal.h> @ 5.38.0.15 log @Fixed declaration of setupshares() for convex. Fixed test for printing message when connecting to a non-primary MX host. @ text @a36 2 extern void syserr(); extern setupshares(int, void (*func)()); d861 1 a861 1 if (j > 0) d1004 1 a1004 1 syserr("Can't install shares!"); d1014 1 a1014 1 syserr("Can't install shares!"); @ 5.38.0.16 log @Added static keywork to declaration for mailfile() and markfailure(). @ text @a138 1 static markfailure(), mailfile(); a575 1 static a1410 1 static @ 5.38.0.17 log @ANSIfied. @ text @d37 2 a38 1 int setupshares(int, void (*func)()); a40 10 #ifdef __STDC__ static mailfile(char *, ADDRESS *); static void markfailure(ENVELOPE *, ADDRESS *, int); static sendoff(ENVELOPE *, MAILER *, char **, ADDRESS *); #else /* !__STDC__ */ static mailfile(); static void markfailure(); static sendoff(); #endif /* __STDC__ */ d115 1 d136 4 d577 1 a577 1 static void d589 1 d646 1 a646 1 Xsleep((unsigned) NFORKTRIES - i);\ d751 1 a751 1 const char *name; d813 1 d845 1 a950 2 if (pid > 0 && tTd(4, 2)) printf("openmailer: forking (pid = %d)\n", pid); a1087 1 void d1125 3 d1129 1 d1134 3 d1138 1 a1217 1 void d1219 1 a1219 1 const char *stat; d1221 1 a1267 1 void d1272 1 a1334 1 void a1429 2 if (pid > 0 && tTd(4, 2)) printf("mailfile: forking (pid = %d)\n", pid); a1526 1 void d1534 1 a1534 1 FILE *lockfp = NULL; d1539 2 d1571 2 a1608 2 if (pid > 0 && tTd(4, 2)) printf("sendall: forking (pid = %d)\n", pid); d1690 1 @ 5.38.0.18 log @In sendall(), remember to close lockfp if the message is queued. From Kannan Varadhan . @ text @a1588 2 if (lockfp != NULL) (void) fclose(lockfp); @