14227346bSdist /* 2e70a7521Sbostic * Copyright (c) 1988 Regents of the University of California. 3e70a7521Sbostic * All rights reserved. 4e70a7521Sbostic * 5e70a7521Sbostic * Redistribution and use in source and binary forms are permitted 6e70a7521Sbostic * provided that this notice is preserved and that due credit is given 7e70a7521Sbostic * to the University of California at Berkeley. The name of the University 8e70a7521Sbostic * may not be used to endorse or promote products derived from this 9e70a7521Sbostic * software without specific prior written permission. This software 10e70a7521Sbostic * is provided ``as is'' without express or implied warranty. 11e70a7521Sbostic * 12e70a7521Sbostic * Sendmail 13e70a7521Sbostic * Copyright (c) 1983 Eric P. Allman 14e70a7521Sbostic * Berkeley, California 154227346bSdist */ 164227346bSdist 174227346bSdist #ifndef lint 18*911693bfSbostic static char sccsid[] = "@(#)deliver.c 5.18 (Berkeley) 04/01/88"; 19e70a7521Sbostic #endif /* not lint */ 204227346bSdist 21*911693bfSbostic #include <sendmail.h> 22*911693bfSbostic #include <sys/signal.h> 23c77d1c25Seric #include <sys/stat.h> 24f28da541Smiriam #include <netdb.h> 25*911693bfSbostic #include <errno.h> 2625a99e2eSeric 2725a99e2eSeric /* 2813bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 2913bbc08cSeric ** 3013bbc08cSeric ** This routine delivers to everyone on the same host as the 3113bbc08cSeric ** user on the head of the list. It is clever about mailers 3213bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 3313bbc08cSeric ** that it will deliver to all these addresses however -- so 3413bbc08cSeric ** deliver should be called once for each address on the 3513bbc08cSeric ** list. 3625a99e2eSeric ** 3725a99e2eSeric ** Parameters: 38588cad61Seric ** e -- the envelope to deliver. 39c77d1c25Seric ** firstto -- head of the address list to deliver to. 4025a99e2eSeric ** 4125a99e2eSeric ** Returns: 4225a99e2eSeric ** zero -- successfully delivered. 4325a99e2eSeric ** else -- some failure, see ExitStat for more info. 4425a99e2eSeric ** 4525a99e2eSeric ** Side Effects: 4625a99e2eSeric ** The standard input is passed off to someone. 4725a99e2eSeric */ 4825a99e2eSeric 49588cad61Seric deliver(e, firstto) 50588cad61Seric register ENVELOPE *e; 51c77d1c25Seric ADDRESS *firstto; 5225a99e2eSeric { 5378442df3Seric char *host; /* host being sent to */ 5478442df3Seric char *user; /* user being sent to */ 5525a99e2eSeric char **pvp; 565dfc646bSeric register char **mvp; 5725a99e2eSeric register char *p; 58588cad61Seric register MAILER *m; /* mailer for this recipient */ 596259796dSeric ADDRESS *ctladdr; 60c77d1c25Seric register ADDRESS *to = firstto; 61c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 62772e6e50Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 63*911693bfSbostic int rcode; /* response code */ 64ee6bf8dfSeric char *pv[MAXPV+1]; 65ee6bf8dfSeric char tobuf[MAXLINE-50]; /* text line of to people */ 66ee6bf8dfSeric char buf[MAXNAME]; 67ee6bf8dfSeric char tfrombuf[MAXNAME]; /* translated from person */ 68ee6bf8dfSeric extern bool checkcompat(); 69ee6bf8dfSeric extern ADDRESS *getctladdr(); 70ee6bf8dfSeric extern char *remotename(); 7125a99e2eSeric 7235490626Seric errno = 0; 73da2935e1Seric if (bitset(QDONTSEND, to->q_flags)) 745dfc646bSeric return (0); 7525a99e2eSeric 7651552439Seric m = to->q_mailer; 7751552439Seric host = to->q_host; 7851552439Seric 7925a99e2eSeric # ifdef DEBUG 806ef48975Seric if (tTd(10, 1)) 815dfc646bSeric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 8251552439Seric m->m_mno, host, to->q_user); 8325a99e2eSeric # endif DEBUG 84f3dbc832Seric 85f3dbc832Seric /* 86f3dbc832Seric ** If this mailer is expensive, and if we don't want to make 87f3dbc832Seric ** connections now, just mark these addresses and return. 88f3dbc832Seric ** This is useful if we want to batch connections to 89f3dbc832Seric ** reduce load. This will cause the messages to be 90f3dbc832Seric ** queued up, and a daemon will come along to send the 91f3dbc832Seric ** messages later. 92f3dbc832Seric ** This should be on a per-mailer basis. 93f3dbc832Seric */ 94f3dbc832Seric 9557fc6f17Seric if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && 96317680d6Seric !Verbose) 97f3dbc832Seric { 98f3dbc832Seric for (; to != NULL; to = to->q_next) 99f4560e80Seric { 100f4560e80Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 101f4560e80Seric continue; 102f3dbc832Seric to->q_flags |= QQUEUEUP|QDONTSEND; 103588cad61Seric e->e_to = to->q_paddr; 104eb238f8cSeric message(Arpa_Info, "queued"); 105eb238f8cSeric if (LogLevel > 4) 106eb238f8cSeric logdelivery("queued"); 107f4560e80Seric } 108588cad61Seric e->e_to = NULL; 109f3dbc832Seric return (0); 110f3dbc832Seric } 111f3dbc832Seric 11225a99e2eSeric /* 1135dfc646bSeric ** Do initial argv setup. 1145dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 1155dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 1165dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 1175dfc646bSeric ** code does not check for 'pv' overflow; this places a 1185dfc646bSeric ** manifest lower limit of 4 for MAXPV. 1193bea8136Seric ** The from address rewrite is expected to make 1203bea8136Seric ** the address relative to the other end. 1215dfc646bSeric */ 1225dfc646bSeric 12378442df3Seric /* rewrite from address, using rewriting rules */ 1249b6c17a6Seric expand("\001f", buf, &buf[sizeof buf - 1], e); 125ee6bf8dfSeric (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); 12678442df3Seric 127588cad61Seric define('g', tfrombuf, e); /* translated sender address */ 128588cad61Seric define('h', host, e); /* to host */ 1295dfc646bSeric Errors = 0; 1305dfc646bSeric pvp = pv; 1315dfc646bSeric *pvp++ = m->m_argv[0]; 1325dfc646bSeric 1335dfc646bSeric /* insert -f or -r flag as appropriate */ 13457fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1355dfc646bSeric { 13657fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 1375dfc646bSeric *pvp++ = "-f"; 1385dfc646bSeric else 1395dfc646bSeric *pvp++ = "-r"; 1409b6c17a6Seric expand("\001g", buf, &buf[sizeof buf - 1], e); 1415dfc646bSeric *pvp++ = newstr(buf); 1425dfc646bSeric } 1435dfc646bSeric 1445dfc646bSeric /* 1455dfc646bSeric ** Append the other fixed parts of the argv. These run 1465dfc646bSeric ** up to the first entry containing "$u". There can only 1475dfc646bSeric ** be one of these, and there are only a few more slots 1485dfc646bSeric ** in the pv after it. 1495dfc646bSeric */ 1505dfc646bSeric 1515dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1525dfc646bSeric { 1539b6c17a6Seric while ((p = index(p, '\001')) != NULL) 1545dfc646bSeric if (*++p == 'u') 1555dfc646bSeric break; 1565dfc646bSeric if (p != NULL) 1575dfc646bSeric break; 1585dfc646bSeric 1595dfc646bSeric /* this entry is safe -- go ahead and process it */ 160588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1615dfc646bSeric *pvp++ = newstr(buf); 1625dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 1635dfc646bSeric { 1645dfc646bSeric syserr("Too many parameters to %s before $u", pv[0]); 1655dfc646bSeric return (-1); 1665dfc646bSeric } 1675dfc646bSeric } 168c579ef51Seric 16933db8731Seric /* 17033db8731Seric ** If we have no substitution for the user name in the argument 17133db8731Seric ** list, we know that we must supply the names otherwise -- and 17233db8731Seric ** SMTP is the answer!! 17333db8731Seric */ 17433db8731Seric 1755dfc646bSeric if (*mvp == NULL) 176c579ef51Seric { 177c579ef51Seric /* running SMTP */ 1782c7e1b8dSeric # ifdef SMTP 179c579ef51Seric clever = TRUE; 180c579ef51Seric *pvp = NULL; 1812c7e1b8dSeric # else SMTP 18233db8731Seric /* oops! we don't implement SMTP */ 1832c7e1b8dSeric syserr("SMTP style mailer"); 1842c7e1b8dSeric return (EX_SOFTWARE); 1852c7e1b8dSeric # endif SMTP 186c579ef51Seric } 1875dfc646bSeric 1885dfc646bSeric /* 1895dfc646bSeric ** At this point *mvp points to the argument with $u. We 1905dfc646bSeric ** run through our address list and append all the addresses 1915dfc646bSeric ** we can. If we run out of space, do not fret! We can 1925dfc646bSeric ** always send another copy later. 1935dfc646bSeric */ 1945dfc646bSeric 1955dfc646bSeric tobuf[0] = '\0'; 196588cad61Seric e->e_to = tobuf; 1976259796dSeric ctladdr = NULL; 1985dfc646bSeric for (; to != NULL; to = to->q_next) 1995dfc646bSeric { 2005dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 20157fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 2025dfc646bSeric break; 2035dfc646bSeric 2045dfc646bSeric /* if already sent or not for this host, don't send */ 205da2935e1Seric if (bitset(QDONTSEND, to->q_flags) || 206da2935e1Seric strcmp(to->q_host, host) != 0 || 207da2935e1Seric to->q_mailer != firstto->q_mailer) 2085dfc646bSeric continue; 2096259796dSeric 2104b22ea87Seric /* avoid overflowing tobuf */ 211588cad61Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 2124b22ea87Seric break; 2134b22ea87Seric 214772e6e50Seric # ifdef DEBUG 2156ef48975Seric if (tTd(10, 1)) 216772e6e50Seric { 217772e6e50Seric printf("\nsend to "); 218772e6e50Seric printaddr(to, FALSE); 219772e6e50Seric } 220772e6e50Seric # endif DEBUG 221772e6e50Seric 2226259796dSeric /* compute effective uid/gid when sending */ 2237da1035fSeric if (to->q_mailer == ProgMailer) 2246259796dSeric ctladdr = getctladdr(to); 2256259796dSeric 2265dfc646bSeric user = to->q_user; 227588cad61Seric e->e_to = to->q_paddr; 2285dfc646bSeric to->q_flags |= QDONTSEND; 2295dfc646bSeric 2305dfc646bSeric /* 2315dfc646bSeric ** Check to see that these people are allowed to 2325dfc646bSeric ** talk to each other. 2332a6e0786Seric */ 2342a6e0786Seric 23569582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 23669582d2fSeric { 23769582d2fSeric NoReturn = TRUE; 238672bec4aSeric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 23969582d2fSeric giveresponse(EX_UNAVAILABLE, m, e); 24069582d2fSeric continue; 24169582d2fSeric } 2422a6e0786Seric if (!checkcompat(to)) 2435dfc646bSeric { 244198d9be0Seric giveresponse(EX_UNAVAILABLE, m, e); 2455dfc646bSeric continue; 2465dfc646bSeric } 2472a6e0786Seric 2482a6e0786Seric /* 2499ec9501bSeric ** Strip quote bits from names if the mailer is dumb 2509ec9501bSeric ** about them. 25125a99e2eSeric */ 25225a99e2eSeric 25357fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 25425a99e2eSeric { 2559ec9501bSeric stripquotes(user, TRUE); 2569ec9501bSeric stripquotes(host, TRUE); 2579ec9501bSeric } 2589ec9501bSeric else 2599ec9501bSeric { 2609ec9501bSeric stripquotes(user, FALSE); 2619ec9501bSeric stripquotes(host, FALSE); 26225a99e2eSeric } 26325a99e2eSeric 264cdb828c5Seric /* hack attack -- delivermail compatibility */ 265cdb828c5Seric if (m == ProgMailer && *user == '|') 266cdb828c5Seric user++; 267cdb828c5Seric 26825a99e2eSeric /* 2693efaed6eSeric ** If an error message has already been given, don't 2703efaed6eSeric ** bother to send to this address. 2713efaed6eSeric ** 2723efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 2733efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 2743efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 2753efaed6eSeric */ 2763efaed6eSeric 2776cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2783efaed6eSeric continue; 2793efaed6eSeric 280f2fec898Seric /* save statistics.... */ 281588cad61Seric markstats(e, to); 282f2fec898Seric 2833efaed6eSeric /* 28425a99e2eSeric ** See if this user name is "special". 28525a99e2eSeric ** If the user name has a slash in it, assume that this 28651552439Seric ** is a file -- send it off without further ado. Note 28751552439Seric ** that this type of addresses is not processed along 28851552439Seric ** with the others, so we fudge on the To person. 28925a99e2eSeric */ 29025a99e2eSeric 2917da1035fSeric if (m == LocalMailer) 29225a99e2eSeric { 293a49f24c0Seric if (user[0] == '/') 29425a99e2eSeric { 2955826d9d3Seric rcode = mailfile(user, getctladdr(to)); 296198d9be0Seric giveresponse(rcode, m, e); 2975dfc646bSeric continue; 29825a99e2eSeric } 29925a99e2eSeric } 30025a99e2eSeric 30113bbc08cSeric /* 30213bbc08cSeric ** Address is verified -- add this user to mailer 30313bbc08cSeric ** argv, and add it to the print list of recipients. 30413bbc08cSeric */ 30513bbc08cSeric 306508daeccSeric /* link together the chain of recipients */ 307508daeccSeric to->q_tchain = tochain; 308508daeccSeric tochain = to; 309508daeccSeric 3105dfc646bSeric /* create list of users for error messages */ 311db8841e9Seric (void) strcat(tobuf, ","); 312db8841e9Seric (void) strcat(tobuf, to->q_paddr); 313588cad61Seric define('u', user, e); /* to user */ 314588cad61Seric define('z', to->q_home, e); /* user's home */ 3155dfc646bSeric 316c579ef51Seric /* 317508daeccSeric ** Expand out this user into argument list. 318c579ef51Seric */ 319c579ef51Seric 320508daeccSeric if (!clever) 321c579ef51Seric { 322588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3235dfc646bSeric *pvp++ = newstr(buf); 3245dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 3255dfc646bSeric { 3265dfc646bSeric /* allow some space for trailing parms */ 3275dfc646bSeric break; 3285dfc646bSeric } 3295dfc646bSeric } 330c579ef51Seric } 3315dfc646bSeric 332145b49b1Seric /* see if any addresses still exist */ 333145b49b1Seric if (tobuf[0] == '\0') 334c579ef51Seric { 335588cad61Seric define('g', (char *) NULL, e); 336145b49b1Seric return (0); 337c579ef51Seric } 338145b49b1Seric 3395dfc646bSeric /* print out messages as full list */ 34063780dbdSeric e->e_to = tobuf + 1; 3415dfc646bSeric 3425dfc646bSeric /* 3435dfc646bSeric ** Fill out any parameters after the $u parameter. 3445dfc646bSeric */ 3455dfc646bSeric 346c579ef51Seric while (!clever && *++mvp != NULL) 3475dfc646bSeric { 348588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3495dfc646bSeric *pvp++ = newstr(buf); 3505dfc646bSeric if (pvp >= &pv[MAXPV]) 3515dfc646bSeric syserr("deliver: pv overflow after $u for %s", pv[0]); 3525dfc646bSeric } 3535dfc646bSeric *pvp++ = NULL; 3545dfc646bSeric 35525a99e2eSeric /* 35625a99e2eSeric ** Call the mailer. 3576328bdf7Seric ** The argument vector gets built, pipes 35825a99e2eSeric ** are created as necessary, and we fork & exec as 3596328bdf7Seric ** appropriate. 360c579ef51Seric ** If we are running SMTP, we just need to clean up. 36125a99e2eSeric */ 36225a99e2eSeric 363588cad61Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 364588cad61Seric 3656259796dSeric if (ctladdr == NULL) 366588cad61Seric ctladdr = &e->e_from; 3672c7e1b8dSeric #ifdef SMTP 368*911693bfSbostic if (clever) { 369*911693bfSbostic expand("\001w", buf, &buf[sizeof(buf) - 1], e); 370*911693bfSbostic rcode = EX_OK; 371*911693bfSbostic if (host[0] == '[') { 37260bcc2d9Sbostic Nmx = 1; 37360bcc2d9Sbostic MxHosts[0] = host; 37460bcc2d9Sbostic } 375*911693bfSbostic else if ((Nmx = getmxrr(host, MxHosts, buf, &rcode)) >= 0 && 376*911693bfSbostic (rcode = smtpinit(m, pv)) == EX_OK) { 377588cad61Seric 378588cad61Seric /* send the recipient list */ 37963780dbdSeric tobuf[0] = '\0'; 380*911693bfSbostic for (to = tochain; to; to = to->q_tchain) { 381*911693bfSbostic register int i; 382*911693bfSbostic register char *t = tobuf; 383588cad61Seric 38463780dbdSeric e->e_to = to->q_paddr; 38577b52738Seric i = smtprcpt(to, m); 386*911693bfSbostic if (i != EX_OK) { 38783b7ddc9Seric markfailure(e, to, i); 388198d9be0Seric giveresponse(i, m, e); 38963780dbdSeric } 390*911693bfSbostic else { 391*911693bfSbostic *t++ = ','; 392*911693bfSbostic for (p = to->q_paddr; *p; *t++ = *p++); 393588cad61Seric } 394588cad61Seric } 395588cad61Seric 39663780dbdSeric /* now send the data */ 39763780dbdSeric if (tobuf[0] == '\0') 39863780dbdSeric e->e_to = NULL; 399*911693bfSbostic else { 40063780dbdSeric e->e_to = tobuf + 1; 40177b52738Seric rcode = smtpdata(m, e); 40263780dbdSeric } 40363780dbdSeric 40463780dbdSeric /* now close the connection */ 405a294c4b0Seric smtpquit(m); 40663780dbdSeric } 407c579ef51Seric } 408c579ef51Seric else 409*911693bfSbostic #endif /* SMTP */ 41077b52738Seric rcode = sendoff(e, m, pv, ctladdr); 4115dfc646bSeric 412c77d1c25Seric /* 41363780dbdSeric ** Do final status disposal. 41463780dbdSeric ** We check for something in tobuf for the SMTP case. 415c77d1c25Seric ** If we got a temporary failure, arrange to queue the 416c77d1c25Seric ** addressees. 417c77d1c25Seric */ 418c77d1c25Seric 41963780dbdSeric if (tobuf[0] != '\0') 420198d9be0Seric giveresponse(rcode, m, e); 42163780dbdSeric if (rcode != EX_OK) 422c77d1c25Seric { 423772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 42483b7ddc9Seric markfailure(e, to, rcode); 425c77d1c25Seric } 426c77d1c25Seric 42735490626Seric errno = 0; 428588cad61Seric define('g', (char *) NULL, e); 4295826d9d3Seric return (rcode); 43025a99e2eSeric } 4315dfc646bSeric /* 43283b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 43383b7ddc9Seric ** 43483b7ddc9Seric ** Parameters: 43583b7ddc9Seric ** e -- the envelope we are sending. 43683b7ddc9Seric ** q -- the address to mark. 43783b7ddc9Seric ** rcode -- the code signifying the particular failure. 43883b7ddc9Seric ** 43983b7ddc9Seric ** Returns: 44083b7ddc9Seric ** none. 44183b7ddc9Seric ** 44283b7ddc9Seric ** Side Effects: 44383b7ddc9Seric ** marks the address (and possibly the envelope) with the 44483b7ddc9Seric ** failure so that an error will be returned or 44583b7ddc9Seric ** the message will be queued, as appropriate. 44683b7ddc9Seric */ 44783b7ddc9Seric 44883b7ddc9Seric markfailure(e, q, rcode) 44983b7ddc9Seric register ENVELOPE *e; 45083b7ddc9Seric register ADDRESS *q; 45183b7ddc9Seric int rcode; 45283b7ddc9Seric { 45383b7ddc9Seric if (rcode == EX_OK) 45483b7ddc9Seric return; 45583b7ddc9Seric else if (rcode != EX_TEMPFAIL) 45683b7ddc9Seric q->q_flags |= QBADADDR; 45783b7ddc9Seric else if (curtime() > e->e_ctime + TimeOut) 45883b7ddc9Seric { 45983b7ddc9Seric extern char *pintvl(); 460198d9be0Seric char buf[MAXLINE]; 46183b7ddc9Seric 46283b7ddc9Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 463198d9be0Seric { 464198d9be0Seric (void) sprintf(buf, "Cannot send message for %s", 46583b7ddc9Seric pintvl(TimeOut, FALSE)); 466198d9be0Seric if (e->e_message != NULL) 467198d9be0Seric free(e->e_message); 468198d9be0Seric e->e_message = newstr(buf); 469198d9be0Seric message(Arpa_Info, buf); 470198d9be0Seric } 47183b7ddc9Seric q->q_flags |= QBADADDR; 47283b7ddc9Seric e->e_flags |= EF_TIMEOUT; 47383b7ddc9Seric } 47483b7ddc9Seric else 47583b7ddc9Seric q->q_flags |= QQUEUEUP; 47683b7ddc9Seric } 47783b7ddc9Seric /* 47832d19d43Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 47932d19d43Seric ** 48032d19d43Seric ** This MUST be a macro, since after a vfork we are running 48132d19d43Seric ** two processes on the same stack!!! 48232d19d43Seric ** 48332d19d43Seric ** Parameters: 48432d19d43Seric ** none. 48532d19d43Seric ** 48632d19d43Seric ** Returns: 48732d19d43Seric ** From a macro??? You've got to be kidding! 48832d19d43Seric ** 48932d19d43Seric ** Side Effects: 49032d19d43Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 49132d19d43Seric ** pid of child in parent, zero in child. 49232d19d43Seric ** -1 on unrecoverable error. 49332d19d43Seric ** 49432d19d43Seric ** Notes: 49532d19d43Seric ** I'm awfully sorry this looks so awful. That's 49632d19d43Seric ** vfork for you..... 49732d19d43Seric */ 49832d19d43Seric 49932d19d43Seric # define NFORKTRIES 5 5004300ddf0Seric # ifdef VMUNIX 50132d19d43Seric # define XFORK vfork 5024300ddf0Seric # else VMUNIX 50332d19d43Seric # define XFORK fork 5044300ddf0Seric # endif VMUNIX 50532d19d43Seric 50632d19d43Seric # define DOFORK(fORKfN) \ 50732d19d43Seric {\ 50832d19d43Seric register int i;\ 50932d19d43Seric \ 51011799049Seric for (i = NFORKTRIES; --i >= 0; )\ 51132d19d43Seric {\ 51232d19d43Seric pid = fORKfN();\ 51332d19d43Seric if (pid >= 0)\ 51432d19d43Seric break;\ 51511799049Seric if (i > 0)\ 5166c4635f6Seric sleep((unsigned) NFORKTRIES - i);\ 51732d19d43Seric }\ 51832d19d43Seric } 51932d19d43Seric /* 5202ed72599Seric ** DOFORK -- simple fork interface to DOFORK. 5212ed72599Seric ** 5222ed72599Seric ** Parameters: 5232ed72599Seric ** none. 5242ed72599Seric ** 5252ed72599Seric ** Returns: 5262ed72599Seric ** pid of child in parent. 5272ed72599Seric ** zero in child. 5282ed72599Seric ** -1 on error. 5292ed72599Seric ** 5302ed72599Seric ** Side Effects: 5312ed72599Seric ** returns twice, once in parent and once in child. 5322ed72599Seric */ 5332ed72599Seric 5342ed72599Seric dofork() 5352ed72599Seric { 5362ed72599Seric register int pid; 5372ed72599Seric 5382ed72599Seric DOFORK(fork); 5392ed72599Seric return (pid); 5402ed72599Seric } 5412ed72599Seric /* 5425dfc646bSeric ** SENDOFF -- send off call to mailer & collect response. 5435dfc646bSeric ** 5445dfc646bSeric ** Parameters: 545588cad61Seric ** e -- the envelope to mail. 5465dfc646bSeric ** m -- mailer descriptor. 5475dfc646bSeric ** pvp -- parameter vector to send to it. 5486259796dSeric ** ctladdr -- an address pointer controlling the 5496259796dSeric ** user/groupid etc. of the mailer. 5505dfc646bSeric ** 5515dfc646bSeric ** Returns: 5525dfc646bSeric ** exit status of mailer. 5535dfc646bSeric ** 5545dfc646bSeric ** Side Effects: 5555dfc646bSeric ** none. 5565dfc646bSeric */ 5575dfc646bSeric 55877b52738Seric sendoff(e, m, pvp, ctladdr) 559588cad61Seric register ENVELOPE *e; 560588cad61Seric MAILER *m; 5615dfc646bSeric char **pvp; 5626259796dSeric ADDRESS *ctladdr; 5635dfc646bSeric { 564c579ef51Seric auto FILE *mfile; 565c579ef51Seric auto FILE *rfile; 5665dfc646bSeric register int i; 567c579ef51Seric int pid; 568c579ef51Seric 569c579ef51Seric /* 570c579ef51Seric ** Create connection to mailer. 571c579ef51Seric */ 572c579ef51Seric 573c579ef51Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 574c579ef51Seric if (pid < 0) 575c579ef51Seric return (-1); 576c579ef51Seric 577c579ef51Seric /* 578c579ef51Seric ** Format and send message. 579c579ef51Seric */ 580c579ef51Seric 58177b52738Seric putfromline(mfile, m); 58277b52738Seric (*e->e_puthdr)(mfile, m, e); 58377b52738Seric putline("\n", mfile, m); 58477b52738Seric (*e->e_putbody)(mfile, m, e); 585c579ef51Seric (void) fclose(mfile); 586c579ef51Seric 587c579ef51Seric i = endmailer(pid, pvp[0]); 588bc6e2962Seric 589bc6e2962Seric /* arrange a return receipt if requested */ 59057fc6f17Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 591bc6e2962Seric { 592588cad61Seric e->e_flags |= EF_SENDRECEIPT; 593bc6e2962Seric /* do we want to send back more info? */ 594bc6e2962Seric } 595bc6e2962Seric 596c579ef51Seric return (i); 597c579ef51Seric } 598c579ef51Seric /* 599c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 600c579ef51Seric ** 601c579ef51Seric ** We should never get fatal errors (e.g., segmentation 602c579ef51Seric ** violation), so we report those specially. For other 603c579ef51Seric ** errors, we choose a status message (into statmsg), 604c579ef51Seric ** and if it represents an error, we print it. 605c579ef51Seric ** 606c579ef51Seric ** Parameters: 607c579ef51Seric ** pid -- pid of mailer. 608c579ef51Seric ** name -- name of mailer (for error messages). 609c579ef51Seric ** 610c579ef51Seric ** Returns: 611c579ef51Seric ** exit code of mailer. 612c579ef51Seric ** 613c579ef51Seric ** Side Effects: 614c579ef51Seric ** none. 615c579ef51Seric */ 616c579ef51Seric 617c579ef51Seric endmailer(pid, name) 618c579ef51Seric int pid; 619c579ef51Seric char *name; 620c579ef51Seric { 621588cad61Seric int st; 622c579ef51Seric 62333db8731Seric /* in the IPC case there is nothing to wait for */ 62433db8731Seric if (pid == 0) 62533db8731Seric return (EX_OK); 62633db8731Seric 62733db8731Seric /* wait for the mailer process to die and collect status */ 628588cad61Seric st = waitfor(pid); 629588cad61Seric if (st == -1) 63078de67c1Seric { 631588cad61Seric syserr("endmailer %s: wait", name); 632588cad61Seric return (EX_SOFTWARE); 633c579ef51Seric } 63433db8731Seric 63533db8731Seric /* see if it died a horrid death */ 636c579ef51Seric if ((st & 0377) != 0) 637c579ef51Seric { 6385f73204aSeric syserr("mailer %s died with signal %o", name, st); 6395f73204aSeric ExitStat = EX_TEMPFAIL; 6405f73204aSeric return (EX_TEMPFAIL); 641c579ef51Seric } 64233db8731Seric 64333db8731Seric /* normal death -- return status */ 644588cad61Seric st = (st >> 8) & 0377; 645588cad61Seric return (st); 646c579ef51Seric } 647c579ef51Seric /* 648c579ef51Seric ** OPENMAILER -- open connection to mailer. 649c579ef51Seric ** 650c579ef51Seric ** Parameters: 651c579ef51Seric ** m -- mailer descriptor. 652c579ef51Seric ** pvp -- parameter vector to pass to mailer. 653c579ef51Seric ** ctladdr -- controlling address for user. 654c579ef51Seric ** clever -- create a full duplex connection. 655c579ef51Seric ** pmfile -- pointer to mfile (to mailer) connection. 656c579ef51Seric ** prfile -- pointer to rfile (from mailer) connection. 657c579ef51Seric ** 658c579ef51Seric ** Returns: 65933db8731Seric ** pid of mailer ( > 0 ). 660c579ef51Seric ** -1 on error. 66133db8731Seric ** zero on an IPC connection. 662c579ef51Seric ** 663c579ef51Seric ** Side Effects: 664c579ef51Seric ** creates a mailer in a subprocess. 665c579ef51Seric */ 666c579ef51Seric 667c579ef51Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 668588cad61Seric MAILER *m; 669c579ef51Seric char **pvp; 670c579ef51Seric ADDRESS *ctladdr; 671c579ef51Seric bool clever; 672c579ef51Seric FILE **pmfile; 673c579ef51Seric FILE **prfile; 674c579ef51Seric { 6755dfc646bSeric int pid; 676f8952a83Seric int mpvect[2]; 677c579ef51Seric int rpvect[2]; 6785dfc646bSeric FILE *mfile; 679c579ef51Seric FILE *rfile; 6805dfc646bSeric extern FILE *fdopen(); 6815dfc646bSeric 6825dfc646bSeric # ifdef DEBUG 6836ef48975Seric if (tTd(11, 1)) 6845dfc646bSeric { 6858c57e552Seric printf("openmailer:"); 6865dfc646bSeric printav(pvp); 6875dfc646bSeric } 6885dfc646bSeric # endif DEBUG 68935490626Seric errno = 0; 6905dfc646bSeric 691ef66a9d0Seric CurHostName = m->m_mailer; 692ef66a9d0Seric 69333db8731Seric /* 69433db8731Seric ** Deal with the special case of mail handled through an IPC 69533db8731Seric ** connection. 69633db8731Seric ** In this case we don't actually fork. We must be 69733db8731Seric ** running SMTP for this to work. We will return a 69833db8731Seric ** zero pid to indicate that we are running IPC. 699e7c1bd78Seric ** We also handle a debug version that just talks to stdin/out. 70033db8731Seric */ 70133db8731Seric 702e7c1bd78Seric #ifdef DEBUG 703e7c1bd78Seric /* check for Local Person Communication -- not for mortals!!! */ 704e7c1bd78Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 705e7c1bd78Seric { 706e7c1bd78Seric *pmfile = stdout; 707e7c1bd78Seric *prfile = stdin; 708e7c1bd78Seric return (0); 709e7c1bd78Seric } 710e7c1bd78Seric #endif DEBUG 711e7c1bd78Seric 71233db8731Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 71333db8731Seric { 7145f73204aSeric #ifdef HOSTINFO 7155f73204aSeric register STAB *st; 7165f73204aSeric extern STAB *stab(); 7175f73204aSeric #endif HOSTINFO 718588cad61Seric #ifdef DAEMON 719ebc61751Sbloom register int i, j; 7201277f9a8Seric register u_short port; 72133db8731Seric 722ef66a9d0Seric CurHostName = pvp[1]; 72333db8731Seric if (!clever) 72433db8731Seric syserr("non-clever IPC"); 72593b6e3cfSeric if (pvp[2] != NULL) 7261277f9a8Seric port = atoi(pvp[2]); 72793b6e3cfSeric else 7281277f9a8Seric port = 0; 729f1853fd7Seric for (j = 0; j < Nmx; j++) 730ebc61751Sbloom { 731f1853fd7Seric CurHostName = MxHosts[j]; 7325f73204aSeric #ifdef HOSTINFO 7335f73204aSeric /* see if we have already determined that this host is fried */ 734f1853fd7Seric st = stab(MxHosts[j], ST_HOST, ST_FIND); 7355f73204aSeric if (st == NULL || st->s_host.ho_exitstat == EX_OK) 736f1853fd7Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 7375f73204aSeric else 738ef66a9d0Seric { 7395f73204aSeric i = st->s_host.ho_exitstat; 740ef66a9d0Seric errno = st->s_host.ho_errno; 741ef66a9d0Seric } 7425f73204aSeric #else HOSTINFO 743f1853fd7Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 7445f73204aSeric #endif HOSTINFO 74533db8731Seric if (i != EX_OK) 746ed854c7bSeric { 7475f73204aSeric #ifdef HOSTINFO 7485f73204aSeric /* enter status of this host */ 7495f73204aSeric if (st == NULL) 750f1853fd7Seric st = stab(MxHosts[j], ST_HOST, ST_ENTER); 7515f73204aSeric st->s_host.ho_exitstat = i; 7525f73204aSeric st->s_host.ho_errno = errno; 7535f73204aSeric #endif HOSTINFO 754ed854c7bSeric ExitStat = i; 755ebc61751Sbloom continue; 756ed854c7bSeric } 75733db8731Seric else 75833db8731Seric return (0); 759ebc61751Sbloom } 760ebc61751Sbloom return (-1); 761588cad61Seric #else DAEMON 762588cad61Seric syserr("openmailer: no IPC"); 763588cad61Seric return (-1); 76433db8731Seric #endif DAEMON 765588cad61Seric } 76633db8731Seric 7676328bdf7Seric /* create a pipe to shove the mail through */ 768f8952a83Seric if (pipe(mpvect) < 0) 76925a99e2eSeric { 770588cad61Seric syserr("openmailer: pipe (to mailer)"); 77125a99e2eSeric return (-1); 77225a99e2eSeric } 773c579ef51Seric 7742c7e1b8dSeric #ifdef SMTP 775c579ef51Seric /* if this mailer speaks smtp, create a return pipe */ 776c579ef51Seric if (clever && pipe(rpvect) < 0) 777c579ef51Seric { 778588cad61Seric syserr("openmailer: pipe (from mailer)"); 779c579ef51Seric (void) close(mpvect[0]); 780c579ef51Seric (void) close(mpvect[1]); 781c579ef51Seric return (-1); 782c579ef51Seric } 7832c7e1b8dSeric #endif SMTP 784c579ef51Seric 78533db8731Seric /* 78633db8731Seric ** Actually fork the mailer process. 78733db8731Seric ** DOFORK is clever about retrying. 7886984bfddSeric ** 7896984bfddSeric ** Dispose of SIGCHLD signal catchers that may be laying 7906984bfddSeric ** around so that endmail will get it. 79133db8731Seric */ 79233db8731Seric 7939a6a5f55Seric if (CurEnv->e_xfp != NULL) 7949a6a5f55Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 795588cad61Seric (void) fflush(stdout); 7966984bfddSeric # ifdef SIGCHLD 7976984bfddSeric (void) signal(SIGCHLD, SIG_DFL); 7986984bfddSeric # endif SIGCHLD 79932d19d43Seric DOFORK(XFORK); 800f129ec7dSeric /* pid is set by DOFORK */ 80125a99e2eSeric if (pid < 0) 80225a99e2eSeric { 80333db8731Seric /* failure */ 804588cad61Seric syserr("openmailer: cannot fork"); 805f8952a83Seric (void) close(mpvect[0]); 806f8952a83Seric (void) close(mpvect[1]); 807588cad61Seric #ifdef SMTP 808c579ef51Seric if (clever) 809c579ef51Seric { 810c579ef51Seric (void) close(rpvect[0]); 811c579ef51Seric (void) close(rpvect[1]); 812c579ef51Seric } 813588cad61Seric #endif SMTP 81425a99e2eSeric return (-1); 81525a99e2eSeric } 81625a99e2eSeric else if (pid == 0) 81725a99e2eSeric { 81813088b9fSeric int i; 8195f73204aSeric extern int DtableSize; 82013088b9fSeric 82125a99e2eSeric /* child -- set up input & exec mailer */ 82203ab8e55Seric /* make diagnostic output be standard output */ 8238f0e7860Seric (void) signal(SIGINT, SIG_IGN); 8248f0e7860Seric (void) signal(SIGHUP, SIG_IGN); 8250984da9fSeric (void) signal(SIGTERM, SIG_DFL); 826f8952a83Seric 827f8952a83Seric /* arrange to filter standard & diag output of command */ 828c579ef51Seric if (clever) 829c579ef51Seric { 830c579ef51Seric (void) close(rpvect[0]); 831c579ef51Seric (void) close(1); 832c579ef51Seric (void) dup(rpvect[1]); 833c579ef51Seric (void) close(rpvect[1]); 834c579ef51Seric } 835276723a8Seric else if (OpMode == MD_SMTP || HoldErrs) 836f8952a83Seric { 837588cad61Seric /* put mailer output in transcript */ 838f8952a83Seric (void) close(1); 8399a6a5f55Seric (void) dup(fileno(CurEnv->e_xfp)); 840f8952a83Seric } 841db8841e9Seric (void) close(2); 842db8841e9Seric (void) dup(1); 843f8952a83Seric 844f8952a83Seric /* arrange to get standard input */ 845f8952a83Seric (void) close(mpvect[1]); 846db8841e9Seric (void) close(0); 847f8952a83Seric if (dup(mpvect[0]) < 0) 84825a99e2eSeric { 84925a99e2eSeric syserr("Cannot dup to zero!"); 850a590b978Seric _exit(EX_OSERR); 85125a99e2eSeric } 852f8952a83Seric (void) close(mpvect[0]); 85357fc6f17Seric if (!bitnset(M_RESTR, m->m_flags)) 8540984da9fSeric { 85553e3fa05Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 856e36b99e2Seric { 857e36b99e2Seric (void) setgid(DefGid); 858e36b99e2Seric (void) setuid(DefUid); 859e36b99e2Seric } 860e36b99e2Seric else 86169f29479Seric { 862e36b99e2Seric (void) setgid(ctladdr->q_gid); 863e36b99e2Seric (void) setuid(ctladdr->q_uid); 86469f29479Seric } 8650984da9fSeric } 866588cad61Seric 86713088b9fSeric /* arrange for all the files to be closed */ 8685f73204aSeric for (i = 3; i < DtableSize; i++) 86913088b9fSeric #ifdef FIOCLEX 87013088b9fSeric (void) ioctl(i, FIOCLEX, 0); 87113088b9fSeric #else FIOCLEX 87213088b9fSeric (void) close(i); 87313088b9fSeric #endif FIOCLEX 87433db8731Seric 87533db8731Seric /* try to execute the mailer */ 8765df317aaSeric execve(m->m_mailer, pvp, UserEnviron); 87733db8731Seric 87813088b9fSeric #ifdef FIOCLEX 87913088b9fSeric syserr("Cannot exec %s", m->m_mailer); 88013088b9fSeric #else FIOCLEX 88132d19d43Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 882db8841e9Seric (void) fflush(stdout); 88313088b9fSeric #endif FIOCLEX 8845f73204aSeric if (m == LocalMailer || errno == EIO || errno == EAGAIN || 8855f73204aSeric errno == ENOMEM || errno == EPROCLIM) 88655f33c03Seric _exit(EX_TEMPFAIL); 88755f33c03Seric else 888a590b978Seric _exit(EX_UNAVAILABLE); 88925a99e2eSeric } 89025a99e2eSeric 891f8952a83Seric /* 892c579ef51Seric ** Set up return value. 893f8952a83Seric */ 894f8952a83Seric 895f8952a83Seric (void) close(mpvect[0]); 896f8952a83Seric mfile = fdopen(mpvect[1], "w"); 897c579ef51Seric if (clever) 89825a99e2eSeric { 899c579ef51Seric (void) close(rpvect[1]); 900c579ef51Seric rfile = fdopen(rpvect[0], "r"); 90125a99e2eSeric } 902c579ef51Seric 903c579ef51Seric *pmfile = mfile; 904c579ef51Seric *prfile = rfile; 905c579ef51Seric 906c579ef51Seric return (pid); 90725a99e2eSeric } 90825a99e2eSeric /* 90925a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 91025a99e2eSeric ** 91125a99e2eSeric ** Parameters: 91225a99e2eSeric ** stat -- the status code from the mailer (high byte 91325a99e2eSeric ** only; core dumps must have been taken care of 91425a99e2eSeric ** already). 91525a99e2eSeric ** m -- the mailer descriptor for this mailer. 91625a99e2eSeric ** 91725a99e2eSeric ** Returns: 918db8841e9Seric ** none. 91925a99e2eSeric ** 92025a99e2eSeric ** Side Effects: 921c1f9df2cSeric ** Errors may be incremented. 92225a99e2eSeric ** ExitStat may be set. 92325a99e2eSeric */ 92425a99e2eSeric 925198d9be0Seric giveresponse(stat, m, e) 92625a99e2eSeric int stat; 927588cad61Seric register MAILER *m; 928198d9be0Seric ENVELOPE *e; 92925a99e2eSeric { 93025a99e2eSeric register char *statmsg; 93125a99e2eSeric extern char *SysExMsg[]; 93225a99e2eSeric register int i; 9338f22b66bSbostic extern int N_SysEx, h_errno; 934198d9be0Seric char buf[MAXLINE]; 93525a99e2eSeric 9367d1fc79dSeric #ifdef lint 9377d1fc79dSeric if (m == NULL) 9387d1fc79dSeric return; 9397d1fc79dSeric #endif lint 9407d1fc79dSeric 94113bbc08cSeric /* 94213bbc08cSeric ** Compute status message from code. 94313bbc08cSeric */ 94413bbc08cSeric 94525a99e2eSeric i = stat - EX__BASE; 946588cad61Seric if (stat == 0) 947588cad61Seric statmsg = "250 Sent"; 948588cad61Seric else if (i < 0 || i > N_SysEx) 949588cad61Seric { 950588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 951588cad61Seric stat = EX_UNAVAILABLE; 952588cad61Seric statmsg = buf; 953588cad61Seric } 954198d9be0Seric else if (stat == EX_TEMPFAIL) 955198d9be0Seric { 9568557d168Seric (void) strcpy(buf, SysExMsg[i]); 957f28da541Smiriam if (h_errno == TRY_AGAIN) 958f28da541Smiriam { 959f28da541Smiriam extern char *errstring(); 960f28da541Smiriam 961f28da541Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 962f28da541Smiriam } 963f28da541Smiriam else 964f28da541Smiriam { 9658557d168Seric if (errno != 0) 966198d9be0Seric { 96787c9b3e7Seric extern char *errstring(); 9688557d168Seric 969d87e85f3Seric statmsg = errstring(errno); 970d87e85f3Seric } 971d87e85f3Seric else 972d87e85f3Seric { 973d87e85f3Seric #ifdef SMTP 974d87e85f3Seric extern char SmtpError[]; 975d87e85f3Seric 976d87e85f3Seric statmsg = SmtpError; 977d87e85f3Seric #else SMTP 978d87e85f3Seric statmsg = NULL; 979d87e85f3Seric #endif SMTP 980d87e85f3Seric } 981f28da541Smiriam } 982d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 983d87e85f3Seric { 98487c9b3e7Seric (void) strcat(buf, ": "); 985d87e85f3Seric (void) strcat(buf, statmsg); 9868557d168Seric } 987198d9be0Seric statmsg = buf; 988198d9be0Seric } 98925a99e2eSeric else 990d87e85f3Seric { 99125a99e2eSeric statmsg = SysExMsg[i]; 992d87e85f3Seric } 993588cad61Seric 994588cad61Seric /* 995588cad61Seric ** Print the message as appropriate 996588cad61Seric */ 997588cad61Seric 998198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 9995826d9d3Seric message(Arpa_Info, &statmsg[4]); 100025a99e2eSeric else 100125a99e2eSeric { 1002c1f9df2cSeric Errors++; 10035826d9d3Seric usrerr(statmsg); 100425a99e2eSeric } 100525a99e2eSeric 100625a99e2eSeric /* 100725a99e2eSeric ** Final cleanup. 100825a99e2eSeric ** Log a record of the transaction. Compute the new 100925a99e2eSeric ** ExitStat -- if we already had an error, stick with 101025a99e2eSeric ** that. 101125a99e2eSeric */ 101225a99e2eSeric 101361f5a1d4Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 1014eb238f8cSeric logdelivery(&statmsg[4]); 1015eb238f8cSeric 1016eb238f8cSeric if (stat != EX_TEMPFAIL) 1017eb238f8cSeric setstat(stat); 1018198d9be0Seric if (stat != EX_OK) 1019198d9be0Seric { 1020198d9be0Seric if (e->e_message != NULL) 1021198d9be0Seric free(e->e_message); 1022198d9be0Seric e->e_message = newstr(&statmsg[4]); 1023198d9be0Seric } 10248557d168Seric errno = 0; 1025f28da541Smiriam h_errno = 0; 1026eb238f8cSeric } 1027eb238f8cSeric /* 1028eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1029eb238f8cSeric ** 1030eb238f8cSeric ** Parameters: 1031eb238f8cSeric ** stat -- the message to print for the status 1032eb238f8cSeric ** 1033eb238f8cSeric ** Returns: 1034eb238f8cSeric ** none 1035eb238f8cSeric ** 1036eb238f8cSeric ** Side Effects: 1037eb238f8cSeric ** none 1038eb238f8cSeric */ 1039eb238f8cSeric 1040eb238f8cSeric logdelivery(stat) 1041eb238f8cSeric char *stat; 10425cf56be3Seric { 10435cf56be3Seric extern char *pintvl(); 10445cf56be3Seric 1045eb238f8cSeric # ifdef LOG 10465cf56be3Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 1047eb238f8cSeric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 104825a99e2eSeric # endif LOG 104925a99e2eSeric } 105025a99e2eSeric /* 105151552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 105225a99e2eSeric ** 105351552439Seric ** This can be made an arbitrary message separator by changing $l 105451552439Seric ** 10559b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 10569b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 10579b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 10589b6c17a6Seric ** this kind of antique garbage???? 105925a99e2eSeric ** 106025a99e2eSeric ** Parameters: 106151552439Seric ** fp -- the file to output to. 106251552439Seric ** m -- the mailer describing this entry. 106325a99e2eSeric ** 106425a99e2eSeric ** Returns: 106551552439Seric ** none 106625a99e2eSeric ** 106725a99e2eSeric ** Side Effects: 106851552439Seric ** outputs some text to fp. 106925a99e2eSeric */ 107025a99e2eSeric 107177b52738Seric putfromline(fp, m) 107251552439Seric register FILE *fp; 107351552439Seric register MAILER *m; 107425a99e2eSeric { 10759b6c17a6Seric char *template = "\001l\n"; 107651552439Seric char buf[MAXLINE]; 107725a99e2eSeric 107857fc6f17Seric if (bitnset(M_NHDR, m->m_flags)) 107951552439Seric return; 108013bbc08cSeric 10812c7e1b8dSeric # ifdef UGLYUUCP 108257fc6f17Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 108374b6e67bSeric { 1084ea09d6edSeric char *bang; 1085ea09d6edSeric char xbuf[MAXLINE]; 108674b6e67bSeric 10879b6c17a6Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 1088ea09d6edSeric bang = index(buf, '!'); 108974b6e67bSeric if (bang == NULL) 1090ea09d6edSeric syserr("No ! in UUCP! (%s)", buf); 109174b6e67bSeric else 1092588cad61Seric { 1093ea09d6edSeric *bang++ = '\0'; 10949b6c17a6Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 1095ea09d6edSeric template = xbuf; 109674b6e67bSeric } 1097588cad61Seric } 10982c7e1b8dSeric # endif UGLYUUCP 1099ea09d6edSeric expand(template, buf, &buf[sizeof buf - 1], CurEnv); 110077b52738Seric putline(buf, fp, m); 1101bc6e2962Seric } 1102bc6e2962Seric /* 110351552439Seric ** PUTBODY -- put the body of a message. 110451552439Seric ** 110551552439Seric ** Parameters: 110651552439Seric ** fp -- file to output onto. 110777b52738Seric ** m -- a mailer descriptor to control output format. 11089a6a5f55Seric ** e -- the envelope to put out. 110951552439Seric ** 111051552439Seric ** Returns: 111151552439Seric ** none. 111251552439Seric ** 111351552439Seric ** Side Effects: 111451552439Seric ** The message is written onto fp. 111551552439Seric */ 111651552439Seric 111777b52738Seric putbody(fp, m, e) 111851552439Seric FILE *fp; 1119588cad61Seric MAILER *m; 11209a6a5f55Seric register ENVELOPE *e; 112151552439Seric { 112277b52738Seric char buf[MAXLINE]; 112351552439Seric 112451552439Seric /* 112551552439Seric ** Output the body of the message 112651552439Seric */ 112751552439Seric 11289a6a5f55Seric if (e->e_dfp == NULL) 112951552439Seric { 11309a6a5f55Seric if (e->e_df != NULL) 11319a6a5f55Seric { 11329a6a5f55Seric e->e_dfp = fopen(e->e_df, "r"); 11339a6a5f55Seric if (e->e_dfp == NULL) 11349a6a5f55Seric syserr("Cannot open %s", e->e_df); 11359a6a5f55Seric } 11369a6a5f55Seric else 113777b52738Seric putline("<<< No Message Collected >>>", fp, m); 11389a6a5f55Seric } 11399a6a5f55Seric if (e->e_dfp != NULL) 11409a6a5f55Seric { 11419a6a5f55Seric rewind(e->e_dfp); 114277b52738Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 114324fc8aeeSeric { 114424fc8aeeSeric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 114524fc8aeeSeric strncmp(buf, "From", 4) == 0) 11463462ad9eSeric (void) putc('>', fp); 114777b52738Seric putline(buf, fp, m); 114824fc8aeeSeric } 114951552439Seric 11509a6a5f55Seric if (ferror(e->e_dfp)) 115151552439Seric { 115251552439Seric syserr("putbody: read error"); 115351552439Seric ExitStat = EX_IOERR; 115451552439Seric } 115551552439Seric } 115651552439Seric 115751552439Seric (void) fflush(fp); 115851552439Seric if (ferror(fp) && errno != EPIPE) 115951552439Seric { 116051552439Seric syserr("putbody: write error"); 116151552439Seric ExitStat = EX_IOERR; 116251552439Seric } 116351552439Seric errno = 0; 116425a99e2eSeric } 116525a99e2eSeric /* 116625a99e2eSeric ** MAILFILE -- Send a message to a file. 116725a99e2eSeric ** 1168f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 1169f129ec7dSeric ** bits, sendmail will try to become the owner of that file 1170f129ec7dSeric ** rather than the real user. Obviously, this only works if 1171f129ec7dSeric ** sendmail runs as root. 1172f129ec7dSeric ** 1173588cad61Seric ** This could be done as a subordinate mailer, except that it 1174588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 1175588cad61Seric ** view this as being sufficiently important as to include it 1176588cad61Seric ** here. For example, if the system is dying, we shouldn't have 1177588cad61Seric ** to create another process plus some pipes to save the message. 1178588cad61Seric ** 117925a99e2eSeric ** Parameters: 118025a99e2eSeric ** filename -- the name of the file to send to. 11816259796dSeric ** ctladdr -- the controlling address header -- includes 11826259796dSeric ** the userid/groupid to be when sending. 118325a99e2eSeric ** 118425a99e2eSeric ** Returns: 118525a99e2eSeric ** The exit code associated with the operation. 118625a99e2eSeric ** 118725a99e2eSeric ** Side Effects: 118825a99e2eSeric ** none. 118925a99e2eSeric */ 119025a99e2eSeric 11916259796dSeric mailfile(filename, ctladdr) 119225a99e2eSeric char *filename; 11936259796dSeric ADDRESS *ctladdr; 119425a99e2eSeric { 119525a99e2eSeric register FILE *f; 119632d19d43Seric register int pid; 119725a99e2eSeric 119832d19d43Seric /* 119932d19d43Seric ** Fork so we can change permissions here. 120032d19d43Seric ** Note that we MUST use fork, not vfork, because of 120132d19d43Seric ** the complications of calling subroutines, etc. 120232d19d43Seric */ 120332d19d43Seric 120432d19d43Seric DOFORK(fork); 120532d19d43Seric 120632d19d43Seric if (pid < 0) 120732d19d43Seric return (EX_OSERR); 120832d19d43Seric else if (pid == 0) 120932d19d43Seric { 121032d19d43Seric /* child -- actually write to file */ 1211f129ec7dSeric struct stat stb; 1212f129ec7dSeric 12130984da9fSeric (void) signal(SIGINT, SIG_DFL); 12140984da9fSeric (void) signal(SIGHUP, SIG_DFL); 12150984da9fSeric (void) signal(SIGTERM, SIG_DFL); 12163462ad9eSeric (void) umask(OldUmask); 1217f129ec7dSeric if (stat(filename, &stb) < 0) 121824447f54Seric { 121924447f54Seric errno = 0; 1220e6e1265fSeric stb.st_mode = 0666; 122124447f54Seric } 1222f129ec7dSeric if (bitset(0111, stb.st_mode)) 1223f129ec7dSeric exit(EX_CANTCREAT); 122403827b5fSeric if (ctladdr == NULL) 12257a941e7aSeric ctladdr = &CurEnv->e_from; 1226f129ec7dSeric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 1227e36b99e2Seric { 1228e36b99e2Seric if (ctladdr->q_uid == 0) 1229e36b99e2Seric (void) setgid(DefGid); 1230e36b99e2Seric else 12316259796dSeric (void) setgid(ctladdr->q_gid); 1232e36b99e2Seric } 1233f129ec7dSeric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 1234e36b99e2Seric { 1235e36b99e2Seric if (ctladdr->q_uid == 0) 1236e36b99e2Seric (void) setuid(DefUid); 1237e36b99e2Seric else 12386259796dSeric (void) setuid(ctladdr->q_uid); 1239e36b99e2Seric } 124027628d59Seric f = dfopen(filename, "a"); 124125a99e2eSeric if (f == NULL) 124232d19d43Seric exit(EX_CANTCREAT); 124325a99e2eSeric 124477b52738Seric putfromline(f, ProgMailer); 124577b52738Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 124677b52738Seric putline("\n", f, ProgMailer); 124777b52738Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 124877b52738Seric putline("\n", f, ProgMailer); 1249db8841e9Seric (void) fclose(f); 125032d19d43Seric (void) fflush(stdout); 1251e36b99e2Seric 125227628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 1253c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 125432d19d43Seric exit(EX_OK); 125513bbc08cSeric /*NOTREACHED*/ 125632d19d43Seric } 125732d19d43Seric else 125832d19d43Seric { 125932d19d43Seric /* parent -- wait for exit status */ 1260588cad61Seric int st; 126132d19d43Seric 1262588cad61Seric st = waitfor(pid); 1263588cad61Seric if ((st & 0377) != 0) 1264588cad61Seric return (EX_UNAVAILABLE); 1265588cad61Seric else 1266588cad61Seric return ((st >> 8) & 0377); 126732d19d43Seric } 126825a99e2eSeric } 1269ea4dc939Seric /* 1270ea4dc939Seric ** SENDALL -- actually send all the messages. 1271ea4dc939Seric ** 1272ea4dc939Seric ** Parameters: 12730c52a0b3Seric ** e -- the envelope to send. 12747b95031aSeric ** mode -- the delivery mode to use. If SM_DEFAULT, use 12757b95031aSeric ** the current SendMode. 1276ea4dc939Seric ** 1277ea4dc939Seric ** Returns: 1278ea4dc939Seric ** none. 1279ea4dc939Seric ** 1280ea4dc939Seric ** Side Effects: 1281ea4dc939Seric ** Scans the send lists and sends everything it finds. 12820c52a0b3Seric ** Delivers any appropriate error messages. 1283276723a8Seric ** If we are running in a non-interactive mode, takes the 1284276723a8Seric ** appropriate action. 1285ea4dc939Seric */ 1286ea4dc939Seric 1287276723a8Seric sendall(e, mode) 12880c52a0b3Seric ENVELOPE *e; 1289276723a8Seric char mode; 1290ea4dc939Seric { 1291e77e673fSeric register ADDRESS *q; 129214a8ed7aSeric bool oldverbose; 1293276723a8Seric int pid; 1294ea4dc939Seric 12957b95031aSeric /* determine actual delivery mode */ 12967b95031aSeric if (mode == SM_DEFAULT) 12977b95031aSeric { 12985f73204aSeric extern bool shouldqueue(); 12997b95031aSeric 13005f73204aSeric if (shouldqueue(e->e_msgpriority)) 13017b95031aSeric mode = SM_QUEUE; 13027b95031aSeric else 13037b95031aSeric mode = SendMode; 13047b95031aSeric } 13057b95031aSeric 1306772e6e50Seric #ifdef DEBUG 1307df864a8fSeric if (tTd(13, 1)) 1308772e6e50Seric { 1309276723a8Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 13100c52a0b3Seric printaddr(e->e_sendqueue, TRUE); 1311772e6e50Seric } 1312772e6e50Seric #endif DEBUG 1313ea4dc939Seric 13140c52a0b3Seric /* 1315276723a8Seric ** Do any preprocessing necessary for the mode we are running. 1316588cad61Seric ** Check to make sure the hop count is reasonable. 1317588cad61Seric ** Delete sends to the sender in mailing lists. 1318276723a8Seric */ 1319276723a8Seric 1320588cad61Seric CurEnv = e; 1321276723a8Seric 1322588cad61Seric if (e->e_hopcount > MAXHOP) 1323276723a8Seric { 1324588cad61Seric syserr("sendall: too many hops (%d max)", MAXHOP); 1325588cad61Seric return; 1326588cad61Seric } 1327588cad61Seric 1328588cad61Seric if (!MeToo) 1329276723a8Seric { 1330f3d6c55cSeric extern ADDRESS *recipient(); 1331f3d6c55cSeric 1332588cad61Seric e->e_from.q_flags |= QDONTSEND; 1333f3d6c55cSeric (void) recipient(&e->e_from, &e->e_sendqueue); 1334276723a8Seric } 1335588cad61Seric 1336588cad61Seric # ifdef QUEUE 1337b254bcb6Seric if ((mode == SM_QUEUE || mode == SM_FORK || 1338b254bcb6Seric (mode != SM_VERIFY && SuperSafe)) && 1339b254bcb6Seric !bitset(EF_INQUEUE, e->e_flags)) 1340588cad61Seric queueup(e, TRUE, mode == SM_QUEUE); 1341276723a8Seric #endif QUEUE 1342276723a8Seric 1343276723a8Seric oldverbose = Verbose; 1344276723a8Seric switch (mode) 1345276723a8Seric { 1346276723a8Seric case SM_VERIFY: 1347276723a8Seric Verbose = TRUE; 1348276723a8Seric break; 1349276723a8Seric 1350276723a8Seric case SM_QUEUE: 1351b254bcb6Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 1352276723a8Seric return; 1353276723a8Seric 1354276723a8Seric case SM_FORK: 13559a6a5f55Seric if (e->e_xfp != NULL) 13569a6a5f55Seric (void) fflush(e->e_xfp); 1357276723a8Seric pid = fork(); 1358276723a8Seric if (pid < 0) 1359276723a8Seric { 1360276723a8Seric mode = SM_DELIVER; 1361276723a8Seric break; 1362276723a8Seric } 1363276723a8Seric else if (pid > 0) 1364a6fce3d8Seric { 1365a6fce3d8Seric /* be sure we leave the temp files to our child */ 1366b254bcb6Seric e->e_id = e->e_df = NULL; 1367276723a8Seric return; 1368a6fce3d8Seric } 1369276723a8Seric 1370276723a8Seric /* double fork to avoid zombies */ 1371276723a8Seric if (fork() > 0) 1372276723a8Seric exit(EX_OK); 1373276723a8Seric 1374a6fce3d8Seric /* be sure we are immune from the terminal */ 1375769e215aSeric disconnect(FALSE); 1376a6fce3d8Seric 1377276723a8Seric break; 1378276723a8Seric } 1379276723a8Seric 1380276723a8Seric /* 13810c52a0b3Seric ** Run through the list and send everything. 13820c52a0b3Seric */ 13830c52a0b3Seric 13840c52a0b3Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1385ea4dc939Seric { 1386276723a8Seric if (mode == SM_VERIFY) 1387ea4dc939Seric { 1388a6fce3d8Seric e->e_to = q->q_paddr; 1389e77e673fSeric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 1390ea4dc939Seric message(Arpa_Info, "deliverable"); 1391ea4dc939Seric } 1392ea4dc939Seric else 1393588cad61Seric (void) deliver(e, q); 1394ea4dc939Seric } 139514a8ed7aSeric Verbose = oldverbose; 13960c52a0b3Seric 13970c52a0b3Seric /* 13980c52a0b3Seric ** Now run through and check for errors. 13990c52a0b3Seric */ 14000c52a0b3Seric 1401276723a8Seric if (mode == SM_VERIFY) 14020c52a0b3Seric return; 14030c52a0b3Seric 14040c52a0b3Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14050c52a0b3Seric { 14060c52a0b3Seric register ADDRESS *qq; 14070c52a0b3Seric 1408df864a8fSeric # ifdef DEBUG 1409df864a8fSeric if (tTd(13, 3)) 1410df864a8fSeric { 1411df864a8fSeric printf("Checking "); 1412df864a8fSeric printaddr(q, FALSE); 1413df864a8fSeric } 1414df864a8fSeric # endif DEBUG 1415df864a8fSeric 1416b254bcb6Seric /* only send errors if the message failed */ 1417b254bcb6Seric if (!bitset(QBADADDR, q->q_flags)) 1418b254bcb6Seric continue; 14190c52a0b3Seric 14200c52a0b3Seric /* we have an address that failed -- find the parent */ 14210c52a0b3Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14220c52a0b3Seric { 14230c52a0b3Seric char obuf[MAXNAME + 6]; 14240c52a0b3Seric extern char *aliaslookup(); 14250c52a0b3Seric 14260c52a0b3Seric /* we can only have owners for local addresses */ 142757fc6f17Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 14280c52a0b3Seric continue; 14290c52a0b3Seric 14300c52a0b3Seric /* see if the owner list exists */ 14310c52a0b3Seric (void) strcpy(obuf, "owner-"); 1432cec031e3Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 1433cec031e3Seric (void) strcat(obuf, "owner"); 1434cec031e3Seric else 14350c52a0b3Seric (void) strcat(obuf, qq->q_user); 14360c52a0b3Seric if (aliaslookup(obuf) == NULL) 14370c52a0b3Seric continue; 14380c52a0b3Seric 1439df864a8fSeric # ifdef DEBUG 1440df864a8fSeric if (tTd(13, 4)) 1441df864a8fSeric printf("Errors to %s\n", obuf); 1442df864a8fSeric # endif DEBUG 1443df864a8fSeric 14440c52a0b3Seric /* owner list exists -- add it to the error queue */ 1445e3e4ed86Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 144653e3fa05Seric ErrorMode = EM_MAIL; 14470c52a0b3Seric break; 14480c52a0b3Seric } 14490c52a0b3Seric 14500c52a0b3Seric /* if we did not find an owner, send to the sender */ 14517455aa0bSeric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 1452e3e4ed86Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 14530c52a0b3Seric } 1454276723a8Seric 1455276723a8Seric if (mode == SM_FORK) 1456276723a8Seric finis(); 14570c52a0b3Seric } 1458