122701Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 642825Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822701Sdist 922701Sdist #ifndef lint 10*57731Seric static char sccsid[] = "@(#)deliver.c 6.12 (Berkeley) 01/26/93"; 1133728Sbostic #endif /* not lint */ 1222701Sdist 1340961Sbostic #include "sendmail.h" 1433931Sbostic #include <sys/signal.h> 1533931Sbostic #include <sys/stat.h> 1633931Sbostic #include <netdb.h> 1736030Sbostic #include <fcntl.h> 1833931Sbostic #include <errno.h> 1935651Seric #ifdef NAMED_BIND 2034022Sbostic #include <arpa/nameser.h> 2134022Sbostic #include <resolv.h> 2235651Seric #endif 23294Seric 24294Seric /* 254315Seric ** DELIVER -- Deliver a message to a list of addresses. 26294Seric ** 274315Seric ** This routine delivers to everyone on the same host as the 284315Seric ** user on the head of the list. It is clever about mailers 294315Seric ** that don't handle multiple users. It is NOT guaranteed 304315Seric ** that it will deliver to all these addresses however -- so 314315Seric ** deliver should be called once for each address on the 324315Seric ** list. 334315Seric ** 34294Seric ** Parameters: 359370Seric ** e -- the envelope to deliver. 364621Seric ** firstto -- head of the address list to deliver to. 37294Seric ** 38294Seric ** Returns: 39294Seric ** zero -- successfully delivered. 40294Seric ** else -- some failure, see ExitStat for more info. 41294Seric ** 42294Seric ** Side Effects: 43294Seric ** The standard input is passed off to someone. 44294Seric */ 45294Seric 469370Seric deliver(e, firstto) 479370Seric register ENVELOPE *e; 484621Seric ADDRESS *firstto; 49294Seric { 504452Seric char *host; /* host being sent to */ 514452Seric char *user; /* user being sent to */ 52294Seric char **pvp; 533233Seric register char **mvp; 543233Seric register char *p; 5510306Seric register MAILER *m; /* mailer for this recipient */ 564397Seric ADDRESS *ctladdr; 5754967Seric register MCI *mci; 584621Seric register ADDRESS *to = firstto; 594863Seric bool clever = FALSE; /* running user smtp to this mailer */ 605032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 6151951Seric int rcode; /* response code */ 6251951Seric char *from; /* pointer to from person */ 6357454Seric char *firstsig; /* signature of firstto */ 6410306Seric char *pv[MAXPV+1]; 6510306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 6610306Seric char buf[MAXNAME]; 6710306Seric char tfrombuf[MAXNAME]; /* translated from person */ 6851951Seric char rpathbuf[MAXNAME]; /* translated return path */ 6957441Seric extern int checkcompat(); 7010306Seric extern ADDRESS *getctladdr(); 7110306Seric extern char *remotename(); 7254967Seric extern MCI *openmailer(); 7357454Seric extern char *hostsignature(); 74294Seric 754488Seric errno = 0; 767052Seric if (bitset(QDONTSEND, to->q_flags)) 773233Seric return (0); 78294Seric 7935651Seric #ifdef NAMED_BIND 8034022Sbostic /* unless interactive, try twice, over a minute */ 8134022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 8234022Sbostic _res.retrans = 30; 8334022Sbostic _res.retry = 2; 8434022Sbostic } 8536788Sbostic #endif 8634022Sbostic 876974Seric m = to->q_mailer; 886974Seric host = to->q_host; 896974Seric 907672Seric if (tTd(10, 1)) 913233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 926974Seric m->m_mno, host, to->q_user); 93294Seric 94294Seric /* 955903Seric ** If this mailer is expensive, and if we don't want to make 965903Seric ** connections now, just mark these addresses and return. 975903Seric ** This is useful if we want to batch connections to 985903Seric ** reduce load. This will cause the messages to be 995903Seric ** queued up, and a daemon will come along to send the 1005903Seric ** messages later. 1015903Seric ** This should be on a per-mailer basis. 1025903Seric */ 1035903Seric 10410682Seric if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && 1058428Seric !Verbose) 1065903Seric { 1075903Seric for (; to != NULL; to = to->q_next) 1088431Seric { 1098431Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 1108431Seric continue; 1118431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 1129370Seric e->e_to = to->q_paddr; 1138496Seric message(Arpa_Info, "queued"); 1148496Seric if (LogLevel > 4) 11554967Seric logdelivery("queued", e); 1168431Seric } 1179370Seric e->e_to = NULL; 1185903Seric return (0); 1195903Seric } 1205903Seric 1215903Seric /* 1223233Seric ** Do initial argv setup. 1233233Seric ** Insert the mailer name. Notice that $x expansion is 1243233Seric ** NOT done on the mailer name. Then, if the mailer has 1253233Seric ** a picky -f flag, we insert it as appropriate. This 1263233Seric ** code does not check for 'pv' overflow; this places a 1273233Seric ** manifest lower limit of 4 for MAXPV. 1288062Seric ** The from address rewrite is expected to make 1298062Seric ** the address relative to the other end. 1302968Seric */ 1312968Seric 1324452Seric /* rewrite from address, using rewriting rules */ 13355012Seric (void) strcpy(rpathbuf, remotename(e->e_returnpath, m, TRUE, TRUE, e)); 13451951Seric if (e->e_returnpath == e->e_sender) 13551951Seric { 13651951Seric from = rpathbuf; 13751951Seric } 13851951Seric else 13951951Seric { 14055012Seric (void) strcpy(tfrombuf, remotename(e->e_sender, m, TRUE, TRUE, e)); 14151951Seric from = tfrombuf; 14251951Seric } 1434452Seric 14451951Seric define('f', e->e_returnpath, e); /* raw return path */ 14551951Seric define('<', rpathbuf, e); /* translated return path */ 14651951Seric define('g', from, e); /* translated sender */ 1479370Seric define('h', host, e); /* to host */ 1483233Seric Errors = 0; 1493233Seric pvp = pv; 1503233Seric *pvp++ = m->m_argv[0]; 1512968Seric 1523233Seric /* insert -f or -r flag as appropriate */ 15310682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1543233Seric { 15510682Seric if (bitnset(M_FOPT, m->m_flags)) 1563233Seric *pvp++ = "-f"; 1573233Seric else 1583233Seric *pvp++ = "-r"; 15951951Seric *pvp++ = newstr(rpathbuf); 1603233Seric } 161294Seric 162294Seric /* 1633233Seric ** Append the other fixed parts of the argv. These run 1643233Seric ** up to the first entry containing "$u". There can only 1653233Seric ** be one of these, and there are only a few more slots 1663233Seric ** in the pv after it. 167294Seric */ 168294Seric 1693233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 170294Seric { 17156795Seric while ((p = strchr(p, '\001')) != NULL) 1723233Seric if (*++p == 'u') 1733233Seric break; 1743233Seric if (p != NULL) 1753233Seric break; 1763233Seric 1773233Seric /* this entry is safe -- go ahead and process it */ 1789370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1793233Seric *pvp++ = newstr(buf); 1803233Seric if (pvp >= &pv[MAXPV - 3]) 1813233Seric { 1823233Seric syserr("Too many parameters to %s before $u", pv[0]); 1833233Seric return (-1); 1843233Seric } 185294Seric } 1864863Seric 1876038Seric /* 1886038Seric ** If we have no substitution for the user name in the argument 1896038Seric ** list, we know that we must supply the names otherwise -- and 1906038Seric ** SMTP is the answer!! 1916038Seric */ 1926038Seric 1933233Seric if (*mvp == NULL) 1944863Seric { 1954863Seric /* running SMTP */ 1965179Seric # ifdef SMTP 1974863Seric clever = TRUE; 1984863Seric *pvp = NULL; 19956795Seric # else /* SMTP */ 2006038Seric /* oops! we don't implement SMTP */ 2015179Seric syserr("SMTP style mailer"); 2025179Seric return (EX_SOFTWARE); 20356795Seric # endif /* SMTP */ 2044863Seric } 205294Seric 206294Seric /* 2073233Seric ** At this point *mvp points to the argument with $u. We 2083233Seric ** run through our address list and append all the addresses 2093233Seric ** we can. If we run out of space, do not fret! We can 2103233Seric ** always send another copy later. 211294Seric */ 212294Seric 2133233Seric tobuf[0] = '\0'; 2149370Seric e->e_to = tobuf; 2154397Seric ctladdr = NULL; 21657454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 2173233Seric for (; to != NULL; to = to->q_next) 218294Seric { 2193233Seric /* avoid sending multiple recipients to dumb mailers */ 22010682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 2213233Seric break; 2223233Seric 2233233Seric /* if already sent or not for this host, don't send */ 2247052Seric if (bitset(QDONTSEND, to->q_flags) || 22557454Seric to->q_mailer != firstto->q_mailer || 22657454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 2273233Seric continue; 2284397Seric 2298225Seric /* avoid overflowing tobuf */ 23042462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 2318225Seric break; 2328225Seric 2337672Seric if (tTd(10, 1)) 2345032Seric { 2355032Seric printf("\nsend to "); 2365032Seric printaddr(to, FALSE); 2375032Seric } 2385032Seric 2394397Seric /* compute effective uid/gid when sending */ 2404596Seric if (to->q_mailer == ProgMailer) 2414397Seric ctladdr = getctladdr(to); 2424397Seric 2433233Seric user = to->q_user; 2449370Seric e->e_to = to->q_paddr; 2453233Seric to->q_flags |= QDONTSEND; 246*57731Seric if (tTd(10, 5)) 247*57731Seric { 248*57731Seric printf("deliver: QDONTSEND "); 249*57731Seric printaddr(to, FALSE); 250*57731Seric } 2513233Seric 2523233Seric /* 2533233Seric ** Check to see that these people are allowed to 2543233Seric ** talk to each other. 2553233Seric */ 2563233Seric 25710699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 25810699Seric { 25929914Seric NoReturn = TRUE; 26010699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 26110699Seric giveresponse(EX_UNAVAILABLE, m, e); 26210699Seric continue; 26310699Seric } 26457441Seric rcode = checkcompat(to, e); 26557459Seric if (rcode != EX_OK) 266294Seric { 26757459Seric giveresponse(rcode, m, e); 2683233Seric continue; 269294Seric } 2703233Seric 2713233Seric /* 2724099Seric ** Strip quote bits from names if the mailer is dumb 2734099Seric ** about them. 2743233Seric */ 2753233Seric 27610682Seric if (bitnset(M_STRIPQ, m->m_flags)) 277294Seric { 27854983Seric stripquotes(user); 27954983Seric stripquotes(host); 2803233Seric } 2813233Seric 2829206Seric /* hack attack -- delivermail compatibility */ 2839206Seric if (m == ProgMailer && *user == '|') 2849206Seric user++; 2859206Seric 2863233Seric /* 2874161Seric ** If an error message has already been given, don't 2884161Seric ** bother to send to this address. 2894161Seric ** 2904161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2914161Seric ** >> NOTE >> cannot do any further aliasing; that 2924161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2934161Seric */ 2944161Seric 2957293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2964161Seric continue; 2974161Seric 2984283Seric /* save statistics.... */ 2999370Seric markstats(e, to); 3004283Seric 3014161Seric /* 3023233Seric ** See if this user name is "special". 3033233Seric ** If the user name has a slash in it, assume that this 3046974Seric ** is a file -- send it off without further ado. Note 3056974Seric ** that this type of addresses is not processed along 3066974Seric ** with the others, so we fudge on the To person. 3073233Seric */ 3083233Seric 30957402Seric if (m == FileMailer) 3103233Seric { 31157402Seric rcode = mailfile(user, getctladdr(to), e); 31257402Seric giveresponse(rcode, m, e); 31357402Seric if (rcode == EX_OK) 31457402Seric to->q_flags |= QSENT; 31557402Seric continue; 316294Seric } 3173233Seric 3184315Seric /* 3194315Seric ** Address is verified -- add this user to mailer 3204315Seric ** argv, and add it to the print list of recipients. 3214315Seric */ 3224315Seric 3236059Seric /* link together the chain of recipients */ 3246272Seric to->q_tchain = tochain; 3256272Seric tochain = to; 3266059Seric 3273233Seric /* create list of users for error messages */ 3289388Seric (void) strcat(tobuf, ","); 3294082Seric (void) strcat(tobuf, to->q_paddr); 3309370Seric define('u', user, e); /* to user */ 3319370Seric define('z', to->q_home, e); /* user's home */ 3323233Seric 3334863Seric /* 3346059Seric ** Expand out this user into argument list. 3354863Seric */ 3364863Seric 3376059Seric if (!clever) 3383233Seric { 3399370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3404863Seric *pvp++ = newstr(buf); 3414863Seric if (pvp >= &pv[MAXPV - 2]) 3424863Seric { 3434863Seric /* allow some space for trailing parms */ 3444863Seric break; 3454863Seric } 3464863Seric } 347294Seric } 348294Seric 3494067Seric /* see if any addresses still exist */ 3504067Seric if (tobuf[0] == '\0') 3514863Seric { 3529370Seric define('g', (char *) NULL, e); 35351951Seric define('<', (char *) NULL, e); 3544067Seric return (0); 3554863Seric } 3564067Seric 3573233Seric /* print out messages as full list */ 3589388Seric e->e_to = tobuf + 1; 3593233Seric 360294Seric /* 3613233Seric ** Fill out any parameters after the $u parameter. 362294Seric */ 363294Seric 3644863Seric while (!clever && *++mvp != NULL) 365294Seric { 3669370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3673233Seric *pvp++ = newstr(buf); 3683233Seric if (pvp >= &pv[MAXPV]) 3693233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 370294Seric } 3713233Seric *pvp++ = NULL; 372294Seric 373294Seric /* 374294Seric ** Call the mailer. 3752898Seric ** The argument vector gets built, pipes 376294Seric ** are created as necessary, and we fork & exec as 3772898Seric ** appropriate. 3784863Seric ** If we are running SMTP, we just need to clean up. 379294Seric */ 380294Seric 38141050Seric if (ctladdr == NULL) 38241050Seric ctladdr = &e->e_from; 38335651Seric #ifdef NAMED_BIND 38451313Seric if (ConfigLevel < 2) 38551313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 38635651Seric #endif 38754967Seric mci = openmailer(m, pv, ctladdr, clever, e); 38854967Seric if (mci == NULL) 38954967Seric { 39054967Seric /* catastrophic error */ 39154967Seric rcode = -1; 39254967Seric goto give_up; 39354967Seric } 39454967Seric else if (mci->mci_state != MCIS_OPEN) 39554967Seric { 39654967Seric /* couldn't open the mailer */ 39754967Seric rcode = mci->mci_exitstat; 39855173Seric errno = mci->mci_errno; 39954967Seric if (rcode == EX_OK) 40054967Seric { 40154967Seric /* shouldn't happen */ 40257721Seric syserr("deliver: rcode=%d, mci_state=%d, sig=%s", 40357721Seric rcode, mci->mci_state, firstsig); 40454967Seric rcode = EX_SOFTWARE; 40554967Seric } 40654967Seric } 40754967Seric else if (!clever) 40854967Seric { 40954967Seric /* 41054967Seric ** Format and send message. 41154967Seric */ 41254967Seric 41354967Seric putfromline(mci->mci_out, m, e); 41454967Seric (*e->e_puthdr)(mci->mci_out, m, e); 41554967Seric putline("\n", mci->mci_out, m); 41654967Seric (*e->e_putbody)(mci->mci_out, m, e); 41754967Seric 41854967Seric /* get the exit status */ 41954967Seric rcode = endmailer(mci, pv[0]); 42054967Seric } 42154967Seric else 42233931Sbostic #ifdef SMTP 42335651Seric { 42454967Seric /* 42554967Seric ** Send the MAIL FROM: protocol 42654967Seric */ 42753751Seric 42854967Seric rcode = smtpmailfrom(m, mci, e); 42954967Seric if (rcode == EX_OK) 43035651Seric { 43154967Seric register char *t = tobuf; 43254967Seric register int i; 43353751Seric 43454967Seric /* send the recipient list */ 43554967Seric tobuf[0] = '\0'; 43654967Seric for (to = tochain; to != NULL; to = to->q_tchain) 43753738Seric { 43854967Seric e->e_to = to->q_paddr; 43954967Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 44053738Seric { 44154967Seric markfailure(e, to, i); 44254967Seric giveresponse(i, m, e); 4439388Seric } 44453738Seric else 44553738Seric { 44654967Seric *t++ = ','; 44754967Seric for (p = to->q_paddr; *p; *t++ = *p++) 44854967Seric continue; 4499388Seric } 45054967Seric } 4519388Seric 45254967Seric /* now send the data */ 45354967Seric if (tobuf[0] == '\0') 45454967Seric { 45554967Seric e->e_to = NULL; 45654967Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 45754967Seric smtprset(m, mci, e); 45854967Seric } 45954967Seric else 46054967Seric { 46154967Seric e->e_to = tobuf + 1; 46254967Seric rcode = smtpdata(m, mci, e); 46354967Seric } 46454967Seric 46554967Seric /* now close the connection */ 46654967Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 46753751Seric smtpquit(m, mci, e); 4689370Seric } 4694863Seric } 47054967Seric #else /* not SMTP */ 47133935Sbostic { 47254967Seric syserr("deliver: need SMTP compiled to use clever mailer"); 47354967Seric rcode = -1; 47454967Seric goto give_up; 47533935Sbostic } 47654967Seric #endif /* SMTP */ 47735651Seric #ifdef NAMED_BIND 47851313Seric if (ConfigLevel < 2) 47951313Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 48035651Seric #endif 4813233Seric 48254967Seric /* arrange a return receipt if requested */ 48354967Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 48454967Seric { 48554967Seric e->e_flags |= EF_SENDRECEIPT; 48654967Seric /* do we want to send back more info? */ 48754967Seric } 48854967Seric 4894621Seric /* 4909388Seric ** Do final status disposal. 4919388Seric ** We check for something in tobuf for the SMTP case. 4929388Seric ** If we got a temporary failure, arrange to queue the 4939388Seric ** addressees. 4944621Seric */ 4954621Seric 49654967Seric give_up: 4979388Seric if (tobuf[0] != '\0') 49810105Seric giveresponse(rcode, m, e); 49947284Seric for (to = tochain; to != NULL; to = to->q_tchain) 50054967Seric { 50147284Seric if (rcode != EX_OK) 50210092Seric markfailure(e, to, rcode); 50347284Seric else 50457589Seric { 50547284Seric to->q_flags |= QSENT; 50657589Seric e->e_nsent++; 50757589Seric } 50854967Seric } 5094621Seric 51054967Seric /* 51154967Seric ** Restore state and return. 51254967Seric */ 51354967Seric 5144488Seric errno = 0; 5159370Seric define('g', (char *) NULL, e); 51651951Seric define('<', (char *) NULL, e); 5178003Seric return (rcode); 5183233Seric } 5193233Seric /* 52010092Seric ** MARKFAILURE -- mark a failure on a specific address. 52110092Seric ** 52210092Seric ** Parameters: 52310092Seric ** e -- the envelope we are sending. 52410092Seric ** q -- the address to mark. 52510092Seric ** rcode -- the code signifying the particular failure. 52610092Seric ** 52710092Seric ** Returns: 52810092Seric ** none. 52910092Seric ** 53010092Seric ** Side Effects: 53110092Seric ** marks the address (and possibly the envelope) with the 53210092Seric ** failure so that an error will be returned or 53310092Seric ** the message will be queued, as appropriate. 53410092Seric */ 53510092Seric 53610092Seric markfailure(e, q, rcode) 53710092Seric register ENVELOPE *e; 53810092Seric register ADDRESS *q; 53910092Seric int rcode; 54010092Seric { 54110092Seric if (rcode == EX_OK) 54210092Seric return; 54340996Sbostic else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) 54410092Seric q->q_flags |= QBADADDR; 54510092Seric else if (curtime() > e->e_ctime + TimeOut) 54610092Seric { 54710092Seric extern char *pintvl(); 54810105Seric char buf[MAXLINE]; 54910092Seric 55010092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 55110105Seric { 55210105Seric (void) sprintf(buf, "Cannot send message for %s", 55310092Seric pintvl(TimeOut, FALSE)); 55410105Seric if (e->e_message != NULL) 55510105Seric free(e->e_message); 55610105Seric e->e_message = newstr(buf); 55710105Seric message(Arpa_Info, buf); 55810105Seric } 55910092Seric q->q_flags |= QBADADDR; 56010092Seric e->e_flags |= EF_TIMEOUT; 56157642Seric fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); 56210092Seric } 56310092Seric else 56410092Seric q->q_flags |= QQUEUEUP; 56510092Seric } 56610092Seric /* 5674214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5684214Seric ** 5694214Seric ** This MUST be a macro, since after a vfork we are running 5704214Seric ** two processes on the same stack!!! 5714214Seric ** 5724214Seric ** Parameters: 5734214Seric ** none. 5744214Seric ** 5754214Seric ** Returns: 5764214Seric ** From a macro??? You've got to be kidding! 5774214Seric ** 5784214Seric ** Side Effects: 5794214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5804214Seric ** pid of child in parent, zero in child. 5814214Seric ** -1 on unrecoverable error. 5824214Seric ** 5834214Seric ** Notes: 5844214Seric ** I'm awfully sorry this looks so awful. That's 5854214Seric ** vfork for you..... 5864214Seric */ 5874214Seric 5884214Seric # define NFORKTRIES 5 5894214Seric 59052107Seric # ifndef FORK 59152107Seric # define FORK fork 59252107Seric # endif 59352107Seric 5944214Seric # define DOFORK(fORKfN) \ 5954214Seric {\ 5964214Seric register int i;\ 5974214Seric \ 59823504Seric for (i = NFORKTRIES; --i >= 0; )\ 5994214Seric {\ 6004214Seric pid = fORKfN();\ 6014214Seric if (pid >= 0)\ 6024214Seric break;\ 60323504Seric if (i > 0)\ 60425617Seric sleep((unsigned) NFORKTRIES - i);\ 6054214Seric }\ 6064214Seric } 6074214Seric /* 6084637Seric ** DOFORK -- simple fork interface to DOFORK. 6094637Seric ** 6104637Seric ** Parameters: 6114637Seric ** none. 6124637Seric ** 6134637Seric ** Returns: 6144637Seric ** pid of child in parent. 6154637Seric ** zero in child. 6164637Seric ** -1 on error. 6174637Seric ** 6184637Seric ** Side Effects: 6194637Seric ** returns twice, once in parent and once in child. 6204637Seric */ 6214637Seric 6224637Seric dofork() 6234637Seric { 6244637Seric register int pid; 6254637Seric 6264637Seric DOFORK(fork); 6274637Seric return (pid); 6284637Seric } 6294637Seric /* 6304863Seric ** ENDMAILER -- Wait for mailer to terminate. 6314863Seric ** 6324863Seric ** We should never get fatal errors (e.g., segmentation 6334863Seric ** violation), so we report those specially. For other 6344863Seric ** errors, we choose a status message (into statmsg), 6354863Seric ** and if it represents an error, we print it. 6364863Seric ** 6374863Seric ** Parameters: 6384863Seric ** pid -- pid of mailer. 6394863Seric ** name -- name of mailer (for error messages). 6404863Seric ** 6414863Seric ** Returns: 6424863Seric ** exit code of mailer. 6434863Seric ** 6444863Seric ** Side Effects: 6454863Seric ** none. 6464863Seric */ 6474863Seric 64853738Seric endmailer(mci, name) 64954967Seric register MCI *mci; 6504863Seric char *name; 6514863Seric { 6529370Seric int st; 6534863Seric 65453738Seric /* close any connections */ 65553738Seric if (mci->mci_in != NULL) 65653738Seric (void) fclose(mci->mci_in); 65753738Seric if (mci->mci_out != NULL) 65853738Seric (void) fclose(mci->mci_out); 65953738Seric mci->mci_in = mci->mci_out = NULL; 66053738Seric mci->mci_state = MCIS_CLOSED; 66153738Seric 6626038Seric /* in the IPC case there is nothing to wait for */ 66353738Seric if (mci->mci_pid == 0) 6646038Seric return (EX_OK); 6656038Seric 6666038Seric /* wait for the mailer process to die and collect status */ 66753738Seric st = waitfor(mci->mci_pid); 6689370Seric if (st == -1) 6698127Seric { 6709370Seric syserr("endmailer %s: wait", name); 6719370Seric return (EX_SOFTWARE); 6724863Seric } 6736038Seric 6746038Seric /* see if it died a horrid death */ 6754863Seric if ((st & 0377) != 0) 6764863Seric { 67724941Seric syserr("mailer %s died with signal %o", name, st); 67824941Seric ExitStat = EX_TEMPFAIL; 67924941Seric return (EX_TEMPFAIL); 6804863Seric } 6816038Seric 6826038Seric /* normal death -- return status */ 6839370Seric st = (st >> 8) & 0377; 6849370Seric return (st); 6854863Seric } 6864863Seric /* 6874863Seric ** OPENMAILER -- open connection to mailer. 6884863Seric ** 6894863Seric ** Parameters: 6904863Seric ** m -- mailer descriptor. 6914863Seric ** pvp -- parameter vector to pass to mailer. 6924863Seric ** ctladdr -- controlling address for user. 6934863Seric ** clever -- create a full duplex connection. 6944863Seric ** 6954863Seric ** Returns: 69653738Seric ** The mail connection info struct for this connection. 69753738Seric ** NULL on failure. 6984863Seric ** 6994863Seric ** Side Effects: 7004863Seric ** creates a mailer in a subprocess. 7014863Seric */ 7024863Seric 70354967Seric MCI * 70454967Seric openmailer(m, pvp, ctladdr, clever, e) 7059370Seric MAILER *m; 7064863Seric char **pvp; 7074863Seric ADDRESS *ctladdr; 7084863Seric bool clever; 70954967Seric ENVELOPE *e; 7104863Seric { 7114863Seric int pid; 71254967Seric register MCI *mci; 7134709Seric int mpvect[2]; 7144863Seric int rpvect[2]; 7153233Seric extern FILE *fdopen(); 7163233Seric 7177672Seric if (tTd(11, 1)) 718294Seric { 7198178Seric printf("openmailer:"); 7203233Seric printav(pvp); 721294Seric } 7224488Seric errno = 0; 7233233Seric 72425050Seric CurHostName = m->m_mailer; 72525050Seric 7266038Seric /* 7276038Seric ** Deal with the special case of mail handled through an IPC 7286038Seric ** connection. 7296038Seric ** In this case we don't actually fork. We must be 7306038Seric ** running SMTP for this to work. We will return a 7316038Seric ** zero pid to indicate that we are running IPC. 73211160Seric ** We also handle a debug version that just talks to stdin/out. 7336038Seric */ 7346038Seric 73511160Seric /* check for Local Person Communication -- not for mortals!!! */ 73611160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 73711160Seric { 73854967Seric mci = (MCI *) xalloc(sizeof *mci); 73954993Seric bzero((char *) mci, sizeof *mci); 74053738Seric mci->mci_in = stdin; 74153738Seric mci->mci_out = stdout; 74254967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 74353751Seric mci->mci_mailer = m; 74411160Seric } 74554967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 74654967Seric strcmp(m->m_mailer, "[TCP]") == 0) 7476038Seric { 74852107Seric #ifdef DAEMON 74957454Seric register int i; 7507285Seric register u_short port; 75157454Seric char *curhost; 75254967Seric extern MCI *mci_get(); 75357454Seric extern char *hostsignature(); 7546038Seric 75525050Seric CurHostName = pvp[1]; 75657454Seric curhost = hostsignature(m, pvp[1], e); 75754967Seric 7586038Seric if (!clever) 7596038Seric syserr("non-clever IPC"); 7606632Seric if (pvp[2] != NULL) 7617285Seric port = atoi(pvp[2]); 7626632Seric else 7637285Seric port = 0; 76457454Seric while (*curhost != '\0') 76529433Sbloom { 76657454Seric register char *p; 76757454Seric char hostbuf[MAXNAME]; 76857454Seric 76957454Seric /* pull the next host from the signature */ 77057454Seric p = strchr(curhost, ':'); 77157454Seric if (p == NULL) 77257454Seric p = &curhost[strlen(curhost)]; 77357454Seric strncpy(hostbuf, curhost, p - curhost); 77457454Seric hostbuf[p - curhost] = '\0'; 77557454Seric if (*p != '\0') 77657454Seric p++; 77757454Seric curhost = p; 77857454Seric 77953738Seric /* see if we already know that this host is fried */ 78057454Seric CurHostName = hostbuf; 78157454Seric mci = mci_get(hostbuf, m); 78254967Seric if (mci->mci_state != MCIS_CLOSED) 78357387Seric { 78457387Seric if (tTd(11, 1)) 78557387Seric { 78657387Seric printf("openmailer: "); 78757387Seric mci_dump(mci); 78857387Seric } 78953738Seric return mci; 79057387Seric } 79153751Seric mci->mci_mailer = m; 79254967Seric if (mci->mci_exitstat != EX_OK) 79354967Seric continue; 79454967Seric 79554967Seric /* try the connection */ 79657454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 79754967Seric message(Arpa_Info, "Connecting to %s (%s)...", 79857454Seric hostbuf, m->m_name); 79957454Seric i = makeconnection(hostbuf, port, mci, 80054967Seric bitnset(M_SECURE_PORT, m->m_flags)); 80154967Seric mci->mci_exitstat = i; 80254967Seric mci->mci_errno = errno; 80354967Seric if (i == EX_OK) 80452106Seric { 80554967Seric mci->mci_state = MCIS_OPENING; 80654967Seric mci_cache(mci); 80754967Seric break; 80834022Sbostic } 80954967Seric else if (tTd(11, 1)) 81054967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 81154967Seric i, errno); 81253738Seric 81354967Seric 81453738Seric /* enter status of this host */ 81553738Seric setstat(i); 8166047Seric } 81754993Seric mci->mci_pid = 0; 81854967Seric #else /* no DAEMON */ 8199370Seric syserr("openmailer: no IPC"); 82057387Seric if (tTd(11, 1)) 82157387Seric printf("openmailer: NULL\n"); 82253738Seric return NULL; 82354967Seric #endif /* DAEMON */ 8246038Seric } 82554967Seric else 826294Seric { 82754967Seric /* create a pipe to shove the mail through */ 82854967Seric if (pipe(mpvect) < 0) 82954967Seric { 83054967Seric syserr("openmailer: pipe (to mailer)"); 83157387Seric if (tTd(11, 1)) 83257387Seric printf("openmailer: NULL\n"); 83354967Seric return NULL; 83454967Seric } 8354863Seric 83654967Seric /* if this mailer speaks smtp, create a return pipe */ 83754967Seric if (clever && pipe(rpvect) < 0) 83854967Seric { 83954967Seric syserr("openmailer: pipe (from mailer)"); 84054967Seric (void) close(mpvect[0]); 84154967Seric (void) close(mpvect[1]); 84257387Seric if (tTd(11, 1)) 84357387Seric printf("openmailer: NULL\n"); 84454967Seric return NULL; 84554967Seric } 8464863Seric 84754967Seric /* 84854967Seric ** Actually fork the mailer process. 84954967Seric ** DOFORK is clever about retrying. 85054967Seric ** 85154967Seric ** Dispose of SIGCHLD signal catchers that may be laying 85254967Seric ** around so that endmail will get it. 85354967Seric */ 8546038Seric 85554967Seric if (e->e_xfp != NULL) 85654967Seric (void) fflush(e->e_xfp); /* for debugging */ 85754967Seric (void) fflush(stdout); 85826434Seric # ifdef SIGCHLD 85954967Seric (void) signal(SIGCHLD, SIG_DFL); 86056795Seric # endif /* SIGCHLD */ 86154967Seric DOFORK(FORK); 86254967Seric /* pid is set by DOFORK */ 86354967Seric if (pid < 0) 8644863Seric { 86554967Seric /* failure */ 86654967Seric syserr("openmailer: cannot fork"); 86754967Seric (void) close(mpvect[0]); 86854967Seric (void) close(mpvect[1]); 86954967Seric if (clever) 87054967Seric { 87154967Seric (void) close(rpvect[0]); 87254967Seric (void) close(rpvect[1]); 87354967Seric } 87457387Seric if (tTd(11, 1)) 87557387Seric printf("openmailer: NULL\n"); 87654967Seric return NULL; 8774863Seric } 87854967Seric else if (pid == 0) 87954967Seric { 88054967Seric int i; 88156678Seric int saveerrno; 88257529Seric char *env[2]; 88354967Seric extern int DtableSize; 88415772Seric 88554967Seric /* child -- set up input & exec mailer */ 88654967Seric /* make diagnostic output be standard output */ 88754967Seric (void) signal(SIGINT, SIG_IGN); 88854967Seric (void) signal(SIGHUP, SIG_IGN); 88954967Seric (void) signal(SIGTERM, SIG_DFL); 8904709Seric 89154967Seric /* arrange to filter std & diag output of command */ 89254967Seric if (clever) 89354967Seric { 89454967Seric (void) close(rpvect[0]); 89554967Seric (void) close(1); 89654967Seric (void) dup(rpvect[1]); 89754967Seric (void) close(rpvect[1]); 89854967Seric } 89954967Seric else if (OpMode == MD_SMTP || HoldErrs) 90054967Seric { 90154967Seric /* put mailer output in transcript */ 90254967Seric (void) close(1); 90354967Seric (void) dup(fileno(e->e_xfp)); 90454967Seric } 90554967Seric (void) close(2); 90654967Seric (void) dup(1); 9074709Seric 90854967Seric /* arrange to get standard input */ 90954967Seric (void) close(mpvect[1]); 91054967Seric (void) close(0); 91154967Seric if (dup(mpvect[0]) < 0) 9124417Seric { 91354967Seric syserr("Cannot dup to zero!"); 91454967Seric _exit(EX_OSERR); 9154417Seric } 91654967Seric (void) close(mpvect[0]); 91754967Seric if (!bitnset(M_RESTR, m->m_flags)) 9184415Seric { 91954967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 92054967Seric { 92154967Seric (void) setgid(DefGid); 92254967Seric (void) initgroups(DefUser, DefGid); 92354967Seric (void) setuid(DefUid); 92454967Seric } 92554967Seric else 92654967Seric { 92754967Seric (void) setgid(ctladdr->q_gid); 92854967Seric (void) initgroups(ctladdr->q_ruser? 92954967Seric ctladdr->q_ruser: ctladdr->q_user, 93054967Seric ctladdr->q_gid); 93154967Seric (void) setuid(ctladdr->q_uid); 93254967Seric } 9334415Seric } 9349370Seric 93554967Seric /* arrange for all the files to be closed */ 93654967Seric for (i = 3; i < DtableSize; i++) 93754967Seric { 93854967Seric register int j; 93954967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 94054967Seric (void)fcntl(i, F_SETFD, j|1); 94154967Seric } 9422774Seric 94354967Seric /* try to execute the mailer */ 94457529Seric env[0] = "AGENT=sendmail"; 94557529Seric env[1] = NULL; 94657529Seric execve(m->m_mailer, pvp, env); 94756678Seric saveerrno = errno; 94854967Seric syserr("Cannot exec %s", m->m_mailer); 94954967Seric if (m == LocalMailer) 95054967Seric _exit(EX_TEMPFAIL); 95156678Seric switch (saveerrno) 95254967Seric { 95354967Seric case EIO: 95454967Seric case EAGAIN: 95554967Seric case ENOMEM: 95651835Seric # ifdef EPROCLIM 95754967Seric case EPROCLIM: 95851835Seric # endif 95954967Seric _exit(EX_TEMPFAIL); 96054967Seric } 96154967Seric _exit(EX_UNAVAILABLE); 96251835Seric } 96354967Seric 96454967Seric /* 96554967Seric ** Set up return value. 96654967Seric */ 96754967Seric 96854967Seric mci = (MCI *) xalloc(sizeof *mci); 96954993Seric bzero((char *) mci, sizeof *mci); 97054967Seric mci->mci_mailer = m; 97154967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 97254993Seric mci->mci_pid = pid; 97354967Seric (void) close(mpvect[0]); 97454967Seric mci->mci_out = fdopen(mpvect[1], "w"); 97554967Seric if (clever) 97654967Seric { 97754967Seric (void) close(rpvect[1]); 97854967Seric mci->mci_in = fdopen(rpvect[0], "r"); 97954967Seric } 98054967Seric else 98154967Seric { 98254967Seric mci->mci_flags |= MCIF_TEMP; 98354967Seric mci->mci_in = NULL; 98454967Seric } 985294Seric } 986294Seric 9874709Seric /* 98854967Seric ** If we are in SMTP opening state, send initial protocol. 9894709Seric */ 9904709Seric 99154967Seric if (clever && mci->mci_state != MCIS_CLOSED) 9924863Seric { 99354967Seric smtpinit(m, mci, e); 99453738Seric } 99557387Seric if (tTd(11, 1)) 99657387Seric { 99757387Seric printf("openmailer: "); 99857387Seric mci_dump(mci); 99957387Seric } 1000294Seric 100153738Seric return mci; 1002294Seric } 1003294Seric /* 1004294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1005294Seric ** 1006294Seric ** Parameters: 1007294Seric ** stat -- the status code from the mailer (high byte 1008294Seric ** only; core dumps must have been taken care of 1009294Seric ** already). 1010294Seric ** m -- the mailer descriptor for this mailer. 1011294Seric ** 1012294Seric ** Returns: 10134082Seric ** none. 1014294Seric ** 1015294Seric ** Side Effects: 10161518Seric ** Errors may be incremented. 1017294Seric ** ExitStat may be set. 1018294Seric */ 1019294Seric 102010105Seric giveresponse(stat, m, e) 1021294Seric int stat; 10229370Seric register MAILER *m; 102310105Seric ENVELOPE *e; 1024294Seric { 1025294Seric register char *statmsg; 1026294Seric extern char *SysExMsg[]; 1027294Seric register int i; 102836788Sbostic extern int N_SysEx; 102936788Sbostic #ifdef NAMED_BIND 103036788Sbostic extern int h_errno; 103136788Sbostic #endif 103210105Seric char buf[MAXLINE]; 1033294Seric 103412135Seric #ifdef lint 103512135Seric if (m == NULL) 103612135Seric return; 103712135Seric #endif lint 103812135Seric 10394315Seric /* 10404315Seric ** Compute status message from code. 10414315Seric */ 10424315Seric 1043294Seric i = stat - EX__BASE; 10449370Seric if (stat == 0) 10459370Seric statmsg = "250 Sent"; 10469370Seric else if (i < 0 || i > N_SysEx) 10479370Seric { 10489370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 10499370Seric stat = EX_UNAVAILABLE; 10509370Seric statmsg = buf; 10519370Seric } 105210105Seric else if (stat == EX_TEMPFAIL) 105310105Seric { 105410124Seric (void) strcpy(buf, SysExMsg[i]); 105536788Sbostic #ifdef NAMED_BIND 105625527Smiriam if (h_errno == TRY_AGAIN) 105710105Seric { 105815137Seric extern char *errstring(); 105915137Seric 106025527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 106121061Seric } 106221061Seric else 106336788Sbostic #endif 106421061Seric { 106525527Smiriam if (errno != 0) 106625527Smiriam { 106725527Smiriam extern char *errstring(); 106825527Smiriam 106925527Smiriam statmsg = errstring(errno); 107025527Smiriam } 107125527Smiriam else 107225527Smiriam { 107321061Seric #ifdef SMTP 107425527Smiriam extern char SmtpError[]; 107521061Seric 107625527Smiriam statmsg = SmtpError; 107756795Seric #else /* SMTP */ 107825527Smiriam statmsg = NULL; 107956795Seric #endif /* SMTP */ 108025527Smiriam } 108121061Seric } 108221061Seric if (statmsg != NULL && statmsg[0] != '\0') 108321061Seric { 108410124Seric (void) strcat(buf, ": "); 108521061Seric (void) strcat(buf, statmsg); 108610105Seric } 108710105Seric statmsg = buf; 108810105Seric } 1089294Seric else 109021061Seric { 1091294Seric statmsg = SysExMsg[i]; 109221061Seric } 10939370Seric 10949370Seric /* 10959370Seric ** Print the message as appropriate 10969370Seric */ 10979370Seric 109810105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 10998003Seric message(Arpa_Info, &statmsg[4]); 1100294Seric else 1101294Seric { 11021518Seric Errors++; 11039370Seric usrerr(statmsg); 1104294Seric } 1105294Seric 1106294Seric /* 1107294Seric ** Final cleanup. 1108294Seric ** Log a record of the transaction. Compute the new 1109294Seric ** ExitStat -- if we already had an error, stick with 1110294Seric ** that. 1111294Seric */ 1112294Seric 11137680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 111454967Seric logdelivery(&statmsg[4], e); 11157858Seric 11164621Seric if (stat != EX_TEMPFAIL) 11174621Seric setstat(stat); 111810105Seric if (stat != EX_OK) 111910105Seric { 112010105Seric if (e->e_message != NULL) 112110105Seric free(e->e_message); 112210105Seric e->e_message = newstr(&statmsg[4]); 112310105Seric } 112410124Seric errno = 0; 112536788Sbostic #ifdef NAMED_BIND 112625527Smiriam h_errno = 0; 112736788Sbostic #endif 1128294Seric } 1129294Seric /* 11308496Seric ** LOGDELIVERY -- log the delivery in the system log 11318496Seric ** 11328496Seric ** Parameters: 11338496Seric ** stat -- the message to print for the status 11348496Seric ** 11358496Seric ** Returns: 11368496Seric ** none 11378496Seric ** 11388496Seric ** Side Effects: 11398496Seric ** none 11408496Seric */ 11418496Seric 114254967Seric logdelivery(stat, e) 11438496Seric char *stat; 114454967Seric register ENVELOPE *e; 11458496Seric { 11468496Seric extern char *pintvl(); 11478496Seric 11488496Seric # ifdef LOG 114954967Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", e->e_id, 115054967Seric e->e_to, pintvl(curtime() - e->e_ctime, TRUE), stat); 115156795Seric # endif /* LOG */ 11528496Seric } 11538496Seric /* 11546974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1155294Seric ** 11566974Seric ** This can be made an arbitrary message separator by changing $l 1157294Seric ** 115816150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 115916150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 116016150Seric ** does a well-meaning programmer such as myself have to deal with 116116150Seric ** this kind of antique garbage???? 11626974Seric ** 1163294Seric ** Parameters: 11646974Seric ** fp -- the file to output to. 11656974Seric ** m -- the mailer describing this entry. 1166294Seric ** 1167294Seric ** Returns: 11686974Seric ** none 1169294Seric ** 1170294Seric ** Side Effects: 11716974Seric ** outputs some text to fp. 1172294Seric */ 1173294Seric 117454967Seric putfromline(fp, m, e) 11756974Seric register FILE *fp; 11766974Seric register MAILER *m; 117754967Seric ENVELOPE *e; 1178294Seric { 117916150Seric char *template = "\001l\n"; 11806974Seric char buf[MAXLINE]; 1181294Seric 118210682Seric if (bitnset(M_NHDR, m->m_flags)) 11836974Seric return; 11844315Seric 11856974Seric # ifdef UGLYUUCP 118610682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 11874205Seric { 118812223Seric char *bang; 118912223Seric char xbuf[MAXLINE]; 11906041Seric 119154967Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 119256795Seric bang = strchr(buf, '!'); 11936974Seric if (bang == NULL) 119412223Seric syserr("No ! in UUCP! (%s)", buf); 11955099Seric else 11969370Seric { 119712223Seric *bang++ = '\0'; 119816150Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 119912223Seric template = xbuf; 12009370Seric } 12016974Seric } 120256795Seric # endif /* UGLYUUCP */ 120354967Seric expand(template, buf, &buf[sizeof buf - 1], e); 120410168Seric putline(buf, fp, m); 12055981Seric } 12065981Seric /* 12076974Seric ** PUTBODY -- put the body of a message. 12086974Seric ** 12096974Seric ** Parameters: 12106974Seric ** fp -- file to output onto. 121110168Seric ** m -- a mailer descriptor to control output format. 12129538Seric ** e -- the envelope to put out. 12136974Seric ** 12146974Seric ** Returns: 12156974Seric ** none. 12166974Seric ** 12176974Seric ** Side Effects: 12186974Seric ** The message is written onto fp. 12196974Seric */ 12206974Seric 122110168Seric putbody(fp, m, e) 12226974Seric FILE *fp; 12239370Seric MAILER *m; 12249538Seric register ENVELOPE *e; 12256974Seric { 122610168Seric char buf[MAXLINE]; 12276974Seric 12286974Seric /* 12296974Seric ** Output the body of the message 12306974Seric */ 12316974Seric 12329538Seric if (e->e_dfp == NULL) 12336974Seric { 12349538Seric if (e->e_df != NULL) 12359538Seric { 12369538Seric e->e_dfp = fopen(e->e_df, "r"); 12379538Seric if (e->e_dfp == NULL) 123840931Srick syserr("putbody: Cannot open %s for %s from %s", 123940931Srick e->e_df, e->e_to, e->e_from); 12409538Seric } 12419538Seric else 124210168Seric putline("<<< No Message Collected >>>", fp, m); 12439538Seric } 12449538Seric if (e->e_dfp != NULL) 12459538Seric { 12469538Seric rewind(e->e_dfp); 124710168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 124816875Seric { 124916875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 125040995Sbostic strncmp(buf, "From ", 5) == 0) 125123102Seric (void) putc('>', fp); 125210168Seric putline(buf, fp, m); 125316875Seric } 12546974Seric 12559538Seric if (ferror(e->e_dfp)) 12566974Seric { 12576974Seric syserr("putbody: read error"); 12586974Seric ExitStat = EX_IOERR; 12596974Seric } 12606974Seric } 12616974Seric 12626974Seric (void) fflush(fp); 12636974Seric if (ferror(fp) && errno != EPIPE) 12646974Seric { 12656974Seric syserr("putbody: write error"); 12666974Seric ExitStat = EX_IOERR; 12676974Seric } 12686974Seric errno = 0; 12696974Seric } 12706974Seric /* 1271294Seric ** MAILFILE -- Send a message to a file. 1272294Seric ** 12734327Seric ** If the file has the setuid/setgid bits set, but NO execute 12744327Seric ** bits, sendmail will try to become the owner of that file 12754327Seric ** rather than the real user. Obviously, this only works if 12764327Seric ** sendmail runs as root. 12774327Seric ** 12789370Seric ** This could be done as a subordinate mailer, except that it 12799370Seric ** is used implicitly to save messages in ~/dead.letter. We 12809370Seric ** view this as being sufficiently important as to include it 12819370Seric ** here. For example, if the system is dying, we shouldn't have 12829370Seric ** to create another process plus some pipes to save the message. 12839370Seric ** 1284294Seric ** Parameters: 1285294Seric ** filename -- the name of the file to send to. 12864397Seric ** ctladdr -- the controlling address header -- includes 12874397Seric ** the userid/groupid to be when sending. 1288294Seric ** 1289294Seric ** Returns: 1290294Seric ** The exit code associated with the operation. 1291294Seric ** 1292294Seric ** Side Effects: 1293294Seric ** none. 1294294Seric */ 1295294Seric 129654967Seric mailfile(filename, ctladdr, e) 1297294Seric char *filename; 12984397Seric ADDRESS *ctladdr; 129954967Seric register ENVELOPE *e; 1300294Seric { 1301294Seric register FILE *f; 13024214Seric register int pid; 130353751Seric int mode; 1304294Seric 13054214Seric /* 13064214Seric ** Fork so we can change permissions here. 13074214Seric ** Note that we MUST use fork, not vfork, because of 13084214Seric ** the complications of calling subroutines, etc. 13094214Seric */ 13104067Seric 13114214Seric DOFORK(fork); 13124214Seric 13134214Seric if (pid < 0) 13144214Seric return (EX_OSERR); 13154214Seric else if (pid == 0) 13164214Seric { 13174214Seric /* child -- actually write to file */ 13184327Seric struct stat stb; 13194327Seric 13204215Seric (void) signal(SIGINT, SIG_DFL); 13214215Seric (void) signal(SIGHUP, SIG_DFL); 13224215Seric (void) signal(SIGTERM, SIG_DFL); 132323102Seric (void) umask(OldUmask); 132452673Seric 13254327Seric if (stat(filename, &stb) < 0) 13264431Seric stb.st_mode = 0666; 132753751Seric mode = stb.st_mode; 132852673Seric 132952673Seric /* limit the errors to those actually caused in the child */ 133052673Seric errno = 0; 133152673Seric ExitStat = EX_OK; 133252673Seric 13334327Seric if (bitset(0111, stb.st_mode)) 13344327Seric exit(EX_CANTCREAT); 13354401Seric if (ctladdr == NULL) 133640931Srick ctladdr = &e->e_from; 133753751Seric else 133853751Seric { 133953751Seric /* ignore setuid and setgid bits */ 134053751Seric mode &= ~(S_ISGID|S_ISUID); 134153751Seric } 134253751Seric 134340931Srick /* we have to open the dfile BEFORE setuid */ 134453751Seric if (e->e_dfp == NULL && e->e_df != NULL) 134540931Srick { 134640931Srick e->e_dfp = fopen(e->e_df, "r"); 134752673Seric if (e->e_dfp == NULL) 134852673Seric { 134940931Srick syserr("mailfile: Cannot open %s for %s from %s", 135053751Seric e->e_df, e->e_to, e->e_from); 135140931Srick } 135240931Srick } 135340931Srick 135453751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 13554417Seric { 135652673Seric if (ctladdr->q_uid == 0) 135752673Seric { 13584417Seric (void) setgid(DefGid); 135940972Sbostic (void) initgroups(DefUser, DefGid); 136052673Seric } 136152673Seric else 136252673Seric { 13634417Seric (void) setgid(ctladdr->q_gid); 136453751Seric (void) initgroups(ctladdr->q_ruser ? 136553751Seric ctladdr->q_ruser : ctladdr->q_user, 136640972Sbostic ctladdr->q_gid); 136740972Sbostic } 13684417Seric } 136953751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 13704417Seric { 13714417Seric if (ctladdr->q_uid == 0) 13724417Seric (void) setuid(DefUid); 13734417Seric else 13744417Seric (void) setuid(ctladdr->q_uid); 13754417Seric } 137652673Seric FileName = filename; 137752673Seric LineNumber = 0; 13786887Seric f = dfopen(filename, "a"); 13794214Seric if (f == NULL) 138052673Seric { 138152673Seric message("cannot open"); 13824214Seric exit(EX_CANTCREAT); 138352673Seric } 13844214Seric 138554967Seric putfromline(f, ProgMailer, e); 138655012Seric (*e->e_puthdr)(f, ProgMailer, e); 138710168Seric putline("\n", f, ProgMailer); 138855012Seric (*e->e_putbody)(f, ProgMailer, e); 138910168Seric putline("\n", f, ProgMailer); 139052673Seric if (ferror(f)) 139152673Seric { 139252673Seric message("I/O error"); 139352673Seric setstat(EX_IOERR); 139452673Seric } 13954214Seric (void) fclose(f); 13964214Seric (void) fflush(stdout); 13974417Seric 13986887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13994621Seric (void) chmod(filename, (int) stb.st_mode); 140052673Seric exit(ExitStat); 14014315Seric /*NOTREACHED*/ 14024214Seric } 14034214Seric else 14044214Seric { 14054214Seric /* parent -- wait for exit status */ 14069370Seric int st; 14074214Seric 14089370Seric st = waitfor(pid); 14099370Seric if ((st & 0377) != 0) 14109370Seric return (EX_UNAVAILABLE); 14119370Seric else 14129370Seric return ((st >> 8) & 0377); 141340931Srick /*NOTREACHED*/ 14144214Seric } 1415294Seric } 14164550Seric /* 14174550Seric ** SENDALL -- actually send all the messages. 14184550Seric ** 14194550Seric ** Parameters: 14207043Seric ** e -- the envelope to send. 142114874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 142214874Seric ** the current SendMode. 14234550Seric ** 14244550Seric ** Returns: 14254550Seric ** none. 14264550Seric ** 14274550Seric ** Side Effects: 14284550Seric ** Scans the send lists and sends everything it finds. 14297043Seric ** Delivers any appropriate error messages. 14309275Seric ** If we are running in a non-interactive mode, takes the 14319275Seric ** appropriate action. 14324550Seric */ 14334550Seric 14349275Seric sendall(e, mode) 14357043Seric ENVELOPE *e; 14369275Seric char mode; 14374550Seric { 14385008Seric register ADDRESS *q; 14397779Seric bool oldverbose; 14409275Seric int pid; 144151937Seric # ifdef LOCKF 144251937Seric struct flock lfd; 144351937Seric # endif 14444550Seric 144514874Seric /* determine actual delivery mode */ 144614874Seric if (mode == SM_DEFAULT) 144714874Seric { 144824941Seric extern bool shouldqueue(); 144914874Seric 145057438Seric if (shouldqueue(e->e_msgpriority, e->e_ctime)) 145114874Seric mode = SM_QUEUE; 145214874Seric else 145314874Seric mode = SendMode; 145414874Seric } 145514874Seric 14568248Seric if (tTd(13, 1)) 14575032Seric { 14589275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 14597043Seric printaddr(e->e_sendqueue, TRUE); 14605032Seric } 14615008Seric 14627043Seric /* 14639275Seric ** Do any preprocessing necessary for the mode we are running. 14649370Seric ** Check to make sure the hop count is reasonable. 14659370Seric ** Delete sends to the sender in mailing lists. 14667043Seric */ 14677043Seric 14689370Seric CurEnv = e; 14699370Seric 147051305Seric if (e->e_hopcount > MaxHopCount) 14719275Seric { 147240931Srick errno = 0; 147340931Srick syserr("sendall: too many hops %d (%d max): from %s, to %s", 147457589Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 147557589Seric e->e_sendqueue->q_paddr); 14769370Seric return; 14779370Seric } 14789275Seric 14799370Seric if (!MeToo) 14809370Seric { 148112611Seric extern ADDRESS *recipient(); 148212611Seric 14839370Seric e->e_from.q_flags |= QDONTSEND; 1484*57731Seric if (tTd(13, 5)) 1485*57731Seric { 1486*57731Seric printf("sendall: QDONTSEND "); 1487*57731Seric printaddr(&e->e_from, FALSE); 1488*57731Seric } 148955012Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 14909275Seric } 14919370Seric 14929370Seric # ifdef QUEUE 14939335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 14949335Seric (mode != SM_VERIFY && SuperSafe)) && 14959335Seric !bitset(EF_INQUEUE, e->e_flags)) 149651920Seric queueup(e, TRUE, mode == SM_QUEUE); 149756795Seric #endif /* QUEUE */ 14989275Seric 14997779Seric oldverbose = Verbose; 15009275Seric switch (mode) 15019275Seric { 15029275Seric case SM_VERIFY: 15037779Seric Verbose = TRUE; 15049275Seric break; 15059275Seric 15069275Seric case SM_QUEUE: 150751916Seric queueonly: 15089335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 15099275Seric return; 15109275Seric 15119275Seric case SM_FORK: 15129538Seric if (e->e_xfp != NULL) 15139538Seric (void) fflush(e->e_xfp); 151451916Seric 151551916Seric # ifdef LOCKF 151651916Seric /* 151751916Seric ** Since lockf has the interesting semantic that the 151851937Seric ** lock is lost when we fork, we have to risk losing 151951937Seric ** the lock here by closing before the fork, and then 152051937Seric ** trying to get it back in the child. 152151916Seric */ 152251916Seric 152351920Seric if (e->e_lockfp != NULL) 152451916Seric { 152551920Seric (void) fclose(e->e_lockfp); 152651920Seric e->e_lockfp = NULL; 152751916Seric } 152851916Seric # endif /* LOCKF */ 152951916Seric 15309275Seric pid = fork(); 15319275Seric if (pid < 0) 15329275Seric { 153351916Seric goto queueonly; 15349275Seric } 15359275Seric else if (pid > 0) 15369293Seric { 15379293Seric /* be sure we leave the temp files to our child */ 15389335Seric e->e_id = e->e_df = NULL; 153951916Seric # ifndef LOCKF 154051920Seric if (e->e_lockfp != NULL) 1541*57731Seric { 154251920Seric (void) fclose(e->e_lockfp); 1543*57731Seric e->e_lockfp = NULL; 1544*57731Seric } 154551916Seric # endif 1546*57731Seric 1547*57731Seric /* close any random open files in the envelope */ 1548*57731Seric if (e->e_dfp != NULL) 1549*57731Seric { 1550*57731Seric (void) fclose(e->e_dfp); 1551*57731Seric e->e_dfp = NULL; 1552*57731Seric } 1553*57731Seric if (e->e_xfp != NULL) 1554*57731Seric { 1555*57731Seric (void) fclose(e->e_xfp); 1556*57731Seric e->e_xfp = NULL; 1557*57731Seric } 15589275Seric return; 15599293Seric } 15609275Seric 15619275Seric /* double fork to avoid zombies */ 15629275Seric if (fork() > 0) 15639275Seric exit(EX_OK); 15649275Seric 15659293Seric /* be sure we are immune from the terminal */ 156610133Seric disconnect(FALSE); 15679293Seric 156851911Seric # ifdef LOCKF 156951911Seric /* 157051916Seric ** Now try to get our lock back. 157151911Seric */ 157251911Seric 157351937Seric lfd.l_type = F_WRLCK; 157451937Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 157551920Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 157651920Seric if (e->e_lockfp == NULL || 157751937Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 157851911Seric { 157951916Seric /* oops.... lost it */ 158051911Seric # ifdef LOG 158151916Seric if (LogLevel > 5) 158251916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 158354967Seric e->e_id); 158451911Seric # endif /* LOG */ 158551916Seric exit(EX_OK); 158651911Seric } 158751911Seric # endif /* LOCKF */ 158851911Seric 15899275Seric break; 15909275Seric } 15919275Seric 15929275Seric /* 15939275Seric ** Run through the list and send everything. 15949275Seric */ 15959275Seric 159657589Seric e->e_nsent = 0; 15977043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15984550Seric { 15999275Seric if (mode == SM_VERIFY) 16004550Seric { 16019293Seric e->e_to = q->q_paddr; 16025008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 16037052Seric message(Arpa_Info, "deliverable"); 16044550Seric } 160547284Seric else if (!bitset(QDONTSEND, q->q_flags)) 160647284Seric { 160750533Seric # ifdef QUEUE 160847284Seric /* 160947284Seric ** Checkpoint the send list every few addresses 161047284Seric */ 161147284Seric 161257589Seric if (e->e_nsent >= CheckpointInterval) 161347284Seric { 161451920Seric queueup(e, TRUE, FALSE); 161557589Seric e->e_nsent = 0; 161647284Seric } 161750533Seric # endif /* QUEUE */ 161857589Seric (void) deliver(e, q); 161947284Seric } 16204550Seric } 16217779Seric Verbose = oldverbose; 16227043Seric 16237043Seric /* 16247043Seric ** Now run through and check for errors. 16257043Seric */ 16267043Seric 162751920Seric if (mode == SM_VERIFY) 16287043Seric return; 16297043Seric 16307043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16317043Seric { 16327043Seric register ADDRESS *qq; 16337043Seric 16348248Seric if (tTd(13, 3)) 16358248Seric { 16368248Seric printf("Checking "); 16378248Seric printaddr(q, FALSE); 16388248Seric } 16398248Seric 16409335Seric /* only send errors if the message failed */ 16419335Seric if (!bitset(QBADADDR, q->q_flags)) 16429335Seric continue; 16437043Seric 16447043Seric /* we have an address that failed -- find the parent */ 16457043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 16467043Seric { 16477043Seric char obuf[MAXNAME + 6]; 16487043Seric extern char *aliaslookup(); 16497043Seric 16507043Seric /* we can only have owners for local addresses */ 165110682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 16527043Seric continue; 16537043Seric 16547043Seric /* see if the owner list exists */ 16557043Seric (void) strcpy(obuf, "owner-"); 16567047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 16577047Seric (void) strcat(obuf, "owner"); 16587047Seric else 16597047Seric (void) strcat(obuf, qq->q_user); 166057438Seric if (!bitnset(M_USR_UPPER, qq->q_mailer->m_flags)) 166157438Seric makelower(obuf); 16627043Seric if (aliaslookup(obuf) == NULL) 16637043Seric continue; 16647043Seric 16658248Seric if (tTd(13, 4)) 16668248Seric printf("Errors to %s\n", obuf); 16678248Seric 16687043Seric /* owner list exists -- add it to the error queue */ 166955012Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue, e); 167057438Seric 167157438Seric /* and set the return path to point to it */ 167257438Seric e->e_returnpath = newstr(obuf); 167357438Seric 167416883Seric ErrorMode = EM_MAIL; 16757043Seric break; 16767043Seric } 16777043Seric 16787043Seric /* if we did not find an owner, send to the sender */ 16798426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 168055012Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue, e); 16817043Seric } 16829275Seric 16839275Seric if (mode == SM_FORK) 16849275Seric finis(); 16854550Seric } 168657454Seric /* 168757454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 168857454Seric ** 168957454Seric ** The signature describes how we are going to send this -- it 169057454Seric ** can be just the hostname (for non-Internet hosts) or can be 169157454Seric ** an ordered list of MX hosts. 169257454Seric ** 169357454Seric ** Parameters: 169457454Seric ** m -- the mailer describing this host. 169557454Seric ** host -- the host name. 169657454Seric ** e -- the current envelope. 169757454Seric ** 169857454Seric ** Returns: 169957454Seric ** The signature for this host. 170057454Seric ** 170157454Seric ** Side Effects: 170257454Seric ** Can tweak the symbol table. 170357454Seric */ 170457454Seric 170557454Seric char * 170657454Seric hostsignature(m, host, e) 170757454Seric register MAILER *m; 170857454Seric char *host; 170957454Seric ENVELOPE *e; 171057454Seric { 171157454Seric register char *p; 171257454Seric register STAB *s; 171357454Seric int i; 171457454Seric int len; 171557454Seric #ifdef NAMED_BIND 171657454Seric int nmx; 171757454Seric auto int rcode; 171857454Seric char *mxhosts[MAXMXHOSTS + 1]; 171957454Seric static char myhostbuf[MAXNAME]; 172057454Seric #endif 172157454Seric 172257454Seric /* 172357454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 172457454Seric */ 172557454Seric 172657454Seric p = m->m_mailer; 172757454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 172857454Seric { 172957454Seric /* just an ordinary mailer */ 173057454Seric return host; 173157454Seric } 173257454Seric 173357454Seric /* 173457454Seric ** If it is a numeric address, just return it. 173557454Seric */ 173657454Seric 173757454Seric if (host[0] == '[') 173857454Seric return host; 173957454Seric 174057454Seric /* 174157454Seric ** Look it up in the symbol table. 174257454Seric */ 174357454Seric 174457454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 174557454Seric if (s->s_hostsig != NULL) 174657454Seric return s->s_hostsig; 174757454Seric 174857454Seric /* 174957454Seric ** Not already there -- create a signature. 175057454Seric */ 175157454Seric 175257454Seric #ifdef NAMED_BIND 175357454Seric if (myhostbuf[0] == '\0') 175457454Seric expand("\001j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e); 175557454Seric 175657454Seric nmx = getmxrr(host, mxhosts, myhostbuf, &rcode); 175757454Seric if (nmx <= 0) 175857454Seric { 175957454Seric register MCI *mci; 176057454Seric extern int errno; 176157454Seric extern MCI *mci_get(); 176257454Seric 176357454Seric /* update the connection info for this host */ 176457454Seric mci = mci_get(host, m); 176557454Seric mci->mci_exitstat = rcode; 176657454Seric mci->mci_errno = errno; 176757454Seric 176857454Seric /* and return the original host name as the signature */ 176957454Seric s->s_hostsig = host; 177057454Seric return host; 177157454Seric } 177257454Seric 177357454Seric len = 0; 177457454Seric for (i = 0; i < nmx; i++) 177557454Seric { 177657454Seric len += strlen(mxhosts[i]) + 1; 177757454Seric } 177857454Seric s->s_hostsig = p = xalloc(len); 177957454Seric for (i = 0; i < nmx; i++) 178057454Seric { 178157454Seric if (i != 0) 178257454Seric *p++ = ':'; 178357454Seric strcpy(p, mxhosts[i]); 178457454Seric p += strlen(p); 178557454Seric } 178657454Seric makelower(s->s_hostsig); 178757454Seric #else 178857454Seric /* not using BIND -- the signature is just the host name */ 178957454Seric s->s_hostsig = host; 179057454Seric #endif 179157454Seric if (tTd(17, 1)) 179257454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 179357454Seric return s->s_hostsig; 179457454Seric } 1795