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*58146Seric static char sccsid[] = "@(#)deliver.c 6.22 (Berkeley) 02/22/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"); 11458020Seric if (LogLevel > 8) 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 */ 13358020Seric (void) strcpy(rpathbuf, remotename(e->e_returnpath, m, TRUE, FALSE, 13458020Seric TRUE, e)); 13551951Seric if (e->e_returnpath == e->e_sender) 13651951Seric { 13751951Seric from = rpathbuf; 13851951Seric } 13951951Seric else 14051951Seric { 14158020Seric (void) strcpy(tfrombuf, remotename(e->e_sender, m, TRUE, FALSE, 14258020Seric TRUE, e)); 14351951Seric from = tfrombuf; 14451951Seric } 1454452Seric 14651951Seric define('f', e->e_returnpath, e); /* raw return path */ 14751951Seric define('<', rpathbuf, e); /* translated return path */ 14851951Seric define('g', from, e); /* translated sender */ 1499370Seric define('h', host, e); /* to host */ 1503233Seric Errors = 0; 1513233Seric pvp = pv; 1523233Seric *pvp++ = m->m_argv[0]; 1532968Seric 1543233Seric /* insert -f or -r flag as appropriate */ 15510682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1563233Seric { 15710682Seric if (bitnset(M_FOPT, m->m_flags)) 1583233Seric *pvp++ = "-f"; 1593233Seric else 1603233Seric *pvp++ = "-r"; 16151951Seric *pvp++ = newstr(rpathbuf); 1623233Seric } 163294Seric 164294Seric /* 1653233Seric ** Append the other fixed parts of the argv. These run 1663233Seric ** up to the first entry containing "$u". There can only 1673233Seric ** be one of these, and there are only a few more slots 1683233Seric ** in the pv after it. 169294Seric */ 170294Seric 1713233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 172294Seric { 17358050Seric /* can't use strchr here because of sign extension problems */ 17458050Seric while (*p != '\0') 17558050Seric { 17658050Seric if ((*p++ & 0377) == MACROEXPAND) 17758050Seric { 17858050Seric if (*p == 'u') 17958050Seric break; 18058050Seric } 18158050Seric } 18258050Seric 18358050Seric if (*p != '\0') 1843233Seric break; 1853233Seric 1863233Seric /* this entry is safe -- go ahead and process it */ 1879370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1883233Seric *pvp++ = newstr(buf); 1893233Seric if (pvp >= &pv[MAXPV - 3]) 1903233Seric { 1913233Seric syserr("Too many parameters to %s before $u", pv[0]); 1923233Seric return (-1); 1933233Seric } 194294Seric } 1954863Seric 1966038Seric /* 1976038Seric ** If we have no substitution for the user name in the argument 1986038Seric ** list, we know that we must supply the names otherwise -- and 1996038Seric ** SMTP is the answer!! 2006038Seric */ 2016038Seric 2023233Seric if (*mvp == NULL) 2034863Seric { 2044863Seric /* running SMTP */ 2055179Seric # ifdef SMTP 2064863Seric clever = TRUE; 2074863Seric *pvp = NULL; 20856795Seric # else /* SMTP */ 2096038Seric /* oops! we don't implement SMTP */ 2105179Seric syserr("SMTP style mailer"); 2115179Seric return (EX_SOFTWARE); 21256795Seric # endif /* SMTP */ 2134863Seric } 214294Seric 215294Seric /* 2163233Seric ** At this point *mvp points to the argument with $u. We 2173233Seric ** run through our address list and append all the addresses 2183233Seric ** we can. If we run out of space, do not fret! We can 2193233Seric ** always send another copy later. 220294Seric */ 221294Seric 2223233Seric tobuf[0] = '\0'; 2239370Seric e->e_to = tobuf; 2244397Seric ctladdr = NULL; 22557454Seric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 2263233Seric for (; to != NULL; to = to->q_next) 227294Seric { 2283233Seric /* avoid sending multiple recipients to dumb mailers */ 22910682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 2303233Seric break; 2313233Seric 2323233Seric /* if already sent or not for this host, don't send */ 2337052Seric if (bitset(QDONTSEND, to->q_flags) || 23457454Seric to->q_mailer != firstto->q_mailer || 23557454Seric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 2363233Seric continue; 2374397Seric 2388225Seric /* avoid overflowing tobuf */ 23942462Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 2408225Seric break; 2418225Seric 2427672Seric if (tTd(10, 1)) 2435032Seric { 2445032Seric printf("\nsend to "); 2455032Seric printaddr(to, FALSE); 2465032Seric } 2475032Seric 2484397Seric /* compute effective uid/gid when sending */ 2494596Seric if (to->q_mailer == ProgMailer) 2504397Seric ctladdr = getctladdr(to); 2514397Seric 2523233Seric user = to->q_user; 2539370Seric e->e_to = to->q_paddr; 2543233Seric to->q_flags |= QDONTSEND; 25557731Seric if (tTd(10, 5)) 25657731Seric { 25757731Seric printf("deliver: QDONTSEND "); 25857731Seric printaddr(to, FALSE); 25957731Seric } 2603233Seric 2613233Seric /* 2623233Seric ** Check to see that these people are allowed to 2633233Seric ** talk to each other. 2643233Seric */ 2653233Seric 26610699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 26710699Seric { 26829914Seric NoReturn = TRUE; 26910699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 27010699Seric giveresponse(EX_UNAVAILABLE, m, e); 27110699Seric continue; 27210699Seric } 27357441Seric rcode = checkcompat(to, e); 27457459Seric if (rcode != EX_OK) 275294Seric { 27657459Seric giveresponse(rcode, m, e); 2773233Seric continue; 278294Seric } 2793233Seric 2803233Seric /* 2814099Seric ** Strip quote bits from names if the mailer is dumb 2824099Seric ** about them. 2833233Seric */ 2843233Seric 28510682Seric if (bitnset(M_STRIPQ, m->m_flags)) 286294Seric { 28754983Seric stripquotes(user); 28854983Seric stripquotes(host); 2893233Seric } 2903233Seric 2919206Seric /* hack attack -- delivermail compatibility */ 2929206Seric if (m == ProgMailer && *user == '|') 2939206Seric user++; 2949206Seric 2953233Seric /* 2964161Seric ** If an error message has already been given, don't 2974161Seric ** bother to send to this address. 2984161Seric ** 2994161Seric ** >>>>>>>>>> This clause assumes that the local mailer 3004161Seric ** >> NOTE >> cannot do any further aliasing; that 3014161Seric ** >>>>>>>>>> function is subsumed by sendmail. 3024161Seric */ 3034161Seric 3047293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 3054161Seric continue; 3064161Seric 3074283Seric /* save statistics.... */ 3089370Seric markstats(e, to); 3094283Seric 3104161Seric /* 3113233Seric ** See if this user name is "special". 3123233Seric ** If the user name has a slash in it, assume that this 3136974Seric ** is a file -- send it off without further ado. Note 3146974Seric ** that this type of addresses is not processed along 3156974Seric ** with the others, so we fudge on the To person. 3163233Seric */ 3173233Seric 31857402Seric if (m == FileMailer) 3193233Seric { 32057402Seric rcode = mailfile(user, getctladdr(to), e); 32157402Seric giveresponse(rcode, m, e); 32257402Seric if (rcode == EX_OK) 32357402Seric to->q_flags |= QSENT; 32457402Seric continue; 325294Seric } 3263233Seric 3274315Seric /* 3284315Seric ** Address is verified -- add this user to mailer 3294315Seric ** argv, and add it to the print list of recipients. 3304315Seric */ 3314315Seric 3326059Seric /* link together the chain of recipients */ 3336272Seric to->q_tchain = tochain; 3346272Seric tochain = to; 3356059Seric 3363233Seric /* create list of users for error messages */ 3379388Seric (void) strcat(tobuf, ","); 3384082Seric (void) strcat(tobuf, to->q_paddr); 3399370Seric define('u', user, e); /* to user */ 3409370Seric define('z', to->q_home, e); /* user's home */ 3413233Seric 3424863Seric /* 3436059Seric ** Expand out this user into argument list. 3444863Seric */ 3454863Seric 3466059Seric if (!clever) 3473233Seric { 3489370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3494863Seric *pvp++ = newstr(buf); 3504863Seric if (pvp >= &pv[MAXPV - 2]) 3514863Seric { 3524863Seric /* allow some space for trailing parms */ 3534863Seric break; 3544863Seric } 3554863Seric } 356294Seric } 357294Seric 3584067Seric /* see if any addresses still exist */ 3594067Seric if (tobuf[0] == '\0') 3604863Seric { 3619370Seric define('g', (char *) NULL, e); 36251951Seric define('<', (char *) NULL, e); 3634067Seric return (0); 3644863Seric } 3654067Seric 3663233Seric /* print out messages as full list */ 3679388Seric e->e_to = tobuf + 1; 3683233Seric 369294Seric /* 3703233Seric ** Fill out any parameters after the $u parameter. 371294Seric */ 372294Seric 3734863Seric while (!clever && *++mvp != NULL) 374294Seric { 3759370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3763233Seric *pvp++ = newstr(buf); 3773233Seric if (pvp >= &pv[MAXPV]) 3783233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 379294Seric } 3803233Seric *pvp++ = NULL; 381294Seric 382294Seric /* 383294Seric ** Call the mailer. 3842898Seric ** The argument vector gets built, pipes 385294Seric ** are created as necessary, and we fork & exec as 3862898Seric ** appropriate. 3874863Seric ** If we are running SMTP, we just need to clean up. 388294Seric */ 389294Seric 39041050Seric if (ctladdr == NULL) 39141050Seric ctladdr = &e->e_from; 39235651Seric #ifdef NAMED_BIND 39351313Seric if (ConfigLevel < 2) 39451313Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 39535651Seric #endif 39654967Seric mci = openmailer(m, pv, ctladdr, clever, e); 39754967Seric if (mci == NULL) 39854967Seric { 39954967Seric /* catastrophic error */ 40057977Seric rcode = EX_OSERR; 40154967Seric goto give_up; 40254967Seric } 40354967Seric else if (mci->mci_state != MCIS_OPEN) 40454967Seric { 40554967Seric /* couldn't open the mailer */ 40654967Seric rcode = mci->mci_exitstat; 40755173Seric errno = mci->mci_errno; 40854967Seric if (rcode == EX_OK) 40954967Seric { 41054967Seric /* shouldn't happen */ 41157721Seric syserr("deliver: rcode=%d, mci_state=%d, sig=%s", 41257721Seric rcode, mci->mci_state, firstsig); 41354967Seric rcode = EX_SOFTWARE; 41454967Seric } 41554967Seric } 41654967Seric else if (!clever) 41754967Seric { 41854967Seric /* 41954967Seric ** Format and send message. 42054967Seric */ 42154967Seric 42254967Seric putfromline(mci->mci_out, m, e); 42354967Seric (*e->e_puthdr)(mci->mci_out, m, e); 42454967Seric putline("\n", mci->mci_out, m); 42554967Seric (*e->e_putbody)(mci->mci_out, m, e); 42654967Seric 42754967Seric /* get the exit status */ 42854967Seric rcode = endmailer(mci, pv[0]); 42954967Seric } 43054967Seric else 43133931Sbostic #ifdef SMTP 43235651Seric { 43354967Seric /* 43454967Seric ** Send the MAIL FROM: protocol 43554967Seric */ 43653751Seric 43754967Seric rcode = smtpmailfrom(m, mci, e); 43854967Seric if (rcode == EX_OK) 43935651Seric { 44054967Seric register char *t = tobuf; 44154967Seric register int i; 44253751Seric 44354967Seric /* send the recipient list */ 44454967Seric tobuf[0] = '\0'; 44554967Seric for (to = tochain; to != NULL; to = to->q_tchain) 44653738Seric { 44754967Seric e->e_to = to->q_paddr; 44854967Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 44953738Seric { 45054967Seric markfailure(e, to, i); 45154967Seric giveresponse(i, m, e); 4529388Seric } 45353738Seric else 45453738Seric { 45554967Seric *t++ = ','; 45654967Seric for (p = to->q_paddr; *p; *t++ = *p++) 45754967Seric continue; 4589388Seric } 45954967Seric } 4609388Seric 46154967Seric /* now send the data */ 46254967Seric if (tobuf[0] == '\0') 46354967Seric { 46454967Seric e->e_to = NULL; 46554967Seric if (bitset(MCIF_CACHED, mci->mci_flags)) 46654967Seric smtprset(m, mci, e); 46754967Seric } 46854967Seric else 46954967Seric { 47054967Seric e->e_to = tobuf + 1; 47154967Seric rcode = smtpdata(m, mci, e); 47254967Seric } 47354967Seric 47454967Seric /* now close the connection */ 47554967Seric if (!bitset(MCIF_CACHED, mci->mci_flags)) 47653751Seric smtpquit(m, mci, e); 4779370Seric } 4784863Seric } 47954967Seric #else /* not SMTP */ 48033935Sbostic { 48154967Seric syserr("deliver: need SMTP compiled to use clever mailer"); 48257977Seric rcode = EX_CONFIG; 48354967Seric goto give_up; 48433935Sbostic } 48554967Seric #endif /* SMTP */ 48635651Seric #ifdef NAMED_BIND 48751313Seric if (ConfigLevel < 2) 48851313Seric _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 48935651Seric #endif 4903233Seric 49154967Seric /* arrange a return receipt if requested */ 49258139Seric if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) 49354967Seric { 49454967Seric e->e_flags |= EF_SENDRECEIPT; 49554967Seric /* do we want to send back more info? */ 49654967Seric } 49754967Seric 4984621Seric /* 4999388Seric ** Do final status disposal. 5009388Seric ** We check for something in tobuf for the SMTP case. 5019388Seric ** If we got a temporary failure, arrange to queue the 5029388Seric ** addressees. 5034621Seric */ 5044621Seric 50554967Seric give_up: 5069388Seric if (tobuf[0] != '\0') 50710105Seric giveresponse(rcode, m, e); 50847284Seric for (to = tochain; to != NULL; to = to->q_tchain) 50954967Seric { 51047284Seric if (rcode != EX_OK) 51110092Seric markfailure(e, to, rcode); 51247284Seric else 51357589Seric { 51447284Seric to->q_flags |= QSENT; 51557589Seric e->e_nsent++; 51657589Seric } 51754967Seric } 5184621Seric 51954967Seric /* 52054967Seric ** Restore state and return. 52154967Seric */ 52254967Seric 5234488Seric errno = 0; 5249370Seric define('g', (char *) NULL, e); 52551951Seric define('<', (char *) NULL, e); 5268003Seric return (rcode); 5273233Seric } 5283233Seric /* 52910092Seric ** MARKFAILURE -- mark a failure on a specific address. 53010092Seric ** 53110092Seric ** Parameters: 53210092Seric ** e -- the envelope we are sending. 53310092Seric ** q -- the address to mark. 53410092Seric ** rcode -- the code signifying the particular failure. 53510092Seric ** 53610092Seric ** Returns: 53710092Seric ** none. 53810092Seric ** 53910092Seric ** Side Effects: 54010092Seric ** marks the address (and possibly the envelope) with the 54110092Seric ** failure so that an error will be returned or 54210092Seric ** the message will be queued, as appropriate. 54310092Seric */ 54410092Seric 54510092Seric markfailure(e, q, rcode) 54610092Seric register ENVELOPE *e; 54710092Seric register ADDRESS *q; 54810092Seric int rcode; 54910092Seric { 55010092Seric if (rcode == EX_OK) 55110092Seric return; 55240996Sbostic else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) 55310092Seric q->q_flags |= QBADADDR; 55410092Seric else if (curtime() > e->e_ctime + TimeOut) 55510092Seric { 55610092Seric extern char *pintvl(); 55710105Seric char buf[MAXLINE]; 55810092Seric 55910092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 56010105Seric { 56110105Seric (void) sprintf(buf, "Cannot send message for %s", 56210092Seric pintvl(TimeOut, FALSE)); 56310105Seric if (e->e_message != NULL) 56410105Seric free(e->e_message); 56510105Seric e->e_message = newstr(buf); 56610105Seric message(Arpa_Info, buf); 56710105Seric } 56810092Seric q->q_flags |= QBADADDR; 56910092Seric e->e_flags |= EF_TIMEOUT; 57057642Seric fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); 57110092Seric } 57210092Seric else 57310092Seric q->q_flags |= QQUEUEUP; 57410092Seric } 57510092Seric /* 5764214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5774214Seric ** 5784214Seric ** This MUST be a macro, since after a vfork we are running 5794214Seric ** two processes on the same stack!!! 5804214Seric ** 5814214Seric ** Parameters: 5824214Seric ** none. 5834214Seric ** 5844214Seric ** Returns: 5854214Seric ** From a macro??? You've got to be kidding! 5864214Seric ** 5874214Seric ** Side Effects: 5884214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5894214Seric ** pid of child in parent, zero in child. 5904214Seric ** -1 on unrecoverable error. 5914214Seric ** 5924214Seric ** Notes: 5934214Seric ** I'm awfully sorry this looks so awful. That's 5944214Seric ** vfork for you..... 5954214Seric */ 5964214Seric 5974214Seric # define NFORKTRIES 5 5984214Seric 59952107Seric # ifndef FORK 60052107Seric # define FORK fork 60152107Seric # endif 60252107Seric 6034214Seric # define DOFORK(fORKfN) \ 6044214Seric {\ 6054214Seric register int i;\ 6064214Seric \ 60723504Seric for (i = NFORKTRIES; --i >= 0; )\ 6084214Seric {\ 6094214Seric pid = fORKfN();\ 6104214Seric if (pid >= 0)\ 6114214Seric break;\ 61223504Seric if (i > 0)\ 61325617Seric sleep((unsigned) NFORKTRIES - i);\ 6144214Seric }\ 6154214Seric } 6164214Seric /* 6174637Seric ** DOFORK -- simple fork interface to DOFORK. 6184637Seric ** 6194637Seric ** Parameters: 6204637Seric ** none. 6214637Seric ** 6224637Seric ** Returns: 6234637Seric ** pid of child in parent. 6244637Seric ** zero in child. 6254637Seric ** -1 on error. 6264637Seric ** 6274637Seric ** Side Effects: 6284637Seric ** returns twice, once in parent and once in child. 6294637Seric */ 6304637Seric 6314637Seric dofork() 6324637Seric { 6334637Seric register int pid; 6344637Seric 6354637Seric DOFORK(fork); 6364637Seric return (pid); 6374637Seric } 6384637Seric /* 6394863Seric ** ENDMAILER -- Wait for mailer to terminate. 6404863Seric ** 6414863Seric ** We should never get fatal errors (e.g., segmentation 6424863Seric ** violation), so we report those specially. For other 6434863Seric ** errors, we choose a status message (into statmsg), 6444863Seric ** and if it represents an error, we print it. 6454863Seric ** 6464863Seric ** Parameters: 6474863Seric ** pid -- pid of mailer. 6484863Seric ** name -- name of mailer (for error messages). 6494863Seric ** 6504863Seric ** Returns: 6514863Seric ** exit code of mailer. 6524863Seric ** 6534863Seric ** Side Effects: 6544863Seric ** none. 6554863Seric */ 6564863Seric 65753738Seric endmailer(mci, name) 65854967Seric register MCI *mci; 6594863Seric char *name; 6604863Seric { 6619370Seric int st; 6624863Seric 66353738Seric /* close any connections */ 66453738Seric if (mci->mci_in != NULL) 66553738Seric (void) fclose(mci->mci_in); 66653738Seric if (mci->mci_out != NULL) 66753738Seric (void) fclose(mci->mci_out); 66853738Seric mci->mci_in = mci->mci_out = NULL; 66953738Seric mci->mci_state = MCIS_CLOSED; 67053738Seric 6716038Seric /* in the IPC case there is nothing to wait for */ 67253738Seric if (mci->mci_pid == 0) 6736038Seric return (EX_OK); 6746038Seric 6756038Seric /* wait for the mailer process to die and collect status */ 67653738Seric st = waitfor(mci->mci_pid); 6779370Seric if (st == -1) 6788127Seric { 6799370Seric syserr("endmailer %s: wait", name); 6809370Seric return (EX_SOFTWARE); 6814863Seric } 6826038Seric 6836038Seric /* see if it died a horrid death */ 6844863Seric if ((st & 0377) != 0) 6854863Seric { 68624941Seric syserr("mailer %s died with signal %o", name, st); 68724941Seric ExitStat = EX_TEMPFAIL; 68824941Seric return (EX_TEMPFAIL); 6894863Seric } 6906038Seric 6916038Seric /* normal death -- return status */ 6929370Seric st = (st >> 8) & 0377; 6939370Seric return (st); 6944863Seric } 6954863Seric /* 6964863Seric ** OPENMAILER -- open connection to mailer. 6974863Seric ** 6984863Seric ** Parameters: 6994863Seric ** m -- mailer descriptor. 7004863Seric ** pvp -- parameter vector to pass to mailer. 7014863Seric ** ctladdr -- controlling address for user. 7024863Seric ** clever -- create a full duplex connection. 7034863Seric ** 7044863Seric ** Returns: 70553738Seric ** The mail connection info struct for this connection. 70653738Seric ** NULL on failure. 7074863Seric ** 7084863Seric ** Side Effects: 7094863Seric ** creates a mailer in a subprocess. 7104863Seric */ 7114863Seric 71254967Seric MCI * 71354967Seric openmailer(m, pvp, ctladdr, clever, e) 7149370Seric MAILER *m; 7154863Seric char **pvp; 7164863Seric ADDRESS *ctladdr; 7174863Seric bool clever; 71854967Seric ENVELOPE *e; 7194863Seric { 7204863Seric int pid; 72154967Seric register MCI *mci; 7224709Seric int mpvect[2]; 7234863Seric int rpvect[2]; 7243233Seric extern FILE *fdopen(); 7253233Seric 7267672Seric if (tTd(11, 1)) 727294Seric { 7288178Seric printf("openmailer:"); 7293233Seric printav(pvp); 730294Seric } 7314488Seric errno = 0; 7323233Seric 73325050Seric CurHostName = m->m_mailer; 73425050Seric 7356038Seric /* 7366038Seric ** Deal with the special case of mail handled through an IPC 7376038Seric ** connection. 7386038Seric ** In this case we don't actually fork. We must be 7396038Seric ** running SMTP for this to work. We will return a 7406038Seric ** zero pid to indicate that we are running IPC. 74111160Seric ** We also handle a debug version that just talks to stdin/out. 7426038Seric */ 7436038Seric 74411160Seric /* check for Local Person Communication -- not for mortals!!! */ 74511160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 74611160Seric { 74754967Seric mci = (MCI *) xalloc(sizeof *mci); 74854993Seric bzero((char *) mci, sizeof *mci); 74953738Seric mci->mci_in = stdin; 75053738Seric mci->mci_out = stdout; 75154967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 75253751Seric mci->mci_mailer = m; 75311160Seric } 75454967Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 75554967Seric strcmp(m->m_mailer, "[TCP]") == 0) 7566038Seric { 75752107Seric #ifdef DAEMON 75857454Seric register int i; 7597285Seric register u_short port; 76057454Seric char *curhost; 76154967Seric extern MCI *mci_get(); 76257454Seric extern char *hostsignature(); 7636038Seric 76425050Seric CurHostName = pvp[1]; 76557454Seric curhost = hostsignature(m, pvp[1], e); 76654967Seric 7676038Seric if (!clever) 7686038Seric syserr("non-clever IPC"); 7696632Seric if (pvp[2] != NULL) 7707285Seric port = atoi(pvp[2]); 7716632Seric else 7727285Seric port = 0; 77357454Seric while (*curhost != '\0') 77429433Sbloom { 77557454Seric register char *p; 77657454Seric char hostbuf[MAXNAME]; 77757454Seric 77857454Seric /* pull the next host from the signature */ 77957454Seric p = strchr(curhost, ':'); 78057454Seric if (p == NULL) 78157454Seric p = &curhost[strlen(curhost)]; 78257454Seric strncpy(hostbuf, curhost, p - curhost); 78357454Seric hostbuf[p - curhost] = '\0'; 78457454Seric if (*p != '\0') 78557454Seric p++; 78657454Seric curhost = p; 78757454Seric 78853738Seric /* see if we already know that this host is fried */ 78957454Seric CurHostName = hostbuf; 79057454Seric mci = mci_get(hostbuf, m); 79154967Seric if (mci->mci_state != MCIS_CLOSED) 79257387Seric { 79357387Seric if (tTd(11, 1)) 79457387Seric { 79557387Seric printf("openmailer: "); 79657387Seric mci_dump(mci); 79757387Seric } 79857943Seric CurHostName = mci->mci_host; 79953738Seric return mci; 80057387Seric } 80153751Seric mci->mci_mailer = m; 80254967Seric if (mci->mci_exitstat != EX_OK) 80354967Seric continue; 80454967Seric 80554967Seric /* try the connection */ 80657454Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 80754967Seric message(Arpa_Info, "Connecting to %s (%s)...", 80857454Seric hostbuf, m->m_name); 80957454Seric i = makeconnection(hostbuf, port, mci, 81054967Seric bitnset(M_SECURE_PORT, m->m_flags)); 81154967Seric mci->mci_exitstat = i; 81254967Seric mci->mci_errno = errno; 81354967Seric if (i == EX_OK) 81452106Seric { 81554967Seric mci->mci_state = MCIS_OPENING; 81654967Seric mci_cache(mci); 81754967Seric break; 81834022Sbostic } 81954967Seric else if (tTd(11, 1)) 82054967Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 82154967Seric i, errno); 82253738Seric 82354967Seric 82453738Seric /* enter status of this host */ 82553738Seric setstat(i); 8266047Seric } 82754993Seric mci->mci_pid = 0; 82854967Seric #else /* no DAEMON */ 8299370Seric syserr("openmailer: no IPC"); 83057387Seric if (tTd(11, 1)) 83157387Seric printf("openmailer: NULL\n"); 83253738Seric return NULL; 83354967Seric #endif /* DAEMON */ 8346038Seric } 83554967Seric else 836294Seric { 83754967Seric /* create a pipe to shove the mail through */ 83854967Seric if (pipe(mpvect) < 0) 83954967Seric { 84054967Seric syserr("openmailer: pipe (to mailer)"); 84157387Seric if (tTd(11, 1)) 84257387Seric printf("openmailer: NULL\n"); 84354967Seric return NULL; 84454967Seric } 8454863Seric 84654967Seric /* if this mailer speaks smtp, create a return pipe */ 84754967Seric if (clever && pipe(rpvect) < 0) 84854967Seric { 84954967Seric syserr("openmailer: pipe (from mailer)"); 85054967Seric (void) close(mpvect[0]); 85154967Seric (void) close(mpvect[1]); 85257387Seric if (tTd(11, 1)) 85357387Seric printf("openmailer: NULL\n"); 85454967Seric return NULL; 85554967Seric } 8564863Seric 85754967Seric /* 85854967Seric ** Actually fork the mailer process. 85954967Seric ** DOFORK is clever about retrying. 86054967Seric ** 86154967Seric ** Dispose of SIGCHLD signal catchers that may be laying 86254967Seric ** around so that endmail will get it. 86354967Seric */ 8646038Seric 86554967Seric if (e->e_xfp != NULL) 86654967Seric (void) fflush(e->e_xfp); /* for debugging */ 86754967Seric (void) fflush(stdout); 86826434Seric # ifdef SIGCHLD 86954967Seric (void) signal(SIGCHLD, SIG_DFL); 87056795Seric # endif /* SIGCHLD */ 87154967Seric DOFORK(FORK); 87254967Seric /* pid is set by DOFORK */ 87354967Seric if (pid < 0) 8744863Seric { 87554967Seric /* failure */ 87654967Seric syserr("openmailer: cannot fork"); 87754967Seric (void) close(mpvect[0]); 87854967Seric (void) close(mpvect[1]); 87954967Seric if (clever) 88054967Seric { 88154967Seric (void) close(rpvect[0]); 88254967Seric (void) close(rpvect[1]); 88354967Seric } 88457387Seric if (tTd(11, 1)) 88557387Seric printf("openmailer: NULL\n"); 88654967Seric return NULL; 8874863Seric } 88854967Seric else if (pid == 0) 88954967Seric { 89054967Seric int i; 89156678Seric int saveerrno; 89257529Seric char *env[2]; 89354967Seric extern int DtableSize; 89415772Seric 89554967Seric /* child -- set up input & exec mailer */ 89654967Seric /* make diagnostic output be standard output */ 89754967Seric (void) signal(SIGINT, SIG_IGN); 89854967Seric (void) signal(SIGHUP, SIG_IGN); 89954967Seric (void) signal(SIGTERM, SIG_DFL); 9004709Seric 90158082Seric /* close any other cached connections */ 90258082Seric mci_flush(FALSE, mci); 90358082Seric 90454967Seric /* arrange to filter std & diag output of command */ 90554967Seric if (clever) 90654967Seric { 90754967Seric (void) close(rpvect[0]); 90854967Seric (void) close(1); 90954967Seric (void) dup(rpvect[1]); 91054967Seric (void) close(rpvect[1]); 91154967Seric } 91254967Seric else if (OpMode == MD_SMTP || HoldErrs) 91354967Seric { 91454967Seric /* put mailer output in transcript */ 91554967Seric (void) close(1); 91654967Seric (void) dup(fileno(e->e_xfp)); 91754967Seric } 91854967Seric (void) close(2); 91954967Seric (void) dup(1); 9204709Seric 92154967Seric /* arrange to get standard input */ 92254967Seric (void) close(mpvect[1]); 92354967Seric (void) close(0); 92454967Seric if (dup(mpvect[0]) < 0) 9254417Seric { 92654967Seric syserr("Cannot dup to zero!"); 92754967Seric _exit(EX_OSERR); 9284417Seric } 92954967Seric (void) close(mpvect[0]); 93054967Seric if (!bitnset(M_RESTR, m->m_flags)) 9314415Seric { 93254967Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 93354967Seric { 93454967Seric (void) setgid(DefGid); 93554967Seric (void) initgroups(DefUser, DefGid); 93654967Seric (void) setuid(DefUid); 93754967Seric } 93854967Seric else 93954967Seric { 94054967Seric (void) setgid(ctladdr->q_gid); 94154967Seric (void) initgroups(ctladdr->q_ruser? 94254967Seric ctladdr->q_ruser: ctladdr->q_user, 94354967Seric ctladdr->q_gid); 94454967Seric (void) setuid(ctladdr->q_uid); 94554967Seric } 9464415Seric } 9479370Seric 94854967Seric /* arrange for all the files to be closed */ 94954967Seric for (i = 3; i < DtableSize; i++) 95054967Seric { 95154967Seric register int j; 95254967Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 95354967Seric (void)fcntl(i, F_SETFD, j|1); 95454967Seric } 9552774Seric 95654967Seric /* try to execute the mailer */ 95757529Seric env[0] = "AGENT=sendmail"; 95857529Seric env[1] = NULL; 95957529Seric execve(m->m_mailer, pvp, env); 96056678Seric saveerrno = errno; 96154967Seric syserr("Cannot exec %s", m->m_mailer); 96254967Seric if (m == LocalMailer) 96354967Seric _exit(EX_TEMPFAIL); 96456678Seric switch (saveerrno) 96554967Seric { 96654967Seric case EIO: 96754967Seric case EAGAIN: 96854967Seric case ENOMEM: 96951835Seric # ifdef EPROCLIM 97054967Seric case EPROCLIM: 97151835Seric # endif 97258108Seric # ifdef ETIMEDOUT 97358108Seric case ETIMEDOUT: 97458108Seric # endif 97554967Seric _exit(EX_TEMPFAIL); 97654967Seric } 97754967Seric _exit(EX_UNAVAILABLE); 97851835Seric } 97954967Seric 98054967Seric /* 98154967Seric ** Set up return value. 98254967Seric */ 98354967Seric 98454967Seric mci = (MCI *) xalloc(sizeof *mci); 98554993Seric bzero((char *) mci, sizeof *mci); 98654967Seric mci->mci_mailer = m; 98754967Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 98854993Seric mci->mci_pid = pid; 98954967Seric (void) close(mpvect[0]); 99054967Seric mci->mci_out = fdopen(mpvect[1], "w"); 99154967Seric if (clever) 99254967Seric { 99354967Seric (void) close(rpvect[1]); 99454967Seric mci->mci_in = fdopen(rpvect[0], "r"); 99554967Seric } 99654967Seric else 99754967Seric { 99854967Seric mci->mci_flags |= MCIF_TEMP; 99954967Seric mci->mci_in = NULL; 100054967Seric } 1001294Seric } 1002294Seric 10034709Seric /* 100454967Seric ** If we are in SMTP opening state, send initial protocol. 10054709Seric */ 10064709Seric 100754967Seric if (clever && mci->mci_state != MCIS_CLOSED) 10084863Seric { 100954967Seric smtpinit(m, mci, e); 101053738Seric } 101157387Seric if (tTd(11, 1)) 101257387Seric { 101357387Seric printf("openmailer: "); 101457387Seric mci_dump(mci); 101557387Seric } 1016294Seric 101753738Seric return mci; 1018294Seric } 1019294Seric /* 1020294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 1021294Seric ** 1022294Seric ** Parameters: 1023294Seric ** stat -- the status code from the mailer (high byte 1024294Seric ** only; core dumps must have been taken care of 1025294Seric ** already). 1026294Seric ** m -- the mailer descriptor for this mailer. 1027294Seric ** 1028294Seric ** Returns: 10294082Seric ** none. 1030294Seric ** 1031294Seric ** Side Effects: 10321518Seric ** Errors may be incremented. 1033294Seric ** ExitStat may be set. 1034294Seric */ 1035294Seric 103610105Seric giveresponse(stat, m, e) 1037294Seric int stat; 10389370Seric register MAILER *m; 103910105Seric ENVELOPE *e; 1040294Seric { 1041294Seric register char *statmsg; 1042294Seric extern char *SysExMsg[]; 1043294Seric register int i; 104436788Sbostic extern int N_SysEx; 104536788Sbostic #ifdef NAMED_BIND 104636788Sbostic extern int h_errno; 104736788Sbostic #endif 104810105Seric char buf[MAXLINE]; 1049294Seric 105012135Seric #ifdef lint 105112135Seric if (m == NULL) 105212135Seric return; 105312135Seric #endif lint 105412135Seric 10554315Seric /* 10564315Seric ** Compute status message from code. 10574315Seric */ 10584315Seric 1059294Seric i = stat - EX__BASE; 10609370Seric if (stat == 0) 10619370Seric statmsg = "250 Sent"; 10629370Seric else if (i < 0 || i > N_SysEx) 10639370Seric { 10649370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 10659370Seric stat = EX_UNAVAILABLE; 10669370Seric statmsg = buf; 10679370Seric } 106810105Seric else if (stat == EX_TEMPFAIL) 106910105Seric { 107010124Seric (void) strcpy(buf, SysExMsg[i]); 107136788Sbostic #ifdef NAMED_BIND 107225527Smiriam if (h_errno == TRY_AGAIN) 107310105Seric { 107415137Seric extern char *errstring(); 107515137Seric 107625527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 107721061Seric } 107821061Seric else 107936788Sbostic #endif 108021061Seric { 108125527Smiriam if (errno != 0) 108225527Smiriam { 108325527Smiriam extern char *errstring(); 108425527Smiriam 108525527Smiriam statmsg = errstring(errno); 108625527Smiriam } 108725527Smiriam else 108825527Smiriam { 108921061Seric #ifdef SMTP 109025527Smiriam extern char SmtpError[]; 109121061Seric 109225527Smiriam statmsg = SmtpError; 109356795Seric #else /* SMTP */ 109425527Smiriam statmsg = NULL; 109556795Seric #endif /* SMTP */ 109625527Smiriam } 109721061Seric } 109821061Seric if (statmsg != NULL && statmsg[0] != '\0') 109921061Seric { 110010124Seric (void) strcat(buf, ": "); 110121061Seric (void) strcat(buf, statmsg); 110210105Seric } 110310105Seric statmsg = buf; 110410105Seric } 1105294Seric else 110621061Seric { 1107294Seric statmsg = SysExMsg[i]; 110821061Seric } 11099370Seric 11109370Seric /* 11119370Seric ** Print the message as appropriate 11129370Seric */ 11139370Seric 111410105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 11158003Seric message(Arpa_Info, &statmsg[4]); 1116294Seric else 1117294Seric { 11181518Seric Errors++; 11199370Seric usrerr(statmsg); 1120294Seric } 1121294Seric 1122294Seric /* 1123294Seric ** Final cleanup. 1124294Seric ** Log a record of the transaction. Compute the new 1125294Seric ** ExitStat -- if we already had an error, stick with 1126294Seric ** that. 1127294Seric */ 1128294Seric 112958020Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 113054967Seric logdelivery(&statmsg[4], e); 11317858Seric 11324621Seric if (stat != EX_TEMPFAIL) 11334621Seric setstat(stat); 113410105Seric if (stat != EX_OK) 113510105Seric { 113610105Seric if (e->e_message != NULL) 113710105Seric free(e->e_message); 113810105Seric e->e_message = newstr(&statmsg[4]); 113910105Seric } 114010124Seric errno = 0; 114136788Sbostic #ifdef NAMED_BIND 114225527Smiriam h_errno = 0; 114336788Sbostic #endif 1144294Seric } 1145294Seric /* 11468496Seric ** LOGDELIVERY -- log the delivery in the system log 11478496Seric ** 11488496Seric ** Parameters: 11498496Seric ** stat -- the message to print for the status 11508496Seric ** 11518496Seric ** Returns: 11528496Seric ** none 11538496Seric ** 11548496Seric ** Side Effects: 11558496Seric ** none 11568496Seric */ 11578496Seric 115854967Seric logdelivery(stat, e) 11598496Seric char *stat; 116054967Seric register ENVELOPE *e; 11618496Seric { 11628496Seric extern char *pintvl(); 11638496Seric 11648496Seric # ifdef LOG 116554967Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", e->e_id, 116654967Seric e->e_to, pintvl(curtime() - e->e_ctime, TRUE), stat); 116756795Seric # endif /* LOG */ 11688496Seric } 11698496Seric /* 11706974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1171294Seric ** 11726974Seric ** This can be made an arbitrary message separator by changing $l 1173294Seric ** 117416150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 117516150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 117616150Seric ** does a well-meaning programmer such as myself have to deal with 117716150Seric ** this kind of antique garbage???? 11786974Seric ** 1179294Seric ** Parameters: 11806974Seric ** fp -- the file to output to. 11816974Seric ** m -- the mailer describing this entry. 1182294Seric ** 1183294Seric ** Returns: 11846974Seric ** none 1185294Seric ** 1186294Seric ** Side Effects: 11876974Seric ** outputs some text to fp. 1188294Seric */ 1189294Seric 119054967Seric putfromline(fp, m, e) 11916974Seric register FILE *fp; 11926974Seric register MAILER *m; 119354967Seric ENVELOPE *e; 1194294Seric { 119558050Seric char *template = "\201l\n"; 11966974Seric char buf[MAXLINE]; 1197294Seric 119810682Seric if (bitnset(M_NHDR, m->m_flags)) 11996974Seric return; 12004315Seric 12016974Seric # ifdef UGLYUUCP 120210682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 12034205Seric { 120412223Seric char *bang; 120512223Seric char xbuf[MAXLINE]; 12066041Seric 120758050Seric expand("\201<", buf, &buf[sizeof buf - 1], e); 120856795Seric bang = strchr(buf, '!'); 12096974Seric if (bang == NULL) 121012223Seric syserr("No ! in UUCP! (%s)", buf); 12115099Seric else 12129370Seric { 121312223Seric *bang++ = '\0'; 121458050Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 121512223Seric template = xbuf; 12169370Seric } 12176974Seric } 121856795Seric # endif /* UGLYUUCP */ 121954967Seric expand(template, buf, &buf[sizeof buf - 1], e); 122010168Seric putline(buf, fp, m); 12215981Seric } 12225981Seric /* 12236974Seric ** PUTBODY -- put the body of a message. 12246974Seric ** 12256974Seric ** Parameters: 12266974Seric ** fp -- file to output onto. 122710168Seric ** m -- a mailer descriptor to control output format. 12289538Seric ** e -- the envelope to put out. 12296974Seric ** 12306974Seric ** Returns: 12316974Seric ** none. 12326974Seric ** 12336974Seric ** Side Effects: 12346974Seric ** The message is written onto fp. 12356974Seric */ 12366974Seric 123710168Seric putbody(fp, m, e) 12386974Seric FILE *fp; 12399370Seric MAILER *m; 12409538Seric register ENVELOPE *e; 12416974Seric { 124210168Seric char buf[MAXLINE]; 12436974Seric 12446974Seric /* 12456974Seric ** Output the body of the message 12466974Seric */ 12476974Seric 12489538Seric if (e->e_dfp == NULL) 12496974Seric { 12509538Seric if (e->e_df != NULL) 12519538Seric { 12529538Seric e->e_dfp = fopen(e->e_df, "r"); 12539538Seric if (e->e_dfp == NULL) 125440931Srick syserr("putbody: Cannot open %s for %s from %s", 125540931Srick e->e_df, e->e_to, e->e_from); 12569538Seric } 12579538Seric else 125810168Seric putline("<<< No Message Collected >>>", fp, m); 12599538Seric } 12609538Seric if (e->e_dfp != NULL) 12619538Seric { 12629538Seric rewind(e->e_dfp); 126310168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 126416875Seric { 126516875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 126640995Sbostic strncmp(buf, "From ", 5) == 0) 126723102Seric (void) putc('>', fp); 126810168Seric putline(buf, fp, m); 126916875Seric } 12706974Seric 12719538Seric if (ferror(e->e_dfp)) 12726974Seric { 12736974Seric syserr("putbody: read error"); 12746974Seric ExitStat = EX_IOERR; 12756974Seric } 12766974Seric } 12776974Seric 12786974Seric (void) fflush(fp); 12796974Seric if (ferror(fp) && errno != EPIPE) 12806974Seric { 12816974Seric syserr("putbody: write error"); 12826974Seric ExitStat = EX_IOERR; 12836974Seric } 12846974Seric errno = 0; 12856974Seric } 12866974Seric /* 1287294Seric ** MAILFILE -- Send a message to a file. 1288294Seric ** 12894327Seric ** If the file has the setuid/setgid bits set, but NO execute 12904327Seric ** bits, sendmail will try to become the owner of that file 12914327Seric ** rather than the real user. Obviously, this only works if 12924327Seric ** sendmail runs as root. 12934327Seric ** 12949370Seric ** This could be done as a subordinate mailer, except that it 12959370Seric ** is used implicitly to save messages in ~/dead.letter. We 12969370Seric ** view this as being sufficiently important as to include it 12979370Seric ** here. For example, if the system is dying, we shouldn't have 12989370Seric ** to create another process plus some pipes to save the message. 12999370Seric ** 1300294Seric ** Parameters: 1301294Seric ** filename -- the name of the file to send to. 13024397Seric ** ctladdr -- the controlling address header -- includes 13034397Seric ** the userid/groupid to be when sending. 1304294Seric ** 1305294Seric ** Returns: 1306294Seric ** The exit code associated with the operation. 1307294Seric ** 1308294Seric ** Side Effects: 1309294Seric ** none. 1310294Seric */ 1311294Seric 131254967Seric mailfile(filename, ctladdr, e) 1313294Seric char *filename; 13144397Seric ADDRESS *ctladdr; 131554967Seric register ENVELOPE *e; 1316294Seric { 1317294Seric register FILE *f; 13184214Seric register int pid; 131953751Seric int mode; 1320294Seric 13214214Seric /* 13224214Seric ** Fork so we can change permissions here. 13234214Seric ** Note that we MUST use fork, not vfork, because of 13244214Seric ** the complications of calling subroutines, etc. 13254214Seric */ 13264067Seric 13274214Seric DOFORK(fork); 13284214Seric 13294214Seric if (pid < 0) 13304214Seric return (EX_OSERR); 13314214Seric else if (pid == 0) 13324214Seric { 13334214Seric /* child -- actually write to file */ 13344327Seric struct stat stb; 13354327Seric 13364215Seric (void) signal(SIGINT, SIG_DFL); 13374215Seric (void) signal(SIGHUP, SIG_DFL); 13384215Seric (void) signal(SIGTERM, SIG_DFL); 133923102Seric (void) umask(OldUmask); 134052673Seric 13414327Seric if (stat(filename, &stb) < 0) 13424431Seric stb.st_mode = 0666; 134353751Seric mode = stb.st_mode; 134452673Seric 134552673Seric /* limit the errors to those actually caused in the child */ 134652673Seric errno = 0; 134752673Seric ExitStat = EX_OK; 134852673Seric 13494327Seric if (bitset(0111, stb.st_mode)) 13504327Seric exit(EX_CANTCREAT); 13514401Seric if (ctladdr == NULL) 135240931Srick ctladdr = &e->e_from; 135353751Seric else 135453751Seric { 135553751Seric /* ignore setuid and setgid bits */ 135653751Seric mode &= ~(S_ISGID|S_ISUID); 135753751Seric } 135853751Seric 135940931Srick /* we have to open the dfile BEFORE setuid */ 136053751Seric if (e->e_dfp == NULL && e->e_df != NULL) 136140931Srick { 136240931Srick e->e_dfp = fopen(e->e_df, "r"); 136352673Seric if (e->e_dfp == NULL) 136452673Seric { 136540931Srick syserr("mailfile: Cannot open %s for %s from %s", 136653751Seric e->e_df, e->e_to, e->e_from); 136740931Srick } 136840931Srick } 136940931Srick 137053751Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 13714417Seric { 137252673Seric if (ctladdr->q_uid == 0) 137352673Seric { 13744417Seric (void) setgid(DefGid); 137540972Sbostic (void) initgroups(DefUser, DefGid); 137652673Seric } 137752673Seric else 137852673Seric { 13794417Seric (void) setgid(ctladdr->q_gid); 138053751Seric (void) initgroups(ctladdr->q_ruser ? 138153751Seric ctladdr->q_ruser : ctladdr->q_user, 138240972Sbostic ctladdr->q_gid); 138340972Sbostic } 13844417Seric } 138553751Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 13864417Seric { 13874417Seric if (ctladdr->q_uid == 0) 13884417Seric (void) setuid(DefUid); 13894417Seric else 13904417Seric (void) setuid(ctladdr->q_uid); 13914417Seric } 139252673Seric FileName = filename; 139352673Seric LineNumber = 0; 13946887Seric f = dfopen(filename, "a"); 13954214Seric if (f == NULL) 139652673Seric { 1397*58146Seric extern char Arpa_PSyserr[]; 1398*58146Seric 1399*58146Seric message(Arpa_PSyserr, "cannot open"); 14004214Seric exit(EX_CANTCREAT); 140152673Seric } 14024214Seric 140354967Seric putfromline(f, ProgMailer, e); 140455012Seric (*e->e_puthdr)(f, ProgMailer, e); 140510168Seric putline("\n", f, ProgMailer); 140655012Seric (*e->e_putbody)(f, ProgMailer, e); 140710168Seric putline("\n", f, ProgMailer); 140852673Seric if (ferror(f)) 140952673Seric { 1410*58146Seric extern char Arpa_TSyserr[]; 1411*58146Seric 1412*58146Seric message(Arpa_TSyserr, "I/O error"); 141352673Seric setstat(EX_IOERR); 141452673Seric } 14154214Seric (void) fclose(f); 14164214Seric (void) fflush(stdout); 14174417Seric 14186887Seric /* reset ISUID & ISGID bits for paranoid systems */ 14194621Seric (void) chmod(filename, (int) stb.st_mode); 142052673Seric exit(ExitStat); 14214315Seric /*NOTREACHED*/ 14224214Seric } 14234214Seric else 14244214Seric { 14254214Seric /* parent -- wait for exit status */ 14269370Seric int st; 14274214Seric 14289370Seric st = waitfor(pid); 14299370Seric if ((st & 0377) != 0) 14309370Seric return (EX_UNAVAILABLE); 14319370Seric else 14329370Seric return ((st >> 8) & 0377); 143340931Srick /*NOTREACHED*/ 14344214Seric } 1435294Seric } 14364550Seric /* 14374550Seric ** SENDALL -- actually send all the messages. 14384550Seric ** 14394550Seric ** Parameters: 14407043Seric ** e -- the envelope to send. 144114874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 144214874Seric ** the current SendMode. 14434550Seric ** 14444550Seric ** Returns: 14454550Seric ** none. 14464550Seric ** 14474550Seric ** Side Effects: 14484550Seric ** Scans the send lists and sends everything it finds. 14497043Seric ** Delivers any appropriate error messages. 14509275Seric ** If we are running in a non-interactive mode, takes the 14519275Seric ** appropriate action. 14524550Seric */ 14534550Seric 14549275Seric sendall(e, mode) 14557043Seric ENVELOPE *e; 14569275Seric char mode; 14574550Seric { 14585008Seric register ADDRESS *q; 14597779Seric bool oldverbose; 14609275Seric int pid; 146151937Seric # ifdef LOCKF 146251937Seric struct flock lfd; 146351937Seric # endif 14644550Seric 146514874Seric /* determine actual delivery mode */ 146614874Seric if (mode == SM_DEFAULT) 146714874Seric { 146824941Seric extern bool shouldqueue(); 146914874Seric 1470*58146Seric mode = SendMode; 1471*58146Seric if (mode != SM_VERIFY && 1472*58146Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 147314874Seric mode = SM_QUEUE; 147414874Seric } 147514874Seric 14768248Seric if (tTd(13, 1)) 14775032Seric { 14789275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 14797043Seric printaddr(e->e_sendqueue, TRUE); 14805032Seric } 14815008Seric 14827043Seric /* 14839275Seric ** Do any preprocessing necessary for the mode we are running. 14849370Seric ** Check to make sure the hop count is reasonable. 14859370Seric ** Delete sends to the sender in mailing lists. 14867043Seric */ 14877043Seric 14889370Seric CurEnv = e; 14899370Seric 149051305Seric if (e->e_hopcount > MaxHopCount) 14919275Seric { 149240931Srick errno = 0; 149340931Srick syserr("sendall: too many hops %d (%d max): from %s, to %s", 149457589Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 149557589Seric e->e_sendqueue->q_paddr); 14969370Seric return; 14979370Seric } 14989275Seric 14999370Seric if (!MeToo) 15009370Seric { 150112611Seric extern ADDRESS *recipient(); 150212611Seric 15039370Seric e->e_from.q_flags |= QDONTSEND; 150457731Seric if (tTd(13, 5)) 150557731Seric { 150657731Seric printf("sendall: QDONTSEND "); 150757731Seric printaddr(&e->e_from, FALSE); 150857731Seric } 150955012Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 15109275Seric } 15119370Seric 15129370Seric # ifdef QUEUE 15139335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 15149335Seric (mode != SM_VERIFY && SuperSafe)) && 15159335Seric !bitset(EF_INQUEUE, e->e_flags)) 151651920Seric queueup(e, TRUE, mode == SM_QUEUE); 151756795Seric #endif /* QUEUE */ 15189275Seric 15197779Seric oldverbose = Verbose; 15209275Seric switch (mode) 15219275Seric { 15229275Seric case SM_VERIFY: 15237779Seric Verbose = TRUE; 15249275Seric break; 15259275Seric 15269275Seric case SM_QUEUE: 152751916Seric queueonly: 15289335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 15299275Seric return; 15309275Seric 15319275Seric case SM_FORK: 15329538Seric if (e->e_xfp != NULL) 15339538Seric (void) fflush(e->e_xfp); 153451916Seric 153551916Seric # ifdef LOCKF 153651916Seric /* 153751916Seric ** Since lockf has the interesting semantic that the 153851937Seric ** lock is lost when we fork, we have to risk losing 153951937Seric ** the lock here by closing before the fork, and then 154051937Seric ** trying to get it back in the child. 154151916Seric */ 154251916Seric 154351920Seric if (e->e_lockfp != NULL) 154451916Seric { 154551920Seric (void) fclose(e->e_lockfp); 154651920Seric e->e_lockfp = NULL; 154751916Seric } 154851916Seric # endif /* LOCKF */ 154951916Seric 15509275Seric pid = fork(); 15519275Seric if (pid < 0) 15529275Seric { 155351916Seric goto queueonly; 15549275Seric } 15559275Seric else if (pid > 0) 15569293Seric { 15579293Seric /* be sure we leave the temp files to our child */ 15589335Seric e->e_id = e->e_df = NULL; 155951916Seric # ifndef LOCKF 156051920Seric if (e->e_lockfp != NULL) 156157731Seric { 156251920Seric (void) fclose(e->e_lockfp); 156357731Seric e->e_lockfp = NULL; 156457731Seric } 156551916Seric # endif 156657731Seric 156757731Seric /* close any random open files in the envelope */ 156857731Seric if (e->e_dfp != NULL) 156957731Seric { 157057731Seric (void) fclose(e->e_dfp); 157157731Seric e->e_dfp = NULL; 157257731Seric } 157357731Seric if (e->e_xfp != NULL) 157457731Seric { 157557731Seric (void) fclose(e->e_xfp); 157657731Seric e->e_xfp = NULL; 157757731Seric } 15789275Seric return; 15799293Seric } 15809275Seric 15819275Seric /* double fork to avoid zombies */ 15829275Seric if (fork() > 0) 15839275Seric exit(EX_OK); 15849275Seric 15859293Seric /* be sure we are immune from the terminal */ 158610133Seric disconnect(FALSE); 15879293Seric 158851911Seric # ifdef LOCKF 158951911Seric /* 159051916Seric ** Now try to get our lock back. 159151911Seric */ 159251911Seric 159351937Seric lfd.l_type = F_WRLCK; 159451937Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 159551920Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 159651920Seric if (e->e_lockfp == NULL || 159751937Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 159851911Seric { 159951916Seric /* oops.... lost it */ 160051911Seric # ifdef LOG 160158020Seric if (LogLevel > 29) 160251916Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 160354967Seric e->e_id); 160451911Seric # endif /* LOG */ 160551916Seric exit(EX_OK); 160651911Seric } 160751911Seric # endif /* LOCKF */ 160851911Seric 160958082Seric /* 161058082Seric ** Close any cached connections. 161158082Seric ** 161258082Seric ** We don't send the QUIT protocol because the parent 161358082Seric ** still knows about the connection. 161458082Seric ** 161558082Seric ** This should only happen when delivering an error 161658082Seric ** message. 161758082Seric */ 161858082Seric 161958082Seric mci_flush(FALSE, NULL); 162058082Seric 16219275Seric break; 16229275Seric } 16239275Seric 16249275Seric /* 16259275Seric ** Run through the list and send everything. 16269275Seric */ 16279275Seric 162857589Seric e->e_nsent = 0; 16297043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16304550Seric { 16319275Seric if (mode == SM_VERIFY) 16324550Seric { 16339293Seric e->e_to = q->q_paddr; 16345008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 16357052Seric message(Arpa_Info, "deliverable"); 16364550Seric } 163747284Seric else if (!bitset(QDONTSEND, q->q_flags)) 163847284Seric { 163950533Seric # ifdef QUEUE 164047284Seric /* 164147284Seric ** Checkpoint the send list every few addresses 164247284Seric */ 164347284Seric 164457589Seric if (e->e_nsent >= CheckpointInterval) 164547284Seric { 164651920Seric queueup(e, TRUE, FALSE); 164757589Seric e->e_nsent = 0; 164847284Seric } 164950533Seric # endif /* QUEUE */ 165057589Seric (void) deliver(e, q); 165147284Seric } 16524550Seric } 16537779Seric Verbose = oldverbose; 16547043Seric 16557043Seric /* 16567043Seric ** Now run through and check for errors. 16577043Seric */ 16587043Seric 165951920Seric if (mode == SM_VERIFY) 16607043Seric return; 16617043Seric 16627043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 16637043Seric { 16647043Seric register ADDRESS *qq; 16657043Seric 16668248Seric if (tTd(13, 3)) 16678248Seric { 16688248Seric printf("Checking "); 16698248Seric printaddr(q, FALSE); 16708248Seric } 16718248Seric 16729335Seric /* only send errors if the message failed */ 16739335Seric if (!bitset(QBADADDR, q->q_flags)) 16749335Seric continue; 16757043Seric 16767043Seric /* we have an address that failed -- find the parent */ 16777043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 16787043Seric { 16797043Seric char obuf[MAXNAME + 6]; 16807043Seric extern char *aliaslookup(); 16817043Seric 16827043Seric /* we can only have owners for local addresses */ 168358139Seric if (!bitnset(M_LOCALMAILER, qq->q_mailer->m_flags)) 16847043Seric continue; 16857043Seric 16867043Seric /* see if the owner list exists */ 16877043Seric (void) strcpy(obuf, "owner-"); 16887047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 16897047Seric (void) strcat(obuf, "owner"); 16907047Seric else 16917047Seric (void) strcat(obuf, qq->q_user); 169257438Seric if (!bitnset(M_USR_UPPER, qq->q_mailer->m_flags)) 169357438Seric makelower(obuf); 16947043Seric if (aliaslookup(obuf) == NULL) 16957043Seric continue; 16967043Seric 16978248Seric if (tTd(13, 4)) 16988248Seric printf("Errors to %s\n", obuf); 16998248Seric 17007043Seric /* owner list exists -- add it to the error queue */ 170158082Seric (void) sendtolist(obuf, (ADDRESS *) NULL, 170258082Seric &e->e_errorqueue, e); 170357438Seric 170457438Seric /* and set the return path to point to it */ 170557438Seric e->e_returnpath = newstr(obuf); 170657438Seric 170716883Seric ErrorMode = EM_MAIL; 17087043Seric break; 17097043Seric } 17107043Seric 17117043Seric /* if we did not find an owner, send to the sender */ 17128426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 171358082Seric (void) sendtolist(e->e_from.q_paddr, qq, 171458082Seric &e->e_errorqueue, e); 17157043Seric } 17169275Seric 17179275Seric if (mode == SM_FORK) 17189275Seric finis(); 17194550Seric } 172057454Seric /* 172157454Seric ** HOSTSIGNATURE -- return the "signature" for a host. 172257454Seric ** 172357454Seric ** The signature describes how we are going to send this -- it 172457454Seric ** can be just the hostname (for non-Internet hosts) or can be 172557454Seric ** an ordered list of MX hosts. 172657454Seric ** 172757454Seric ** Parameters: 172857454Seric ** m -- the mailer describing this host. 172957454Seric ** host -- the host name. 173057454Seric ** e -- the current envelope. 173157454Seric ** 173257454Seric ** Returns: 173357454Seric ** The signature for this host. 173457454Seric ** 173557454Seric ** Side Effects: 173657454Seric ** Can tweak the symbol table. 173757454Seric */ 173857454Seric 173957454Seric char * 174057454Seric hostsignature(m, host, e) 174157454Seric register MAILER *m; 174257454Seric char *host; 174357454Seric ENVELOPE *e; 174457454Seric { 174557454Seric register char *p; 174657454Seric register STAB *s; 174757454Seric int i; 174857454Seric int len; 174957454Seric #ifdef NAMED_BIND 175057454Seric int nmx; 175157454Seric auto int rcode; 175257454Seric char *mxhosts[MAXMXHOSTS + 1]; 175357454Seric static char myhostbuf[MAXNAME]; 175457454Seric #endif 175557454Seric 175657454Seric /* 175757454Seric ** Check to see if this uses IPC -- if not, it can't have MX records. 175857454Seric */ 175957454Seric 176057454Seric p = m->m_mailer; 176157454Seric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 176257454Seric { 176357454Seric /* just an ordinary mailer */ 176457454Seric return host; 176557454Seric } 176657454Seric 176757454Seric /* 176857454Seric ** If it is a numeric address, just return it. 176957454Seric */ 177057454Seric 177157454Seric if (host[0] == '[') 177257454Seric return host; 177357454Seric 177457454Seric /* 177557454Seric ** Look it up in the symbol table. 177657454Seric */ 177757454Seric 177857454Seric s = stab(host, ST_HOSTSIG, ST_ENTER); 177957454Seric if (s->s_hostsig != NULL) 178057454Seric return s->s_hostsig; 178157454Seric 178257454Seric /* 178357454Seric ** Not already there -- create a signature. 178457454Seric */ 178557454Seric 178657454Seric #ifdef NAMED_BIND 178757454Seric if (myhostbuf[0] == '\0') 178858050Seric expand("\201j", myhostbuf, &myhostbuf[sizeof myhostbuf - 1], e); 178957454Seric 179057454Seric nmx = getmxrr(host, mxhosts, myhostbuf, &rcode); 179157454Seric if (nmx <= 0) 179257454Seric { 179357454Seric register MCI *mci; 179457454Seric extern int errno; 179557454Seric extern MCI *mci_get(); 179657454Seric 179757454Seric /* update the connection info for this host */ 179857454Seric mci = mci_get(host, m); 179957454Seric mci->mci_exitstat = rcode; 180057454Seric mci->mci_errno = errno; 180157454Seric 180257454Seric /* and return the original host name as the signature */ 180357454Seric s->s_hostsig = host; 180457454Seric return host; 180557454Seric } 180657454Seric 180757454Seric len = 0; 180857454Seric for (i = 0; i < nmx; i++) 180957454Seric { 181057454Seric len += strlen(mxhosts[i]) + 1; 181157454Seric } 181257454Seric s->s_hostsig = p = xalloc(len); 181357454Seric for (i = 0; i < nmx; i++) 181457454Seric { 181557454Seric if (i != 0) 181657454Seric *p++ = ':'; 181757454Seric strcpy(p, mxhosts[i]); 181857454Seric p += strlen(p); 181957454Seric } 182057454Seric makelower(s->s_hostsig); 182157454Seric #else 182257454Seric /* not using BIND -- the signature is just the host name */ 182357454Seric s->s_hostsig = host; 182457454Seric #endif 182557454Seric if (tTd(17, 1)) 182657454Seric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 182757454Seric return s->s_hostsig; 182857454Seric } 1829