122701Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 633728Sbostic * Redistribution and use in source and binary forms are permitted 734920Sbostic * provided that the above copyright notice and this paragraph are 834920Sbostic * duplicated in all such forms and that any documentation, 934920Sbostic * advertising materials, and other materials related to such 1034920Sbostic * distribution and use acknowledge that the software was developed 1134920Sbostic * by the University of California, Berkeley. The name of the 1234920Sbostic * University may not be used to endorse or promote products derived 1334920Sbostic * from this software without specific prior written permission. 1434920Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1534920Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1634920Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1733728Sbostic */ 1822701Sdist 1922701Sdist #ifndef lint 20*40992Sbostic static char sccsid[] = "@(#)deliver.c 5.33 (Berkeley) 04/19/90"; 2133728Sbostic #endif /* not lint */ 2222701Sdist 2340961Sbostic #include "sendmail.h" 2433931Sbostic #include <sys/signal.h> 2533931Sbostic #include <sys/stat.h> 2633931Sbostic #include <netdb.h> 2736030Sbostic #include <fcntl.h> 2833931Sbostic #include <errno.h> 2935651Seric #ifdef NAMED_BIND 3034022Sbostic #include <arpa/nameser.h> 3134022Sbostic #include <resolv.h> 3235651Seric #endif 33294Seric 34294Seric /* 354315Seric ** DELIVER -- Deliver a message to a list of addresses. 36294Seric ** 374315Seric ** This routine delivers to everyone on the same host as the 384315Seric ** user on the head of the list. It is clever about mailers 394315Seric ** that don't handle multiple users. It is NOT guaranteed 404315Seric ** that it will deliver to all these addresses however -- so 414315Seric ** deliver should be called once for each address on the 424315Seric ** list. 434315Seric ** 44294Seric ** Parameters: 459370Seric ** e -- the envelope to deliver. 464621Seric ** firstto -- head of the address list to deliver to. 47294Seric ** 48294Seric ** Returns: 49294Seric ** zero -- successfully delivered. 50294Seric ** else -- some failure, see ExitStat for more info. 51294Seric ** 52294Seric ** Side Effects: 53294Seric ** The standard input is passed off to someone. 54294Seric */ 55294Seric 569370Seric deliver(e, firstto) 579370Seric register ENVELOPE *e; 584621Seric ADDRESS *firstto; 59294Seric { 604452Seric char *host; /* host being sent to */ 614452Seric char *user; /* user being sent to */ 62294Seric char **pvp; 633233Seric register char **mvp; 643233Seric register char *p; 6510306Seric register MAILER *m; /* mailer for this recipient */ 664397Seric ADDRESS *ctladdr; 674621Seric register ADDRESS *to = firstto; 684863Seric bool clever = FALSE; /* running user smtp to this mailer */ 695032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 7033931Sbostic int rcode; /* response code */ 7110306Seric char *pv[MAXPV+1]; 7210306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 7310306Seric char buf[MAXNAME]; 7410306Seric char tfrombuf[MAXNAME]; /* translated from person */ 7510306Seric extern bool checkcompat(); 7610306Seric extern ADDRESS *getctladdr(); 7710306Seric extern char *remotename(); 78294Seric 794488Seric errno = 0; 807052Seric if (bitset(QDONTSEND, to->q_flags)) 813233Seric return (0); 82294Seric 8335651Seric #ifdef NAMED_BIND 8434022Sbostic /* unless interactive, try twice, over a minute */ 8534022Sbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 8634022Sbostic _res.retrans = 30; 8734022Sbostic _res.retry = 2; 8834022Sbostic } 8936788Sbostic #endif 9034022Sbostic 916974Seric m = to->q_mailer; 926974Seric host = to->q_host; 936974Seric 947672Seric if (tTd(10, 1)) 953233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 966974Seric m->m_mno, host, to->q_user); 97294Seric 98294Seric /* 995903Seric ** If this mailer is expensive, and if we don't want to make 1005903Seric ** connections now, just mark these addresses and return. 1015903Seric ** This is useful if we want to batch connections to 1025903Seric ** reduce load. This will cause the messages to be 1035903Seric ** queued up, and a daemon will come along to send the 1045903Seric ** messages later. 1055903Seric ** This should be on a per-mailer basis. 1065903Seric */ 1075903Seric 10810682Seric if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && 1098428Seric !Verbose) 1105903Seric { 1115903Seric for (; to != NULL; to = to->q_next) 1128431Seric { 1138431Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 1148431Seric continue; 1158431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 1169370Seric e->e_to = to->q_paddr; 1178496Seric message(Arpa_Info, "queued"); 1188496Seric if (LogLevel > 4) 1198496Seric logdelivery("queued"); 1208431Seric } 1219370Seric e->e_to = NULL; 1225903Seric return (0); 1235903Seric } 1245903Seric 1255903Seric /* 1263233Seric ** Do initial argv setup. 1273233Seric ** Insert the mailer name. Notice that $x expansion is 1283233Seric ** NOT done on the mailer name. Then, if the mailer has 1293233Seric ** a picky -f flag, we insert it as appropriate. This 1303233Seric ** code does not check for 'pv' overflow; this places a 1313233Seric ** manifest lower limit of 4 for MAXPV. 1328062Seric ** The from address rewrite is expected to make 1338062Seric ** the address relative to the other end. 1342968Seric */ 1352968Seric 1364452Seric /* rewrite from address, using rewriting rules */ 13716150Seric expand("\001f", buf, &buf[sizeof buf - 1], e); 13810306Seric (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); 1394452Seric 1409370Seric define('g', tfrombuf, e); /* translated sender address */ 1419370Seric define('h', host, e); /* to host */ 1423233Seric Errors = 0; 1433233Seric pvp = pv; 1443233Seric *pvp++ = m->m_argv[0]; 1452968Seric 1463233Seric /* insert -f or -r flag as appropriate */ 14710682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1483233Seric { 14910682Seric if (bitnset(M_FOPT, m->m_flags)) 1503233Seric *pvp++ = "-f"; 1513233Seric else 1523233Seric *pvp++ = "-r"; 15316150Seric expand("\001g", buf, &buf[sizeof buf - 1], e); 1543233Seric *pvp++ = newstr(buf); 1553233Seric } 156294Seric 157294Seric /* 1583233Seric ** Append the other fixed parts of the argv. These run 1593233Seric ** up to the first entry containing "$u". There can only 1603233Seric ** be one of these, and there are only a few more slots 1613233Seric ** in the pv after it. 162294Seric */ 163294Seric 1643233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 165294Seric { 16616150Seric while ((p = index(p, '\001')) != NULL) 1673233Seric if (*++p == 'u') 1683233Seric break; 1693233Seric if (p != NULL) 1703233Seric break; 1713233Seric 1723233Seric /* this entry is safe -- go ahead and process it */ 1739370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1743233Seric *pvp++ = newstr(buf); 1753233Seric if (pvp >= &pv[MAXPV - 3]) 1763233Seric { 1773233Seric syserr("Too many parameters to %s before $u", pv[0]); 1783233Seric return (-1); 1793233Seric } 180294Seric } 1814863Seric 1826038Seric /* 1836038Seric ** If we have no substitution for the user name in the argument 1846038Seric ** list, we know that we must supply the names otherwise -- and 1856038Seric ** SMTP is the answer!! 1866038Seric */ 1876038Seric 1883233Seric if (*mvp == NULL) 1894863Seric { 1904863Seric /* running SMTP */ 1915179Seric # ifdef SMTP 1924863Seric clever = TRUE; 1934863Seric *pvp = NULL; 1945179Seric # else SMTP 1956038Seric /* oops! we don't implement SMTP */ 1965179Seric syserr("SMTP style mailer"); 1975179Seric return (EX_SOFTWARE); 1985179Seric # endif SMTP 1994863Seric } 200294Seric 201294Seric /* 2023233Seric ** At this point *mvp points to the argument with $u. We 2033233Seric ** run through our address list and append all the addresses 2043233Seric ** we can. If we run out of space, do not fret! We can 2053233Seric ** always send another copy later. 206294Seric */ 207294Seric 2083233Seric tobuf[0] = '\0'; 2099370Seric e->e_to = tobuf; 2104397Seric ctladdr = NULL; 2113233Seric for (; to != NULL; to = to->q_next) 212294Seric { 2133233Seric /* avoid sending multiple recipients to dumb mailers */ 21410682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 2153233Seric break; 2163233Seric 2173233Seric /* if already sent or not for this host, don't send */ 2187052Seric if (bitset(QDONTSEND, to->q_flags) || 2197052Seric strcmp(to->q_host, host) != 0 || 2207052Seric to->q_mailer != firstto->q_mailer) 2213233Seric continue; 2224397Seric 2238225Seric /* avoid overflowing tobuf */ 2249370Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 2258225Seric break; 2268225Seric 2277672Seric if (tTd(10, 1)) 2285032Seric { 2295032Seric printf("\nsend to "); 2305032Seric printaddr(to, FALSE); 2315032Seric } 2325032Seric 2334397Seric /* compute effective uid/gid when sending */ 2344596Seric if (to->q_mailer == ProgMailer) 2354397Seric ctladdr = getctladdr(to); 2364397Seric 2373233Seric user = to->q_user; 2389370Seric e->e_to = to->q_paddr; 2393233Seric to->q_flags |= QDONTSEND; 2403233Seric 2413233Seric /* 2423233Seric ** Check to see that these people are allowed to 2433233Seric ** talk to each other. 2443233Seric */ 2453233Seric 24610699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 24710699Seric { 24829914Seric NoReturn = TRUE; 24910699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 25010699Seric giveresponse(EX_UNAVAILABLE, m, e); 25110699Seric continue; 25210699Seric } 2533233Seric if (!checkcompat(to)) 254294Seric { 25510105Seric giveresponse(EX_UNAVAILABLE, m, e); 2563233Seric continue; 257294Seric } 2583233Seric 2593233Seric /* 2604099Seric ** Strip quote bits from names if the mailer is dumb 2614099Seric ** about them. 2623233Seric */ 2633233Seric 26410682Seric if (bitnset(M_STRIPQ, m->m_flags)) 265294Seric { 2664099Seric stripquotes(user, TRUE); 2674099Seric stripquotes(host, TRUE); 2683233Seric } 2694099Seric else 2704099Seric { 2714099Seric stripquotes(user, FALSE); 2724099Seric stripquotes(host, FALSE); 2734099Seric } 2743233Seric 2759206Seric /* hack attack -- delivermail compatibility */ 2769206Seric if (m == ProgMailer && *user == '|') 2779206Seric user++; 2789206Seric 2793233Seric /* 2804161Seric ** If an error message has already been given, don't 2814161Seric ** bother to send to this address. 2824161Seric ** 2834161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2844161Seric ** >> NOTE >> cannot do any further aliasing; that 2854161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2864161Seric */ 2874161Seric 2887293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2894161Seric continue; 2904161Seric 2914283Seric /* save statistics.... */ 2929370Seric markstats(e, to); 2934283Seric 2944161Seric /* 2953233Seric ** See if this user name is "special". 2963233Seric ** If the user name has a slash in it, assume that this 2976974Seric ** is a file -- send it off without further ado. Note 2986974Seric ** that this type of addresses is not processed along 2996974Seric ** with the others, so we fudge on the To person. 3003233Seric */ 3013233Seric 3024596Seric if (m == LocalMailer) 3033233Seric { 3045599Seric if (user[0] == '/') 305294Seric { 3068003Seric rcode = mailfile(user, getctladdr(to)); 30710105Seric giveresponse(rcode, m, e); 3083233Seric continue; 309294Seric } 310294Seric } 3113233Seric 3124315Seric /* 3134315Seric ** Address is verified -- add this user to mailer 3144315Seric ** argv, and add it to the print list of recipients. 3154315Seric */ 3164315Seric 3176059Seric /* link together the chain of recipients */ 3186272Seric to->q_tchain = tochain; 3196272Seric tochain = to; 3206059Seric 3213233Seric /* create list of users for error messages */ 3229388Seric (void) strcat(tobuf, ","); 3234082Seric (void) strcat(tobuf, to->q_paddr); 3249370Seric define('u', user, e); /* to user */ 3259370Seric define('z', to->q_home, e); /* user's home */ 3263233Seric 3274863Seric /* 3286059Seric ** Expand out this user into argument list. 3294863Seric */ 3304863Seric 3316059Seric if (!clever) 3323233Seric { 3339370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3344863Seric *pvp++ = newstr(buf); 3354863Seric if (pvp >= &pv[MAXPV - 2]) 3364863Seric { 3374863Seric /* allow some space for trailing parms */ 3384863Seric break; 3394863Seric } 3404863Seric } 341294Seric } 342294Seric 3434067Seric /* see if any addresses still exist */ 3444067Seric if (tobuf[0] == '\0') 3454863Seric { 3469370Seric define('g', (char *) NULL, e); 3474067Seric return (0); 3484863Seric } 3494067Seric 3503233Seric /* print out messages as full list */ 3519388Seric e->e_to = tobuf + 1; 3523233Seric 353294Seric /* 3543233Seric ** Fill out any parameters after the $u parameter. 355294Seric */ 356294Seric 3574863Seric while (!clever && *++mvp != NULL) 358294Seric { 3599370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3603233Seric *pvp++ = newstr(buf); 3613233Seric if (pvp >= &pv[MAXPV]) 3623233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 363294Seric } 3643233Seric *pvp++ = NULL; 365294Seric 366294Seric /* 367294Seric ** Call the mailer. 3682898Seric ** The argument vector gets built, pipes 369294Seric ** are created as necessary, and we fork & exec as 3702898Seric ** appropriate. 3714863Seric ** If we are running SMTP, we just need to clean up. 372294Seric */ 373294Seric 37435651Seric #ifdef NAMED_BIND 37534022Sbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 37635651Seric #endif 37733931Sbostic #ifdef SMTP 37835651Seric if (clever) 37935651Seric { 38033931Sbostic rcode = EX_OK; 38135651Seric #ifdef NAMED_BIND 38236810Sbostic if (host[0] && host[0] != '[') 38335651Seric { 38436810Sbostic expand("\001w", buf, &buf[sizeof(buf) - 1], e); 38535651Seric Nmx = getmxrr(host, MxHosts, buf, &rcode); 38635651Seric } 38735651Seric else 38835651Seric #endif 38935651Seric { 39031952Sbostic Nmx = 1; 39131952Sbostic MxHosts[0] = host; 39235651Seric } 39335651Seric if (Nmx >= 0) 39435651Seric { 39534022Sbostic message(Arpa_Info, "Connecting to %s (%s)...", 39634022Sbostic MxHosts[0], m->m_name); 39734022Sbostic if ((rcode = smtpinit(m, pv)) == EX_OK) { 39836239Skarels register char *t = tobuf; 39936239Skarels register int i; 40036239Skarels 40134022Sbostic /* send the recipient list */ 40234022Sbostic tobuf[0] = '\0'; 40334022Sbostic for (to = tochain; to; to = to->q_tchain) { 40434022Sbostic e->e_to = to->q_paddr; 40534022Sbostic if ((i = smtprcpt(to, m)) != EX_OK) { 40634022Sbostic markfailure(e, to, i); 40734022Sbostic giveresponse(i, m, e); 40834022Sbostic } 40934022Sbostic else { 41034022Sbostic *t++ = ','; 41134022Sbostic for (p = to->q_paddr; *p; *t++ = *p++); 41234022Sbostic } 4139388Seric } 41434022Sbostic 41534022Sbostic /* now send the data */ 41634022Sbostic if (tobuf[0] == '\0') 41734022Sbostic e->e_to = NULL; 41833931Sbostic else { 41934022Sbostic e->e_to = tobuf + 1; 42034022Sbostic rcode = smtpdata(m, e); 4219388Seric } 4229388Seric 42334022Sbostic /* now close the connection */ 42434022Sbostic smtpquit(m); 4259370Seric } 4269370Seric } 4274863Seric } 4284863Seric else 42933931Sbostic #endif /* SMTP */ 43033935Sbostic { 43134022Sbostic message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name); 43210168Seric rcode = sendoff(e, m, pv, ctladdr); 43333935Sbostic } 43435651Seric #ifdef NAMED_BIND 43534022Sbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 43635651Seric #endif 4373233Seric 4384621Seric /* 4399388Seric ** Do final status disposal. 4409388Seric ** We check for something in tobuf for the SMTP case. 4419388Seric ** If we got a temporary failure, arrange to queue the 4429388Seric ** addressees. 4434621Seric */ 4444621Seric 4459388Seric if (tobuf[0] != '\0') 44610105Seric giveresponse(rcode, m, e); 4479388Seric if (rcode != EX_OK) 4485032Seric for (to = tochain; to != NULL; to = to->q_tchain) 44910092Seric markfailure(e, to, rcode); 4504621Seric 4514488Seric errno = 0; 4529370Seric define('g', (char *) NULL, e); 4538003Seric return (rcode); 4543233Seric } 4553233Seric /* 45610092Seric ** MARKFAILURE -- mark a failure on a specific address. 45710092Seric ** 45810092Seric ** Parameters: 45910092Seric ** e -- the envelope we are sending. 46010092Seric ** q -- the address to mark. 46110092Seric ** rcode -- the code signifying the particular failure. 46210092Seric ** 46310092Seric ** Returns: 46410092Seric ** none. 46510092Seric ** 46610092Seric ** Side Effects: 46710092Seric ** marks the address (and possibly the envelope) with the 46810092Seric ** failure so that an error will be returned or 46910092Seric ** the message will be queued, as appropriate. 47010092Seric */ 47110092Seric 47210092Seric markfailure(e, q, rcode) 47310092Seric register ENVELOPE *e; 47410092Seric register ADDRESS *q; 47510092Seric int rcode; 47610092Seric { 47710092Seric if (rcode == EX_OK) 47810092Seric return; 47910092Seric else if (rcode != EX_TEMPFAIL) 48010092Seric q->q_flags |= QBADADDR; 48110092Seric else if (curtime() > e->e_ctime + TimeOut) 48210092Seric { 48310092Seric extern char *pintvl(); 48410105Seric char buf[MAXLINE]; 48510092Seric 48610092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 48710105Seric { 48810105Seric (void) sprintf(buf, "Cannot send message for %s", 48910092Seric pintvl(TimeOut, FALSE)); 49010105Seric if (e->e_message != NULL) 49110105Seric free(e->e_message); 49210105Seric e->e_message = newstr(buf); 49310105Seric message(Arpa_Info, buf); 49410105Seric } 49510092Seric q->q_flags |= QBADADDR; 49610092Seric e->e_flags |= EF_TIMEOUT; 49710092Seric } 49810092Seric else 49910092Seric q->q_flags |= QQUEUEUP; 50010092Seric } 50110092Seric /* 5024214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5034214Seric ** 5044214Seric ** This MUST be a macro, since after a vfork we are running 5054214Seric ** two processes on the same stack!!! 5064214Seric ** 5074214Seric ** Parameters: 5084214Seric ** none. 5094214Seric ** 5104214Seric ** Returns: 5114214Seric ** From a macro??? You've got to be kidding! 5124214Seric ** 5134214Seric ** Side Effects: 5144214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5154214Seric ** pid of child in parent, zero in child. 5164214Seric ** -1 on unrecoverable error. 5174214Seric ** 5184214Seric ** Notes: 5194214Seric ** I'm awfully sorry this looks so awful. That's 5204214Seric ** vfork for you..... 5214214Seric */ 5224214Seric 5234214Seric # define NFORKTRIES 5 5249148Seric # ifdef VMUNIX 5254214Seric # define XFORK vfork 5269148Seric # else VMUNIX 5274214Seric # define XFORK fork 5289148Seric # endif VMUNIX 5294214Seric 5304214Seric # define DOFORK(fORKfN) \ 5314214Seric {\ 5324214Seric register int i;\ 5334214Seric \ 53423504Seric for (i = NFORKTRIES; --i >= 0; )\ 5354214Seric {\ 5364214Seric pid = fORKfN();\ 5374214Seric if (pid >= 0)\ 5384214Seric break;\ 53923504Seric if (i > 0)\ 54025617Seric sleep((unsigned) NFORKTRIES - i);\ 5414214Seric }\ 5424214Seric } 5434214Seric /* 5444637Seric ** DOFORK -- simple fork interface to DOFORK. 5454637Seric ** 5464637Seric ** Parameters: 5474637Seric ** none. 5484637Seric ** 5494637Seric ** Returns: 5504637Seric ** pid of child in parent. 5514637Seric ** zero in child. 5524637Seric ** -1 on error. 5534637Seric ** 5544637Seric ** Side Effects: 5554637Seric ** returns twice, once in parent and once in child. 5564637Seric */ 5574637Seric 5584637Seric dofork() 5594637Seric { 5604637Seric register int pid; 5614637Seric 5624637Seric DOFORK(fork); 5634637Seric return (pid); 5644637Seric } 5654637Seric /* 5663233Seric ** SENDOFF -- send off call to mailer & collect response. 5673233Seric ** 5683233Seric ** Parameters: 5699370Seric ** e -- the envelope to mail. 5703233Seric ** m -- mailer descriptor. 5713233Seric ** pvp -- parameter vector to send to it. 5724397Seric ** ctladdr -- an address pointer controlling the 5734397Seric ** user/groupid etc. of the mailer. 5743233Seric ** 5753233Seric ** Returns: 5763233Seric ** exit status of mailer. 5773233Seric ** 5783233Seric ** Side Effects: 5793233Seric ** none. 5803233Seric */ 58134022Sbostic static 58210168Seric sendoff(e, m, pvp, ctladdr) 5839370Seric register ENVELOPE *e; 5849370Seric MAILER *m; 5853233Seric char **pvp; 5864397Seric ADDRESS *ctladdr; 5873233Seric { 5884863Seric auto FILE *mfile; 5894863Seric auto FILE *rfile; 5903233Seric register int i; 5913233Seric int pid; 5924863Seric 5934863Seric /* 5944863Seric ** Create connection to mailer. 5954863Seric */ 5964863Seric 5974863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5984863Seric if (pid < 0) 5994863Seric return (-1); 6004863Seric 6014863Seric /* 6024863Seric ** Format and send message. 6034863Seric */ 6044863Seric 60510168Seric putfromline(mfile, m); 60610168Seric (*e->e_puthdr)(mfile, m, e); 60710168Seric putline("\n", mfile, m); 60810168Seric (*e->e_putbody)(mfile, m, e); 6094863Seric (void) fclose(mfile); 610*40992Sbostic if (rfile != NULL) 611*40992Sbostic (void) fclose(rfile); 6124863Seric 6134863Seric i = endmailer(pid, pvp[0]); 6145981Seric 6155981Seric /* arrange a return receipt if requested */ 61610682Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 6175981Seric { 6189370Seric e->e_flags |= EF_SENDRECEIPT; 6195981Seric /* do we want to send back more info? */ 6205981Seric } 6215981Seric 6224863Seric return (i); 6234863Seric } 6244863Seric /* 6254863Seric ** ENDMAILER -- Wait for mailer to terminate. 6264863Seric ** 6274863Seric ** We should never get fatal errors (e.g., segmentation 6284863Seric ** violation), so we report those specially. For other 6294863Seric ** errors, we choose a status message (into statmsg), 6304863Seric ** and if it represents an error, we print it. 6314863Seric ** 6324863Seric ** Parameters: 6334863Seric ** pid -- pid of mailer. 6344863Seric ** name -- name of mailer (for error messages). 6354863Seric ** 6364863Seric ** Returns: 6374863Seric ** exit code of mailer. 6384863Seric ** 6394863Seric ** Side Effects: 6404863Seric ** none. 6414863Seric */ 6424863Seric 6434863Seric endmailer(pid, name) 6444863Seric int pid; 6454863Seric char *name; 6464863Seric { 6479370Seric int st; 6484863Seric 6496038Seric /* in the IPC case there is nothing to wait for */ 6506038Seric if (pid == 0) 6516038Seric return (EX_OK); 6526038Seric 6536038Seric /* wait for the mailer process to die and collect status */ 6549370Seric st = waitfor(pid); 6559370Seric if (st == -1) 6568127Seric { 6579370Seric syserr("endmailer %s: wait", name); 6589370Seric return (EX_SOFTWARE); 6594863Seric } 6606038Seric 6616038Seric /* see if it died a horrid death */ 6624863Seric if ((st & 0377) != 0) 6634863Seric { 66424941Seric syserr("mailer %s died with signal %o", name, st); 66524941Seric ExitStat = EX_TEMPFAIL; 66624941Seric return (EX_TEMPFAIL); 6674863Seric } 6686038Seric 6696038Seric /* normal death -- return status */ 6709370Seric st = (st >> 8) & 0377; 6719370Seric return (st); 6724863Seric } 6734863Seric /* 6744863Seric ** OPENMAILER -- open connection to mailer. 6754863Seric ** 6764863Seric ** Parameters: 6774863Seric ** m -- mailer descriptor. 6784863Seric ** pvp -- parameter vector to pass to mailer. 6794863Seric ** ctladdr -- controlling address for user. 6804863Seric ** clever -- create a full duplex connection. 6814863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6824863Seric ** prfile -- pointer to rfile (from mailer) connection. 6834863Seric ** 6844863Seric ** Returns: 6856038Seric ** pid of mailer ( > 0 ). 6864863Seric ** -1 on error. 6876038Seric ** zero on an IPC connection. 6884863Seric ** 6894863Seric ** Side Effects: 6904863Seric ** creates a mailer in a subprocess. 6914863Seric */ 6924863Seric 6934863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6949370Seric MAILER *m; 6954863Seric char **pvp; 6964863Seric ADDRESS *ctladdr; 6974863Seric bool clever; 6984863Seric FILE **pmfile; 6994863Seric FILE **prfile; 7004863Seric { 7014863Seric int pid; 7024709Seric int mpvect[2]; 7034863Seric int rpvect[2]; 70440979Sbostic FILE *mfile = NULL; 70540979Sbostic FILE *rfile = NULL; 7063233Seric extern FILE *fdopen(); 7073233Seric 7087672Seric if (tTd(11, 1)) 709294Seric { 7108178Seric printf("openmailer:"); 7113233Seric printav(pvp); 712294Seric } 7134488Seric errno = 0; 7143233Seric 71525050Seric CurHostName = m->m_mailer; 71625050Seric 7176038Seric /* 7186038Seric ** Deal with the special case of mail handled through an IPC 7196038Seric ** connection. 7206038Seric ** In this case we don't actually fork. We must be 7216038Seric ** running SMTP for this to work. We will return a 7226038Seric ** zero pid to indicate that we are running IPC. 72311160Seric ** We also handle a debug version that just talks to stdin/out. 7246038Seric */ 7256038Seric 72611160Seric /* check for Local Person Communication -- not for mortals!!! */ 72711160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 72811160Seric { 72911160Seric *pmfile = stdout; 73011160Seric *prfile = stdin; 73111160Seric return (0); 73211160Seric } 73311160Seric 7346038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 7356038Seric { 73624941Seric #ifdef HOSTINFO 73724941Seric register STAB *st; 73824941Seric extern STAB *stab(); 73924941Seric #endif HOSTINFO 7409370Seric #ifdef DAEMON 74129433Sbloom register int i, j; 7427285Seric register u_short port; 7436038Seric 74425050Seric CurHostName = pvp[1]; 7456038Seric if (!clever) 7466038Seric syserr("non-clever IPC"); 7476632Seric if (pvp[2] != NULL) 7487285Seric port = atoi(pvp[2]); 7496632Seric else 7507285Seric port = 0; 75129865Seric for (j = 0; j < Nmx; j++) 75229433Sbloom { 75329865Seric CurHostName = MxHosts[j]; 75424941Seric #ifdef HOSTINFO 75524941Seric /* see if we have already determined that this host is fried */ 75629865Seric st = stab(MxHosts[j], ST_HOST, ST_FIND); 75734022Sbostic if (st == NULL || st->s_host.ho_exitstat == EX_OK) { 75834022Sbostic if (j > 1) 75934022Sbostic message(Arpa_Info, 76034022Sbostic "Connecting to %s (%s)...", 76134022Sbostic MxHosts[j], m->m_name); 76229865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 76334022Sbostic } 76429433Sbloom else 76529433Sbloom { 76629433Sbloom i = st->s_host.ho_exitstat; 76729433Sbloom errno = st->s_host.ho_errno; 76829433Sbloom } 76924941Seric #else HOSTINFO 77029865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 77124941Seric #endif HOSTINFO 77229433Sbloom if (i != EX_OK) 77329433Sbloom { 77424941Seric #ifdef HOSTINFO 77529433Sbloom /* enter status of this host */ 77629433Sbloom if (st == NULL) 77729865Seric st = stab(MxHosts[j], ST_HOST, ST_ENTER); 77829433Sbloom st->s_host.ho_exitstat = i; 77929433Sbloom st->s_host.ho_errno = errno; 78024941Seric #endif HOSTINFO 78129433Sbloom ExitStat = i; 78229433Sbloom continue; 78329433Sbloom } 78429433Sbloom else 78529433Sbloom return (0); 7866047Seric } 78729433Sbloom return (-1); 7889370Seric #else DAEMON 7899370Seric syserr("openmailer: no IPC"); 7909370Seric return (-1); 7919370Seric #endif DAEMON 7926038Seric } 7936038Seric 7942898Seric /* create a pipe to shove the mail through */ 7954709Seric if (pipe(mpvect) < 0) 796294Seric { 7979370Seric syserr("openmailer: pipe (to mailer)"); 798294Seric return (-1); 799294Seric } 8004863Seric 8019370Seric #ifdef SMTP 8024863Seric /* if this mailer speaks smtp, create a return pipe */ 8034863Seric if (clever && pipe(rpvect) < 0) 8044863Seric { 8059370Seric syserr("openmailer: pipe (from mailer)"); 8064863Seric (void) close(mpvect[0]); 8074863Seric (void) close(mpvect[1]); 8084863Seric return (-1); 8094863Seric } 8109370Seric #endif SMTP 8114863Seric 8126038Seric /* 8136038Seric ** Actually fork the mailer process. 8146038Seric ** DOFORK is clever about retrying. 81526434Seric ** 81626434Seric ** Dispose of SIGCHLD signal catchers that may be laying 81726434Seric ** around so that endmail will get it. 8186038Seric */ 8196038Seric 8209538Seric if (CurEnv->e_xfp != NULL) 8219538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 8229370Seric (void) fflush(stdout); 82326434Seric # ifdef SIGCHLD 82426434Seric (void) signal(SIGCHLD, SIG_DFL); 82526434Seric # endif SIGCHLD 8264214Seric DOFORK(XFORK); 8274327Seric /* pid is set by DOFORK */ 828294Seric if (pid < 0) 829294Seric { 8306038Seric /* failure */ 8319370Seric syserr("openmailer: cannot fork"); 8324709Seric (void) close(mpvect[0]); 8334709Seric (void) close(mpvect[1]); 8349370Seric #ifdef SMTP 8354863Seric if (clever) 8364863Seric { 8374863Seric (void) close(rpvect[0]); 8384863Seric (void) close(rpvect[1]); 8394863Seric } 8409370Seric #endif SMTP 841294Seric return (-1); 842294Seric } 843294Seric else if (pid == 0) 844294Seric { 84515772Seric int i; 84624941Seric extern int DtableSize; 84715772Seric 848294Seric /* child -- set up input & exec mailer */ 8491621Seric /* make diagnostic output be standard output */ 8504477Seric (void) signal(SIGINT, SIG_IGN); 8514477Seric (void) signal(SIGHUP, SIG_IGN); 8524215Seric (void) signal(SIGTERM, SIG_DFL); 8534709Seric 8544709Seric /* arrange to filter standard & diag output of command */ 8554863Seric if (clever) 8564709Seric { 8574863Seric (void) close(rpvect[0]); 8584709Seric (void) close(1); 8594863Seric (void) dup(rpvect[1]); 8604863Seric (void) close(rpvect[1]); 8614863Seric } 8629275Seric else if (OpMode == MD_SMTP || HoldErrs) 8634863Seric { 8649370Seric /* put mailer output in transcript */ 8654863Seric (void) close(1); 8669538Seric (void) dup(fileno(CurEnv->e_xfp)); 8674709Seric } 8684082Seric (void) close(2); 8694082Seric (void) dup(1); 8704709Seric 8714709Seric /* arrange to get standard input */ 8724709Seric (void) close(mpvect[1]); 8734082Seric (void) close(0); 8744709Seric if (dup(mpvect[0]) < 0) 875294Seric { 8762898Seric syserr("Cannot dup to zero!"); 8772898Seric _exit(EX_OSERR); 878294Seric } 8794709Seric (void) close(mpvect[0]); 88010682Seric if (!bitnset(M_RESTR, m->m_flags)) 8814215Seric { 88216883Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 8834417Seric { 8844417Seric (void) setgid(DefGid); 88540972Sbostic (void) initgroups(DefUser, DefGid); 8864417Seric (void) setuid(DefUid); 8874417Seric } 8884417Seric else 8894415Seric { 8904417Seric (void) setgid(ctladdr->q_gid); 89140972Sbostic (void) initgroups(ctladdr->q_ruser? 89240972Sbostic ctladdr->q_ruser: ctladdr->q_user, 89340972Sbostic ctladdr->q_gid); 8944417Seric (void) setuid(ctladdr->q_uid); 8954415Seric } 8964215Seric } 8979370Seric 89815772Seric /* arrange for all the files to be closed */ 89936030Sbostic for (i = 3; i < DtableSize; i++) { 90036030Sbostic register int j; 90136030Sbostic if ((j = fcntl(i, F_GETFD, 0)) != -1) 90236030Sbostic (void)fcntl(i, F_SETFD, j|1); 90336030Sbostic } 9042774Seric 9056038Seric /* try to execute the mailer */ 90625026Seric execve(m->m_mailer, pvp, UserEnviron); 90715772Seric syserr("Cannot exec %s", m->m_mailer); 90824941Seric if (m == LocalMailer || errno == EIO || errno == EAGAIN || 90924941Seric errno == ENOMEM || errno == EPROCLIM) 91016902Seric _exit(EX_TEMPFAIL); 91116902Seric else 91216902Seric _exit(EX_UNAVAILABLE); 913294Seric } 914294Seric 9154709Seric /* 9164863Seric ** Set up return value. 9174709Seric */ 9184709Seric 9194709Seric (void) close(mpvect[0]); 9204709Seric mfile = fdopen(mpvect[1], "w"); 9214863Seric if (clever) 9224863Seric { 9234863Seric (void) close(rpvect[1]); 9244863Seric rfile = fdopen(rpvect[0], "r"); 925*40992Sbostic } else 926*40992Sbostic rfile = NULL; 927294Seric 9284863Seric *pmfile = mfile; 9294863Seric *prfile = rfile; 930294Seric 9314863Seric return (pid); 932294Seric } 933294Seric /* 934294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 935294Seric ** 936294Seric ** Parameters: 937294Seric ** stat -- the status code from the mailer (high byte 938294Seric ** only; core dumps must have been taken care of 939294Seric ** already). 940294Seric ** m -- the mailer descriptor for this mailer. 941294Seric ** 942294Seric ** Returns: 9434082Seric ** none. 944294Seric ** 945294Seric ** Side Effects: 9461518Seric ** Errors may be incremented. 947294Seric ** ExitStat may be set. 948294Seric */ 949294Seric 95010105Seric giveresponse(stat, m, e) 951294Seric int stat; 9529370Seric register MAILER *m; 95310105Seric ENVELOPE *e; 954294Seric { 955294Seric register char *statmsg; 956294Seric extern char *SysExMsg[]; 957294Seric register int i; 95836788Sbostic extern int N_SysEx; 95936788Sbostic #ifdef NAMED_BIND 96036788Sbostic extern int h_errno; 96136788Sbostic #endif 96210105Seric char buf[MAXLINE]; 963294Seric 96412135Seric #ifdef lint 96512135Seric if (m == NULL) 96612135Seric return; 96712135Seric #endif lint 96812135Seric 9694315Seric /* 9704315Seric ** Compute status message from code. 9714315Seric */ 9724315Seric 973294Seric i = stat - EX__BASE; 9749370Seric if (stat == 0) 9759370Seric statmsg = "250 Sent"; 9769370Seric else if (i < 0 || i > N_SysEx) 9779370Seric { 9789370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 9799370Seric stat = EX_UNAVAILABLE; 9809370Seric statmsg = buf; 9819370Seric } 98210105Seric else if (stat == EX_TEMPFAIL) 98310105Seric { 98410124Seric (void) strcpy(buf, SysExMsg[i]); 98536788Sbostic #ifdef NAMED_BIND 98625527Smiriam if (h_errno == TRY_AGAIN) 98710105Seric { 98815137Seric extern char *errstring(); 98915137Seric 99025527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 99121061Seric } 99221061Seric else 99336788Sbostic #endif 99421061Seric { 99525527Smiriam if (errno != 0) 99625527Smiriam { 99725527Smiriam extern char *errstring(); 99825527Smiriam 99925527Smiriam statmsg = errstring(errno); 100025527Smiriam } 100125527Smiriam else 100225527Smiriam { 100321061Seric #ifdef SMTP 100425527Smiriam extern char SmtpError[]; 100521061Seric 100625527Smiriam statmsg = SmtpError; 100721061Seric #else SMTP 100825527Smiriam statmsg = NULL; 100921061Seric #endif SMTP 101025527Smiriam } 101121061Seric } 101221061Seric if (statmsg != NULL && statmsg[0] != '\0') 101321061Seric { 101410124Seric (void) strcat(buf, ": "); 101521061Seric (void) strcat(buf, statmsg); 101610105Seric } 101710105Seric statmsg = buf; 101810105Seric } 1019294Seric else 102021061Seric { 1021294Seric statmsg = SysExMsg[i]; 102221061Seric } 10239370Seric 10249370Seric /* 10259370Seric ** Print the message as appropriate 10269370Seric */ 10279370Seric 102810105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 10298003Seric message(Arpa_Info, &statmsg[4]); 1030294Seric else 1031294Seric { 10321518Seric Errors++; 10339370Seric usrerr(statmsg); 1034294Seric } 1035294Seric 1036294Seric /* 1037294Seric ** Final cleanup. 1038294Seric ** Log a record of the transaction. Compute the new 1039294Seric ** ExitStat -- if we already had an error, stick with 1040294Seric ** that. 1041294Seric */ 1042294Seric 10437680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 10448496Seric logdelivery(&statmsg[4]); 10457858Seric 10464621Seric if (stat != EX_TEMPFAIL) 10474621Seric setstat(stat); 104810105Seric if (stat != EX_OK) 104910105Seric { 105010105Seric if (e->e_message != NULL) 105110105Seric free(e->e_message); 105210105Seric e->e_message = newstr(&statmsg[4]); 105310105Seric } 105410124Seric errno = 0; 105536788Sbostic #ifdef NAMED_BIND 105625527Smiriam h_errno = 0; 105736788Sbostic #endif 1058294Seric } 1059294Seric /* 10608496Seric ** LOGDELIVERY -- log the delivery in the system log 10618496Seric ** 10628496Seric ** Parameters: 10638496Seric ** stat -- the message to print for the status 10648496Seric ** 10658496Seric ** Returns: 10668496Seric ** none 10678496Seric ** 10688496Seric ** Side Effects: 10698496Seric ** none 10708496Seric */ 10718496Seric 10728496Seric logdelivery(stat) 10738496Seric char *stat; 10748496Seric { 10758496Seric extern char *pintvl(); 10768496Seric 10778496Seric # ifdef LOG 10788496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 10798496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 10808496Seric # endif LOG 10818496Seric } 10828496Seric /* 10836974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1084294Seric ** 10856974Seric ** This can be made an arbitrary message separator by changing $l 1086294Seric ** 108716150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 108816150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 108916150Seric ** does a well-meaning programmer such as myself have to deal with 109016150Seric ** this kind of antique garbage???? 10916974Seric ** 1092294Seric ** Parameters: 10936974Seric ** fp -- the file to output to. 10946974Seric ** m -- the mailer describing this entry. 1095294Seric ** 1096294Seric ** Returns: 10976974Seric ** none 1098294Seric ** 1099294Seric ** Side Effects: 11006974Seric ** outputs some text to fp. 1101294Seric */ 1102294Seric 110310168Seric putfromline(fp, m) 11046974Seric register FILE *fp; 11056974Seric register MAILER *m; 1106294Seric { 110716150Seric char *template = "\001l\n"; 11086974Seric char buf[MAXLINE]; 1109294Seric 111010682Seric if (bitnset(M_NHDR, m->m_flags)) 11116974Seric return; 11124315Seric 11136974Seric # ifdef UGLYUUCP 111410682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 11154205Seric { 111612223Seric char *bang; 111712223Seric char xbuf[MAXLINE]; 11186041Seric 111916150Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 112012223Seric bang = index(buf, '!'); 11216974Seric if (bang == NULL) 112212223Seric syserr("No ! in UUCP! (%s)", buf); 11235099Seric else 11249370Seric { 112512223Seric *bang++ = '\0'; 112616150Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 112712223Seric template = xbuf; 11289370Seric } 11296974Seric } 11305179Seric # endif UGLYUUCP 113112223Seric expand(template, buf, &buf[sizeof buf - 1], CurEnv); 113210168Seric putline(buf, fp, m); 11335981Seric } 11345981Seric /* 11356974Seric ** PUTBODY -- put the body of a message. 11366974Seric ** 11376974Seric ** Parameters: 11386974Seric ** fp -- file to output onto. 113910168Seric ** m -- a mailer descriptor to control output format. 11409538Seric ** e -- the envelope to put out. 11416974Seric ** 11426974Seric ** Returns: 11436974Seric ** none. 11446974Seric ** 11456974Seric ** Side Effects: 11466974Seric ** The message is written onto fp. 11476974Seric */ 11486974Seric 114910168Seric putbody(fp, m, e) 11506974Seric FILE *fp; 11519370Seric MAILER *m; 11529538Seric register ENVELOPE *e; 11536974Seric { 115410168Seric char buf[MAXLINE]; 11556974Seric 11566974Seric /* 11576974Seric ** Output the body of the message 11586974Seric */ 11596974Seric 11609538Seric if (e->e_dfp == NULL) 11616974Seric { 11629538Seric if (e->e_df != NULL) 11639538Seric { 11649538Seric e->e_dfp = fopen(e->e_df, "r"); 11659538Seric if (e->e_dfp == NULL) 116640931Srick syserr("putbody: Cannot open %s for %s from %s", 116740931Srick e->e_df, e->e_to, e->e_from); 11689538Seric } 11699538Seric else 117010168Seric putline("<<< No Message Collected >>>", fp, m); 11719538Seric } 11729538Seric if (e->e_dfp != NULL) 11739538Seric { 11749538Seric rewind(e->e_dfp); 117510168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 117616875Seric { 117716875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 117816875Seric strncmp(buf, "From", 4) == 0) 117923102Seric (void) putc('>', fp); 118010168Seric putline(buf, fp, m); 118116875Seric } 11826974Seric 11839538Seric if (ferror(e->e_dfp)) 11846974Seric { 11856974Seric syserr("putbody: read error"); 11866974Seric ExitStat = EX_IOERR; 11876974Seric } 11886974Seric } 11896974Seric 11906974Seric (void) fflush(fp); 11916974Seric if (ferror(fp) && errno != EPIPE) 11926974Seric { 11936974Seric syserr("putbody: write error"); 11946974Seric ExitStat = EX_IOERR; 11956974Seric } 11966974Seric errno = 0; 11976974Seric } 11986974Seric /* 1199294Seric ** MAILFILE -- Send a message to a file. 1200294Seric ** 12014327Seric ** If the file has the setuid/setgid bits set, but NO execute 12024327Seric ** bits, sendmail will try to become the owner of that file 12034327Seric ** rather than the real user. Obviously, this only works if 12044327Seric ** sendmail runs as root. 12054327Seric ** 12069370Seric ** This could be done as a subordinate mailer, except that it 12079370Seric ** is used implicitly to save messages in ~/dead.letter. We 12089370Seric ** view this as being sufficiently important as to include it 12099370Seric ** here. For example, if the system is dying, we shouldn't have 12109370Seric ** to create another process plus some pipes to save the message. 12119370Seric ** 1212294Seric ** Parameters: 1213294Seric ** filename -- the name of the file to send to. 12144397Seric ** ctladdr -- the controlling address header -- includes 12154397Seric ** the userid/groupid to be when sending. 1216294Seric ** 1217294Seric ** Returns: 1218294Seric ** The exit code associated with the operation. 1219294Seric ** 1220294Seric ** Side Effects: 1221294Seric ** none. 1222294Seric */ 1223294Seric 12244397Seric mailfile(filename, ctladdr) 1225294Seric char *filename; 12264397Seric ADDRESS *ctladdr; 1227294Seric { 1228294Seric register FILE *f; 12294214Seric register int pid; 123040931Srick ENVELOPE *e = CurEnv; 1231294Seric 12324214Seric /* 12334214Seric ** Fork so we can change permissions here. 12344214Seric ** Note that we MUST use fork, not vfork, because of 12354214Seric ** the complications of calling subroutines, etc. 12364214Seric */ 12374067Seric 12384214Seric DOFORK(fork); 12394214Seric 12404214Seric if (pid < 0) 12414214Seric return (EX_OSERR); 12424214Seric else if (pid == 0) 12434214Seric { 12444214Seric /* child -- actually write to file */ 12454327Seric struct stat stb; 12464327Seric 12474215Seric (void) signal(SIGINT, SIG_DFL); 12484215Seric (void) signal(SIGHUP, SIG_DFL); 12494215Seric (void) signal(SIGTERM, SIG_DFL); 125023102Seric (void) umask(OldUmask); 12514327Seric if (stat(filename, &stb) < 0) 125211935Seric { 125311935Seric errno = 0; 12544431Seric stb.st_mode = 0666; 125511935Seric } 12564327Seric if (bitset(0111, stb.st_mode)) 12574327Seric exit(EX_CANTCREAT); 12584401Seric if (ctladdr == NULL) 125940931Srick ctladdr = &e->e_from; 126040931Srick /* we have to open the dfile BEFORE setuid */ 126140931Srick if (e->e_dfp == NULL && e->e_df != NULL) 126240931Srick { 126340931Srick e->e_dfp = fopen(e->e_df, "r"); 126440931Srick if (e->e_dfp == NULL) { 126540931Srick syserr("mailfile: Cannot open %s for %s from %s", 126640931Srick e->e_df, e->e_to, e->e_from); 126740931Srick } 126840931Srick } 126940931Srick 12704327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 12714417Seric { 127240972Sbostic if (ctladdr->q_uid == 0) { 12734417Seric (void) setgid(DefGid); 127440972Sbostic (void) initgroups(DefUser, DefGid); 127540972Sbostic } else { 12764417Seric (void) setgid(ctladdr->q_gid); 127740972Sbostic (void) initgroups(ctladdr->q_ruser? 127840972Sbostic ctladdr->q_ruser: ctladdr->q_user, 127940972Sbostic ctladdr->q_gid); 128040972Sbostic } 12814417Seric } 12824327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 12834417Seric { 12844417Seric if (ctladdr->q_uid == 0) 12854417Seric (void) setuid(DefUid); 12864417Seric else 12874417Seric (void) setuid(ctladdr->q_uid); 12884417Seric } 12896887Seric f = dfopen(filename, "a"); 12904214Seric if (f == NULL) 12914214Seric exit(EX_CANTCREAT); 12924214Seric 129310168Seric putfromline(f, ProgMailer); 129410168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 129510168Seric putline("\n", f, ProgMailer); 129610168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 129710168Seric putline("\n", f, ProgMailer); 12984214Seric (void) fclose(f); 12994214Seric (void) fflush(stdout); 13004417Seric 13016887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13024621Seric (void) chmod(filename, (int) stb.st_mode); 13034214Seric exit(EX_OK); 13044315Seric /*NOTREACHED*/ 13054214Seric } 13064214Seric else 13074214Seric { 13084214Seric /* parent -- wait for exit status */ 13099370Seric int st; 13104214Seric 13119370Seric st = waitfor(pid); 13129370Seric if ((st & 0377) != 0) 13139370Seric return (EX_UNAVAILABLE); 13149370Seric else 13159370Seric return ((st >> 8) & 0377); 131640931Srick /*NOTREACHED*/ 13174214Seric } 1318294Seric } 13194550Seric /* 13204550Seric ** SENDALL -- actually send all the messages. 13214550Seric ** 13224550Seric ** Parameters: 13237043Seric ** e -- the envelope to send. 132414874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 132514874Seric ** the current SendMode. 13264550Seric ** 13274550Seric ** Returns: 13284550Seric ** none. 13294550Seric ** 13304550Seric ** Side Effects: 13314550Seric ** Scans the send lists and sends everything it finds. 13327043Seric ** Delivers any appropriate error messages. 13339275Seric ** If we are running in a non-interactive mode, takes the 13349275Seric ** appropriate action. 13354550Seric */ 13364550Seric 13379275Seric sendall(e, mode) 13387043Seric ENVELOPE *e; 13399275Seric char mode; 13404550Seric { 13415008Seric register ADDRESS *q; 13427779Seric bool oldverbose; 13439275Seric int pid; 134440979Sbostic FILE *lockfp = NULL, *queueup(); 13454550Seric 134614874Seric /* determine actual delivery mode */ 134714874Seric if (mode == SM_DEFAULT) 134814874Seric { 134924941Seric extern bool shouldqueue(); 135014874Seric 135124941Seric if (shouldqueue(e->e_msgpriority)) 135214874Seric mode = SM_QUEUE; 135314874Seric else 135414874Seric mode = SendMode; 135514874Seric } 135614874Seric 13578248Seric if (tTd(13, 1)) 13585032Seric { 13599275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 13607043Seric printaddr(e->e_sendqueue, TRUE); 13615032Seric } 13625008Seric 13637043Seric /* 13649275Seric ** Do any preprocessing necessary for the mode we are running. 13659370Seric ** Check to make sure the hop count is reasonable. 13669370Seric ** Delete sends to the sender in mailing lists. 13677043Seric */ 13687043Seric 13699370Seric CurEnv = e; 13709370Seric 13719370Seric if (e->e_hopcount > MAXHOP) 13729275Seric { 137340931Srick errno = 0; 137440931Srick syserr("sendall: too many hops %d (%d max): from %s, to %s", 137540931Srick e->e_hopcount, MAXHOP, e->e_from, e->e_to); 13769370Seric return; 13779370Seric } 13789275Seric 13799370Seric if (!MeToo) 13809370Seric { 138112611Seric extern ADDRESS *recipient(); 138212611Seric 13839370Seric e->e_from.q_flags |= QDONTSEND; 138412611Seric (void) recipient(&e->e_from, &e->e_sendqueue); 13859275Seric } 13869370Seric 13879370Seric # ifdef QUEUE 13889335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 13899335Seric (mode != SM_VERIFY && SuperSafe)) && 13909335Seric !bitset(EF_INQUEUE, e->e_flags)) 139140931Srick lockfp = queueup(e, TRUE, mode == SM_QUEUE); 13929275Seric #endif QUEUE 13939275Seric 13947779Seric oldverbose = Verbose; 13959275Seric switch (mode) 13969275Seric { 13979275Seric case SM_VERIFY: 13987779Seric Verbose = TRUE; 13999275Seric break; 14009275Seric 14019275Seric case SM_QUEUE: 14029335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 14039275Seric return; 14049275Seric 14059275Seric case SM_FORK: 14069538Seric if (e->e_xfp != NULL) 14079538Seric (void) fflush(e->e_xfp); 14089275Seric pid = fork(); 14099275Seric if (pid < 0) 14109275Seric { 14119275Seric mode = SM_DELIVER; 14129275Seric break; 14139275Seric } 14149275Seric else if (pid > 0) 14159293Seric { 14169293Seric /* be sure we leave the temp files to our child */ 14179335Seric e->e_id = e->e_df = NULL; 141840931Srick if (lockfp != NULL) 141940931Srick (void) fclose(lockfp); 14209275Seric return; 14219293Seric } 14229275Seric 14239275Seric /* double fork to avoid zombies */ 14249275Seric if (fork() > 0) 14259275Seric exit(EX_OK); 14269275Seric 14279293Seric /* be sure we are immune from the terminal */ 142810133Seric disconnect(FALSE); 14299293Seric 14309275Seric break; 14319275Seric } 14329275Seric 14339275Seric /* 14349275Seric ** Run through the list and send everything. 14359275Seric */ 14369275Seric 14377043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14384550Seric { 14399275Seric if (mode == SM_VERIFY) 14404550Seric { 14419293Seric e->e_to = q->q_paddr; 14425008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14437052Seric message(Arpa_Info, "deliverable"); 14444550Seric } 14455008Seric else 14469370Seric (void) deliver(e, q); 14474550Seric } 14487779Seric Verbose = oldverbose; 14497043Seric 14507043Seric /* 14517043Seric ** Now run through and check for errors. 14527043Seric */ 14537043Seric 145440931Srick if (mode == SM_VERIFY) { 145540931Srick if (lockfp != NULL) 145640931Srick (void) fclose(lockfp); 14577043Seric return; 145840931Srick } 14597043Seric 14607043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14617043Seric { 14627043Seric register ADDRESS *qq; 14637043Seric 14648248Seric if (tTd(13, 3)) 14658248Seric { 14668248Seric printf("Checking "); 14678248Seric printaddr(q, FALSE); 14688248Seric } 14698248Seric 14709335Seric /* only send errors if the message failed */ 14719335Seric if (!bitset(QBADADDR, q->q_flags)) 14729335Seric continue; 14737043Seric 14747043Seric /* we have an address that failed -- find the parent */ 14757043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14767043Seric { 14777043Seric char obuf[MAXNAME + 6]; 14787043Seric extern char *aliaslookup(); 14797043Seric 14807043Seric /* we can only have owners for local addresses */ 148110682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 14827043Seric continue; 14837043Seric 14847043Seric /* see if the owner list exists */ 14857043Seric (void) strcpy(obuf, "owner-"); 14867047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14877047Seric (void) strcat(obuf, "owner"); 14887047Seric else 14897047Seric (void) strcat(obuf, qq->q_user); 14907043Seric if (aliaslookup(obuf) == NULL) 14917043Seric continue; 14927043Seric 14938248Seric if (tTd(13, 4)) 14948248Seric printf("Errors to %s\n", obuf); 14958248Seric 14967043Seric /* owner list exists -- add it to the error queue */ 14979615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 149816883Seric ErrorMode = EM_MAIL; 14997043Seric break; 15007043Seric } 15017043Seric 15027043Seric /* if we did not find an owner, send to the sender */ 15038426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 15049615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 15057043Seric } 15069275Seric 150740931Srick /* this removes the lock on the file */ 150840931Srick if (lockfp != NULL) 150940931Srick (void) fclose(lockfp); 151040931Srick 15119275Seric if (mode == SM_FORK) 15129275Seric finis(); 15134550Seric } 1514