122701Sdist /* 222701Sdist ** Sendmail 322701Sdist ** Copyright (c) 1983 Eric P. Allman 422701Sdist ** Berkeley, California 522701Sdist ** 622701Sdist ** Copyright (c) 1983 Regents of the University of California. 722701Sdist ** All rights reserved. The Berkeley software License Agreement 822701Sdist ** specifies the terms and conditions for redistribution. 922701Sdist */ 1022701Sdist 1122701Sdist #ifndef lint 12*29865Seric static char SccsId[] = "@(#)deliver.c 5.12 (Berkeley) 10/14/86"; 1322701Sdist #endif not lint 1422701Sdist 15294Seric # include <signal.h> 164123Seric # include <errno.h> 174621Seric # include "sendmail.h" 184327Seric # include <sys/stat.h> 1925527Smiriam # include <netdb.h> 20294Seric 21294Seric /* 224315Seric ** DELIVER -- Deliver a message to a list of addresses. 23294Seric ** 244315Seric ** This routine delivers to everyone on the same host as the 254315Seric ** user on the head of the list. It is clever about mailers 264315Seric ** that don't handle multiple users. It is NOT guaranteed 274315Seric ** that it will deliver to all these addresses however -- so 284315Seric ** deliver should be called once for each address on the 294315Seric ** list. 304315Seric ** 31294Seric ** Parameters: 329370Seric ** e -- the envelope to deliver. 334621Seric ** firstto -- head of the address list to deliver to. 34294Seric ** 35294Seric ** Returns: 36294Seric ** zero -- successfully delivered. 37294Seric ** else -- some failure, see ExitStat for more info. 38294Seric ** 39294Seric ** Side Effects: 40294Seric ** The standard input is passed off to someone. 41294Seric */ 42294Seric 439370Seric deliver(e, firstto) 449370Seric register ENVELOPE *e; 454621Seric ADDRESS *firstto; 46294Seric { 474452Seric char *host; /* host being sent to */ 484452Seric char *user; /* user being sent to */ 49294Seric char **pvp; 503233Seric register char **mvp; 513233Seric register char *p; 5210306Seric register MAILER *m; /* mailer for this recipient */ 534397Seric ADDRESS *ctladdr; 544621Seric register ADDRESS *to = firstto; 554863Seric bool clever = FALSE; /* running user smtp to this mailer */ 565032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 578003Seric register int rcode; /* response code */ 5810306Seric char *pv[MAXPV+1]; 5910306Seric char tobuf[MAXLINE-50]; /* text line of to people */ 6010306Seric char buf[MAXNAME]; 6110306Seric char tfrombuf[MAXNAME]; /* translated from person */ 6210306Seric extern bool checkcompat(); 6310306Seric extern ADDRESS *getctladdr(); 6410306Seric extern char *remotename(); 65294Seric 664488Seric errno = 0; 677052Seric if (bitset(QDONTSEND, to->q_flags)) 683233Seric return (0); 69294Seric 706974Seric m = to->q_mailer; 716974Seric host = to->q_host; 726974Seric 73294Seric # ifdef DEBUG 747672Seric if (tTd(10, 1)) 753233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 766974Seric m->m_mno, host, to->q_user); 77294Seric # endif DEBUG 78294Seric 79294Seric /* 805903Seric ** If this mailer is expensive, and if we don't want to make 815903Seric ** connections now, just mark these addresses and return. 825903Seric ** This is useful if we want to batch connections to 835903Seric ** reduce load. This will cause the messages to be 845903Seric ** queued up, and a daemon will come along to send the 855903Seric ** messages later. 865903Seric ** This should be on a per-mailer basis. 875903Seric */ 885903Seric 8910682Seric if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) && 908428Seric !Verbose) 915903Seric { 925903Seric for (; to != NULL; to = to->q_next) 938431Seric { 948431Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 958431Seric continue; 968431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 979370Seric e->e_to = to->q_paddr; 988496Seric message(Arpa_Info, "queued"); 998496Seric if (LogLevel > 4) 1008496Seric logdelivery("queued"); 1018431Seric } 1029370Seric e->e_to = NULL; 1035903Seric return (0); 1045903Seric } 1055903Seric 1065903Seric /* 1073233Seric ** Do initial argv setup. 1083233Seric ** Insert the mailer name. Notice that $x expansion is 1093233Seric ** NOT done on the mailer name. Then, if the mailer has 1103233Seric ** a picky -f flag, we insert it as appropriate. This 1113233Seric ** code does not check for 'pv' overflow; this places a 1123233Seric ** manifest lower limit of 4 for MAXPV. 1138062Seric ** The from address rewrite is expected to make 1148062Seric ** the address relative to the other end. 1152968Seric */ 1162968Seric 1174452Seric /* rewrite from address, using rewriting rules */ 11816150Seric expand("\001f", buf, &buf[sizeof buf - 1], e); 11910306Seric (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE)); 1204452Seric 1219370Seric define('g', tfrombuf, e); /* translated sender address */ 1229370Seric define('h', host, e); /* to host */ 1233233Seric Errors = 0; 1243233Seric pvp = pv; 1253233Seric *pvp++ = m->m_argv[0]; 1262968Seric 1273233Seric /* insert -f or -r flag as appropriate */ 12810682Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 1293233Seric { 13010682Seric if (bitnset(M_FOPT, m->m_flags)) 1313233Seric *pvp++ = "-f"; 1323233Seric else 1333233Seric *pvp++ = "-r"; 13416150Seric expand("\001g", buf, &buf[sizeof buf - 1], e); 1353233Seric *pvp++ = newstr(buf); 1363233Seric } 137294Seric 138294Seric /* 1393233Seric ** Append the other fixed parts of the argv. These run 1403233Seric ** up to the first entry containing "$u". There can only 1413233Seric ** be one of these, and there are only a few more slots 1423233Seric ** in the pv after it. 143294Seric */ 144294Seric 1453233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 146294Seric { 14716150Seric while ((p = index(p, '\001')) != NULL) 1483233Seric if (*++p == 'u') 1493233Seric break; 1503233Seric if (p != NULL) 1513233Seric break; 1523233Seric 1533233Seric /* this entry is safe -- go ahead and process it */ 1549370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1553233Seric *pvp++ = newstr(buf); 1563233Seric if (pvp >= &pv[MAXPV - 3]) 1573233Seric { 1583233Seric syserr("Too many parameters to %s before $u", pv[0]); 1593233Seric return (-1); 1603233Seric } 161294Seric } 1624863Seric 1636038Seric /* 1646038Seric ** If we have no substitution for the user name in the argument 1656038Seric ** list, we know that we must supply the names otherwise -- and 1666038Seric ** SMTP is the answer!! 1676038Seric */ 1686038Seric 1693233Seric if (*mvp == NULL) 1704863Seric { 1714863Seric /* running SMTP */ 1725179Seric # ifdef SMTP 1734863Seric clever = TRUE; 1744863Seric *pvp = NULL; 1755179Seric # else SMTP 1766038Seric /* oops! we don't implement SMTP */ 1775179Seric syserr("SMTP style mailer"); 1785179Seric return (EX_SOFTWARE); 1795179Seric # endif SMTP 1804863Seric } 181294Seric 182294Seric /* 1833233Seric ** At this point *mvp points to the argument with $u. We 1843233Seric ** run through our address list and append all the addresses 1853233Seric ** we can. If we run out of space, do not fret! We can 1863233Seric ** always send another copy later. 187294Seric */ 188294Seric 1893233Seric tobuf[0] = '\0'; 1909370Seric e->e_to = tobuf; 1914397Seric ctladdr = NULL; 1923233Seric for (; to != NULL; to = to->q_next) 193294Seric { 1943233Seric /* avoid sending multiple recipients to dumb mailers */ 19510682Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 1963233Seric break; 1973233Seric 1983233Seric /* if already sent or not for this host, don't send */ 1997052Seric if (bitset(QDONTSEND, to->q_flags) || 2007052Seric strcmp(to->q_host, host) != 0 || 2017052Seric to->q_mailer != firstto->q_mailer) 2023233Seric continue; 2034397Seric 2048225Seric /* avoid overflowing tobuf */ 2059370Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 2068225Seric break; 2078225Seric 2085032Seric # ifdef DEBUG 2097672Seric if (tTd(10, 1)) 2105032Seric { 2115032Seric printf("\nsend to "); 2125032Seric printaddr(to, FALSE); 2135032Seric } 2145032Seric # endif DEBUG 2155032Seric 2164397Seric /* compute effective uid/gid when sending */ 2174596Seric if (to->q_mailer == ProgMailer) 2184397Seric ctladdr = getctladdr(to); 2194397Seric 2203233Seric user = to->q_user; 2219370Seric e->e_to = to->q_paddr; 2223233Seric to->q_flags |= QDONTSEND; 2233233Seric 2243233Seric /* 2253233Seric ** Check to see that these people are allowed to 2263233Seric ** talk to each other. 2273233Seric */ 2283233Seric 22910699Seric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 23010699Seric { 23110699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 23210699Seric NoReturn = TRUE; 23310699Seric giveresponse(EX_UNAVAILABLE, m, e); 23410699Seric continue; 23510699Seric } 2363233Seric if (!checkcompat(to)) 237294Seric { 23810105Seric giveresponse(EX_UNAVAILABLE, m, e); 2393233Seric continue; 240294Seric } 2413233Seric 2423233Seric /* 2434099Seric ** Strip quote bits from names if the mailer is dumb 2444099Seric ** about them. 2453233Seric */ 2463233Seric 24710682Seric if (bitnset(M_STRIPQ, m->m_flags)) 248294Seric { 2494099Seric stripquotes(user, TRUE); 2504099Seric stripquotes(host, TRUE); 2513233Seric } 2524099Seric else 2534099Seric { 2544099Seric stripquotes(user, FALSE); 2554099Seric stripquotes(host, FALSE); 2564099Seric } 2573233Seric 2589206Seric /* hack attack -- delivermail compatibility */ 2599206Seric if (m == ProgMailer && *user == '|') 2609206Seric user++; 2619206Seric 2623233Seric /* 2634161Seric ** If an error message has already been given, don't 2644161Seric ** bother to send to this address. 2654161Seric ** 2664161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2674161Seric ** >> NOTE >> cannot do any further aliasing; that 2684161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2694161Seric */ 2704161Seric 2717293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2724161Seric continue; 2734161Seric 2744283Seric /* save statistics.... */ 2759370Seric markstats(e, to); 2764283Seric 2774161Seric /* 2783233Seric ** See if this user name is "special". 2793233Seric ** If the user name has a slash in it, assume that this 2806974Seric ** is a file -- send it off without further ado. Note 2816974Seric ** that this type of addresses is not processed along 2826974Seric ** with the others, so we fudge on the To person. 2833233Seric */ 2843233Seric 2854596Seric if (m == LocalMailer) 2863233Seric { 2875599Seric if (user[0] == '/') 288294Seric { 2898003Seric rcode = mailfile(user, getctladdr(to)); 29010105Seric giveresponse(rcode, m, e); 2913233Seric continue; 292294Seric } 293294Seric } 2943233Seric 2954315Seric /* 2964315Seric ** Address is verified -- add this user to mailer 2974315Seric ** argv, and add it to the print list of recipients. 2984315Seric */ 2994315Seric 3006059Seric /* link together the chain of recipients */ 3016272Seric to->q_tchain = tochain; 3026272Seric tochain = to; 3036059Seric 3043233Seric /* create list of users for error messages */ 3059388Seric (void) strcat(tobuf, ","); 3064082Seric (void) strcat(tobuf, to->q_paddr); 3079370Seric define('u', user, e); /* to user */ 3089370Seric define('z', to->q_home, e); /* user's home */ 3093233Seric 3104863Seric /* 3116059Seric ** Expand out this user into argument list. 3124863Seric */ 3134863Seric 3146059Seric if (!clever) 3153233Seric { 3169370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3174863Seric *pvp++ = newstr(buf); 3184863Seric if (pvp >= &pv[MAXPV - 2]) 3194863Seric { 3204863Seric /* allow some space for trailing parms */ 3214863Seric break; 3224863Seric } 3234863Seric } 324294Seric } 325294Seric 3264067Seric /* see if any addresses still exist */ 3274067Seric if (tobuf[0] == '\0') 3284863Seric { 3299370Seric define('g', (char *) NULL, e); 3304067Seric return (0); 3314863Seric } 3324067Seric 3333233Seric /* print out messages as full list */ 3349388Seric e->e_to = tobuf + 1; 3353233Seric 336294Seric /* 3373233Seric ** Fill out any parameters after the $u parameter. 338294Seric */ 339294Seric 3404863Seric while (!clever && *++mvp != NULL) 341294Seric { 3429370Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3433233Seric *pvp++ = newstr(buf); 3443233Seric if (pvp >= &pv[MAXPV]) 3453233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 346294Seric } 3473233Seric *pvp++ = NULL; 348294Seric 349294Seric /* 350294Seric ** Call the mailer. 3512898Seric ** The argument vector gets built, pipes 352294Seric ** are created as necessary, and we fork & exec as 3532898Seric ** appropriate. 3544863Seric ** If we are running SMTP, we just need to clean up. 355294Seric */ 356294Seric 3579370Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 3589370Seric 3594397Seric if (ctladdr == NULL) 3609370Seric ctladdr = &e->e_from; 3615179Seric # ifdef SMTP 3624863Seric if (clever) 3634863Seric { 36429655Sbloom # ifdef MXDOMAIN 36529655Sbloom expand("\001w", buf, &buf[sizeof buf - 1], e); 366*29865Seric if ((Nmx = getmxrr(host, MxHosts, MAXMXHOSTS, buf)) < 0) 36729655Sbloom { 36829655Sbloom /* 36929655Sbloom * Map errors into standard values 37029655Sbloom */ 371*29865Seric if (Nmx == -1) 37229655Sbloom rcode = EX_TEMPFAIL; 373*29865Seric else if (Nmx == -3) 37429655Sbloom rcode = EX_NOHOST; 37529655Sbloom else 37629655Sbloom rcode = EX_UNAVAILABLE; 37729655Sbloom } 37829655Sbloom else 37929655Sbloom rcode = EX_OK; 38029655Sbloom #else MXDOMAIN 381*29865Seric Nmx = 1; 382*29865Seric MxHosts[0] = q->q_host; 38329655Sbloom rcode = EX_OK; 38429655Sbloom #endif 3859370Seric /* send the initial SMTP protocol */ 38629655Sbloom if (rcode == EX_OK) 38729655Sbloom rcode = smtpinit(m, pv); 3889370Seric 3899388Seric if (rcode == EX_OK) 3909370Seric { 3919388Seric /* send the recipient list */ 3929388Seric tobuf[0] = '\0'; 3939388Seric for (to = tochain; to != NULL; to = to->q_tchain) 3949388Seric { 3959388Seric int i; 3969370Seric 3979388Seric e->e_to = to->q_paddr; 39810168Seric i = smtprcpt(to, m); 3999388Seric if (i != EX_OK) 4009388Seric { 40110092Seric markfailure(e, to, i); 40210105Seric giveresponse(i, m, e); 4039388Seric } 4049388Seric else 4059388Seric { 40623102Seric (void) strcat(tobuf, ","); 40723102Seric (void) strcat(tobuf, to->q_paddr); 4089388Seric } 4099388Seric } 4109388Seric 4119388Seric /* now send the data */ 4129388Seric if (tobuf[0] == '\0') 4139388Seric e->e_to = NULL; 4149370Seric else 4159370Seric { 4169388Seric e->e_to = tobuf + 1; 41710168Seric rcode = smtpdata(m, e); 4189370Seric } 4199388Seric 4209388Seric /* now close the connection */ 42115531Seric smtpquit(m); 4229370Seric } 4234863Seric } 4244863Seric else 4255179Seric # endif SMTP 42610168Seric rcode = sendoff(e, m, pv, ctladdr); 4273233Seric 4284621Seric /* 4299388Seric ** Do final status disposal. 4309388Seric ** We check for something in tobuf for the SMTP case. 4319388Seric ** If we got a temporary failure, arrange to queue the 4329388Seric ** addressees. 4334621Seric */ 4344621Seric 4359388Seric if (tobuf[0] != '\0') 43610105Seric giveresponse(rcode, m, e); 4379388Seric if (rcode != EX_OK) 4384621Seric { 4395032Seric for (to = tochain; to != NULL; to = to->q_tchain) 44010092Seric markfailure(e, to, rcode); 4414621Seric } 4424621Seric 4434488Seric errno = 0; 4449370Seric define('g', (char *) NULL, e); 4458003Seric return (rcode); 4463233Seric } 4473233Seric /* 44810092Seric ** MARKFAILURE -- mark a failure on a specific address. 44910092Seric ** 45010092Seric ** Parameters: 45110092Seric ** e -- the envelope we are sending. 45210092Seric ** q -- the address to mark. 45310092Seric ** rcode -- the code signifying the particular failure. 45410092Seric ** 45510092Seric ** Returns: 45610092Seric ** none. 45710092Seric ** 45810092Seric ** Side Effects: 45910092Seric ** marks the address (and possibly the envelope) with the 46010092Seric ** failure so that an error will be returned or 46110092Seric ** the message will be queued, as appropriate. 46210092Seric */ 46310092Seric 46410092Seric markfailure(e, q, rcode) 46510092Seric register ENVELOPE *e; 46610092Seric register ADDRESS *q; 46710092Seric int rcode; 46810092Seric { 46910092Seric if (rcode == EX_OK) 47010092Seric return; 47110092Seric else if (rcode != EX_TEMPFAIL) 47210092Seric q->q_flags |= QBADADDR; 47310092Seric else if (curtime() > e->e_ctime + TimeOut) 47410092Seric { 47510092Seric extern char *pintvl(); 47610105Seric char buf[MAXLINE]; 47710092Seric 47810092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 47910105Seric { 48010105Seric (void) sprintf(buf, "Cannot send message for %s", 48110092Seric pintvl(TimeOut, FALSE)); 48210105Seric if (e->e_message != NULL) 48310105Seric free(e->e_message); 48410105Seric e->e_message = newstr(buf); 48510105Seric message(Arpa_Info, buf); 48610105Seric } 48710092Seric q->q_flags |= QBADADDR; 48810092Seric e->e_flags |= EF_TIMEOUT; 48910092Seric } 49010092Seric else 49110092Seric q->q_flags |= QQUEUEUP; 49210092Seric } 49310092Seric /* 4944214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4954214Seric ** 4964214Seric ** This MUST be a macro, since after a vfork we are running 4974214Seric ** two processes on the same stack!!! 4984214Seric ** 4994214Seric ** Parameters: 5004214Seric ** none. 5014214Seric ** 5024214Seric ** Returns: 5034214Seric ** From a macro??? You've got to be kidding! 5044214Seric ** 5054214Seric ** Side Effects: 5064214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5074214Seric ** pid of child in parent, zero in child. 5084214Seric ** -1 on unrecoverable error. 5094214Seric ** 5104214Seric ** Notes: 5114214Seric ** I'm awfully sorry this looks so awful. That's 5124214Seric ** vfork for you..... 5134214Seric */ 5144214Seric 5154214Seric # define NFORKTRIES 5 5169148Seric # ifdef VMUNIX 5174214Seric # define XFORK vfork 5189148Seric # else VMUNIX 5194214Seric # define XFORK fork 5209148Seric # endif VMUNIX 5214214Seric 5224214Seric # define DOFORK(fORKfN) \ 5234214Seric {\ 5244214Seric register int i;\ 5254214Seric \ 52623504Seric for (i = NFORKTRIES; --i >= 0; )\ 5274214Seric {\ 5284214Seric pid = fORKfN();\ 5294214Seric if (pid >= 0)\ 5304214Seric break;\ 53123504Seric if (i > 0)\ 53225617Seric sleep((unsigned) NFORKTRIES - i);\ 5334214Seric }\ 5344214Seric } 5354214Seric /* 5364637Seric ** DOFORK -- simple fork interface to DOFORK. 5374637Seric ** 5384637Seric ** Parameters: 5394637Seric ** none. 5404637Seric ** 5414637Seric ** Returns: 5424637Seric ** pid of child in parent. 5434637Seric ** zero in child. 5444637Seric ** -1 on error. 5454637Seric ** 5464637Seric ** Side Effects: 5474637Seric ** returns twice, once in parent and once in child. 5484637Seric */ 5494637Seric 5504637Seric dofork() 5514637Seric { 5524637Seric register int pid; 5534637Seric 5544637Seric DOFORK(fork); 5554637Seric return (pid); 5564637Seric } 5574637Seric /* 5583233Seric ** SENDOFF -- send off call to mailer & collect response. 5593233Seric ** 5603233Seric ** Parameters: 5619370Seric ** e -- the envelope to mail. 5623233Seric ** m -- mailer descriptor. 5633233Seric ** pvp -- parameter vector to send to it. 5644397Seric ** ctladdr -- an address pointer controlling the 5654397Seric ** user/groupid etc. of the mailer. 5663233Seric ** 5673233Seric ** Returns: 5683233Seric ** exit status of mailer. 5693233Seric ** 5703233Seric ** Side Effects: 5713233Seric ** none. 5723233Seric */ 5733233Seric 57410168Seric sendoff(e, m, pvp, ctladdr) 5759370Seric register ENVELOPE *e; 5769370Seric MAILER *m; 5773233Seric char **pvp; 5784397Seric ADDRESS *ctladdr; 5793233Seric { 5804863Seric auto FILE *mfile; 5814863Seric auto FILE *rfile; 5823233Seric register int i; 5833233Seric int pid; 5844863Seric 5854863Seric /* 5864863Seric ** Create connection to mailer. 5874863Seric */ 5884863Seric 5894863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5904863Seric if (pid < 0) 5914863Seric return (-1); 5924863Seric 5934863Seric /* 5944863Seric ** Format and send message. 5954863Seric */ 5964863Seric 59710168Seric putfromline(mfile, m); 59810168Seric (*e->e_puthdr)(mfile, m, e); 59910168Seric putline("\n", mfile, m); 60010168Seric (*e->e_putbody)(mfile, m, e); 6014863Seric (void) fclose(mfile); 6024863Seric 6034863Seric i = endmailer(pid, pvp[0]); 6045981Seric 6055981Seric /* arrange a return receipt if requested */ 60610682Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 6075981Seric { 6089370Seric e->e_flags |= EF_SENDRECEIPT; 6095981Seric /* do we want to send back more info? */ 6105981Seric } 6115981Seric 6124863Seric return (i); 6134863Seric } 6144863Seric /* 6154863Seric ** ENDMAILER -- Wait for mailer to terminate. 6164863Seric ** 6174863Seric ** We should never get fatal errors (e.g., segmentation 6184863Seric ** violation), so we report those specially. For other 6194863Seric ** errors, we choose a status message (into statmsg), 6204863Seric ** and if it represents an error, we print it. 6214863Seric ** 6224863Seric ** Parameters: 6234863Seric ** pid -- pid of mailer. 6244863Seric ** name -- name of mailer (for error messages). 6254863Seric ** 6264863Seric ** Returns: 6274863Seric ** exit code of mailer. 6284863Seric ** 6294863Seric ** Side Effects: 6304863Seric ** none. 6314863Seric */ 6324863Seric 6334863Seric endmailer(pid, name) 6344863Seric int pid; 6354863Seric char *name; 6364863Seric { 6379370Seric int st; 6384863Seric 6396038Seric /* in the IPC case there is nothing to wait for */ 6406038Seric if (pid == 0) 6416038Seric return (EX_OK); 6426038Seric 6436038Seric /* wait for the mailer process to die and collect status */ 6449370Seric st = waitfor(pid); 6459370Seric if (st == -1) 6468127Seric { 6479370Seric syserr("endmailer %s: wait", name); 6489370Seric return (EX_SOFTWARE); 6494863Seric } 6506038Seric 6516038Seric /* see if it died a horrid death */ 6524863Seric if ((st & 0377) != 0) 6534863Seric { 65424941Seric syserr("mailer %s died with signal %o", name, st); 65524941Seric ExitStat = EX_TEMPFAIL; 65624941Seric return (EX_TEMPFAIL); 6574863Seric } 6586038Seric 6596038Seric /* normal death -- return status */ 6609370Seric st = (st >> 8) & 0377; 6619370Seric return (st); 6624863Seric } 6634863Seric /* 6644863Seric ** OPENMAILER -- open connection to mailer. 6654863Seric ** 6664863Seric ** Parameters: 6674863Seric ** m -- mailer descriptor. 6684863Seric ** pvp -- parameter vector to pass to mailer. 6694863Seric ** ctladdr -- controlling address for user. 6704863Seric ** clever -- create a full duplex connection. 6714863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6724863Seric ** prfile -- pointer to rfile (from mailer) connection. 6734863Seric ** 6744863Seric ** Returns: 6756038Seric ** pid of mailer ( > 0 ). 6764863Seric ** -1 on error. 6776038Seric ** zero on an IPC connection. 6784863Seric ** 6794863Seric ** Side Effects: 6804863Seric ** creates a mailer in a subprocess. 6814863Seric */ 6824863Seric 6834863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6849370Seric MAILER *m; 6854863Seric char **pvp; 6864863Seric ADDRESS *ctladdr; 6874863Seric bool clever; 6884863Seric FILE **pmfile; 6894863Seric FILE **prfile; 6904863Seric { 6914863Seric int pid; 6924709Seric int mpvect[2]; 6934863Seric int rpvect[2]; 6943233Seric FILE *mfile; 6954863Seric FILE *rfile; 6963233Seric extern FILE *fdopen(); 6973233Seric 6983233Seric # ifdef DEBUG 6997672Seric if (tTd(11, 1)) 700294Seric { 7018178Seric printf("openmailer:"); 7023233Seric printav(pvp); 703294Seric } 7043233Seric # endif DEBUG 7054488Seric errno = 0; 7063233Seric 70725050Seric CurHostName = m->m_mailer; 70825050Seric 7096038Seric /* 7106038Seric ** Deal with the special case of mail handled through an IPC 7116038Seric ** connection. 7126038Seric ** In this case we don't actually fork. We must be 7136038Seric ** running SMTP for this to work. We will return a 7146038Seric ** zero pid to indicate that we are running IPC. 71511160Seric ** We also handle a debug version that just talks to stdin/out. 7166038Seric */ 7176038Seric 71811160Seric #ifdef DEBUG 71911160Seric /* check for Local Person Communication -- not for mortals!!! */ 72011160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 72111160Seric { 72211160Seric *pmfile = stdout; 72311160Seric *prfile = stdin; 72411160Seric return (0); 72511160Seric } 72611160Seric #endif DEBUG 72711160Seric 7286038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 7296038Seric { 73024941Seric #ifdef HOSTINFO 73124941Seric register STAB *st; 73224941Seric extern STAB *stab(); 73324941Seric #endif HOSTINFO 7349370Seric #ifdef DAEMON 73529433Sbloom register int i, j; 7367285Seric register u_short port; 7376038Seric 73825050Seric CurHostName = pvp[1]; 7396038Seric if (!clever) 7406038Seric syserr("non-clever IPC"); 7416632Seric if (pvp[2] != NULL) 7427285Seric port = atoi(pvp[2]); 7436632Seric else 7447285Seric port = 0; 745*29865Seric for (j = 0; j < Nmx; j++) 74629433Sbloom { 747*29865Seric CurHostName = MxHosts[j]; 74824941Seric #ifdef HOSTINFO 74924941Seric /* see if we have already determined that this host is fried */ 750*29865Seric st = stab(MxHosts[j], ST_HOST, ST_FIND); 75129433Sbloom if (st == NULL || st->s_host.ho_exitstat == EX_OK) 752*29865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 75329433Sbloom else 75429433Sbloom { 75529433Sbloom i = st->s_host.ho_exitstat; 75629433Sbloom errno = st->s_host.ho_errno; 75729433Sbloom } 75824941Seric #else HOSTINFO 759*29865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 76024941Seric #endif HOSTINFO 76129433Sbloom if (i != EX_OK) 76229433Sbloom { 76324941Seric #ifdef HOSTINFO 76429433Sbloom /* enter status of this host */ 76529433Sbloom if (st == NULL) 766*29865Seric st = stab(MxHosts[j], ST_HOST, ST_ENTER); 76729433Sbloom st->s_host.ho_exitstat = i; 76829433Sbloom st->s_host.ho_errno = errno; 76924941Seric #endif HOSTINFO 77029433Sbloom ExitStat = i; 77129433Sbloom continue; 77229433Sbloom } 77329433Sbloom else 77429433Sbloom return (0); 7756047Seric } 77629433Sbloom return (-1); 7779370Seric #else DAEMON 7789370Seric syserr("openmailer: no IPC"); 7799370Seric return (-1); 7809370Seric #endif DAEMON 7816038Seric } 7826038Seric 7832898Seric /* create a pipe to shove the mail through */ 7844709Seric if (pipe(mpvect) < 0) 785294Seric { 7869370Seric syserr("openmailer: pipe (to mailer)"); 787294Seric return (-1); 788294Seric } 7894863Seric 7909370Seric #ifdef SMTP 7914863Seric /* if this mailer speaks smtp, create a return pipe */ 7924863Seric if (clever && pipe(rpvect) < 0) 7934863Seric { 7949370Seric syserr("openmailer: pipe (from mailer)"); 7954863Seric (void) close(mpvect[0]); 7964863Seric (void) close(mpvect[1]); 7974863Seric return (-1); 7984863Seric } 7999370Seric #endif SMTP 8004863Seric 8016038Seric /* 8026038Seric ** Actually fork the mailer process. 8036038Seric ** DOFORK is clever about retrying. 80426434Seric ** 80526434Seric ** Dispose of SIGCHLD signal catchers that may be laying 80626434Seric ** around so that endmail will get it. 8076038Seric */ 8086038Seric 8099538Seric if (CurEnv->e_xfp != NULL) 8109538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 8119370Seric (void) fflush(stdout); 81226434Seric # ifdef SIGCHLD 81326434Seric (void) signal(SIGCHLD, SIG_DFL); 81426434Seric # endif SIGCHLD 8154214Seric DOFORK(XFORK); 8164327Seric /* pid is set by DOFORK */ 817294Seric if (pid < 0) 818294Seric { 8196038Seric /* failure */ 8209370Seric syserr("openmailer: cannot fork"); 8214709Seric (void) close(mpvect[0]); 8224709Seric (void) close(mpvect[1]); 8239370Seric #ifdef SMTP 8244863Seric if (clever) 8254863Seric { 8264863Seric (void) close(rpvect[0]); 8274863Seric (void) close(rpvect[1]); 8284863Seric } 8299370Seric #endif SMTP 830294Seric return (-1); 831294Seric } 832294Seric else if (pid == 0) 833294Seric { 83415772Seric int i; 83524941Seric extern int DtableSize; 83615772Seric 837294Seric /* child -- set up input & exec mailer */ 8381621Seric /* make diagnostic output be standard output */ 8394477Seric (void) signal(SIGINT, SIG_IGN); 8404477Seric (void) signal(SIGHUP, SIG_IGN); 8414215Seric (void) signal(SIGTERM, SIG_DFL); 8424709Seric 8434709Seric /* arrange to filter standard & diag output of command */ 8444863Seric if (clever) 8454709Seric { 8464863Seric (void) close(rpvect[0]); 8474709Seric (void) close(1); 8484863Seric (void) dup(rpvect[1]); 8494863Seric (void) close(rpvect[1]); 8504863Seric } 8519275Seric else if (OpMode == MD_SMTP || HoldErrs) 8524863Seric { 8539370Seric /* put mailer output in transcript */ 8544863Seric (void) close(1); 8559538Seric (void) dup(fileno(CurEnv->e_xfp)); 8564709Seric } 8574082Seric (void) close(2); 8584082Seric (void) dup(1); 8594709Seric 8604709Seric /* arrange to get standard input */ 8614709Seric (void) close(mpvect[1]); 8624082Seric (void) close(0); 8634709Seric if (dup(mpvect[0]) < 0) 864294Seric { 8652898Seric syserr("Cannot dup to zero!"); 8662898Seric _exit(EX_OSERR); 867294Seric } 8684709Seric (void) close(mpvect[0]); 86910682Seric if (!bitnset(M_RESTR, m->m_flags)) 8704215Seric { 87116883Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 8724417Seric { 8734417Seric (void) setgid(DefGid); 8744417Seric (void) setuid(DefUid); 8754417Seric } 8764417Seric else 8774415Seric { 8784417Seric (void) setgid(ctladdr->q_gid); 8794417Seric (void) setuid(ctladdr->q_uid); 8804415Seric } 8814215Seric } 8829370Seric 88315772Seric /* arrange for all the files to be closed */ 88424941Seric for (i = 3; i < DtableSize; i++) 88515772Seric #ifdef FIOCLEX 88615772Seric (void) ioctl(i, FIOCLEX, 0); 88715772Seric #else FIOCLEX 88815772Seric (void) close(i); 88915772Seric #endif FIOCLEX 8902774Seric 8916038Seric /* try to execute the mailer */ 89225026Seric execve(m->m_mailer, pvp, UserEnviron); 8936038Seric 89415772Seric #ifdef FIOCLEX 89515772Seric syserr("Cannot exec %s", m->m_mailer); 89615772Seric #else FIOCLEX 8974214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 8984082Seric (void) fflush(stdout); 89915772Seric #endif FIOCLEX 90024941Seric if (m == LocalMailer || errno == EIO || errno == EAGAIN || 90124941Seric errno == ENOMEM || errno == EPROCLIM) 90216902Seric _exit(EX_TEMPFAIL); 90316902Seric else 90416902Seric _exit(EX_UNAVAILABLE); 905294Seric } 906294Seric 9074709Seric /* 9084863Seric ** Set up return value. 9094709Seric */ 9104709Seric 9114709Seric (void) close(mpvect[0]); 9124709Seric mfile = fdopen(mpvect[1], "w"); 9134863Seric if (clever) 9144863Seric { 9154863Seric (void) close(rpvect[1]); 9164863Seric rfile = fdopen(rpvect[0], "r"); 9174863Seric } 918294Seric 9194863Seric *pmfile = mfile; 9204863Seric *prfile = rfile; 921294Seric 9224863Seric return (pid); 923294Seric } 924294Seric /* 925294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 926294Seric ** 927294Seric ** Parameters: 928294Seric ** stat -- the status code from the mailer (high byte 929294Seric ** only; core dumps must have been taken care of 930294Seric ** already). 931294Seric ** m -- the mailer descriptor for this mailer. 932294Seric ** 933294Seric ** Returns: 9344082Seric ** none. 935294Seric ** 936294Seric ** Side Effects: 9371518Seric ** Errors may be incremented. 938294Seric ** ExitStat may be set. 939294Seric */ 940294Seric 94110105Seric giveresponse(stat, m, e) 942294Seric int stat; 9439370Seric register MAILER *m; 94410105Seric ENVELOPE *e; 945294Seric { 946294Seric register char *statmsg; 947294Seric extern char *SysExMsg[]; 948294Seric register int i; 949294Seric extern int N_SysEx; 95010105Seric char buf[MAXLINE]; 951294Seric 95212135Seric #ifdef lint 95312135Seric if (m == NULL) 95412135Seric return; 95512135Seric #endif lint 95612135Seric 9574315Seric /* 9584315Seric ** Compute status message from code. 9594315Seric */ 9604315Seric 961294Seric i = stat - EX__BASE; 9629370Seric if (stat == 0) 9639370Seric statmsg = "250 Sent"; 9649370Seric else if (i < 0 || i > N_SysEx) 9659370Seric { 9669370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 9679370Seric stat = EX_UNAVAILABLE; 9689370Seric statmsg = buf; 9699370Seric } 97010105Seric else if (stat == EX_TEMPFAIL) 97110105Seric { 97210124Seric (void) strcpy(buf, SysExMsg[i]); 97325527Smiriam if (h_errno == TRY_AGAIN) 97410105Seric { 97515137Seric extern char *errstring(); 97615137Seric 97725527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 97821061Seric } 97921061Seric else 98021061Seric { 98125527Smiriam if (errno != 0) 98225527Smiriam { 98325527Smiriam extern char *errstring(); 98425527Smiriam 98525527Smiriam statmsg = errstring(errno); 98625527Smiriam } 98725527Smiriam else 98825527Smiriam { 98921061Seric #ifdef SMTP 99025527Smiriam extern char SmtpError[]; 99121061Seric 99225527Smiriam statmsg = SmtpError; 99321061Seric #else SMTP 99425527Smiriam statmsg = NULL; 99521061Seric #endif SMTP 99625527Smiriam } 99721061Seric } 99821061Seric if (statmsg != NULL && statmsg[0] != '\0') 99921061Seric { 100010124Seric (void) strcat(buf, ": "); 100121061Seric (void) strcat(buf, statmsg); 100210105Seric } 100310105Seric statmsg = buf; 100410105Seric } 1005294Seric else 100621061Seric { 1007294Seric statmsg = SysExMsg[i]; 100821061Seric } 10099370Seric 10109370Seric /* 10119370Seric ** Print the message as appropriate 10129370Seric */ 10139370Seric 101410105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 10158003Seric message(Arpa_Info, &statmsg[4]); 1016294Seric else 1017294Seric { 10181518Seric Errors++; 10199370Seric usrerr(statmsg); 1020294Seric } 1021294Seric 1022294Seric /* 1023294Seric ** Final cleanup. 1024294Seric ** Log a record of the transaction. Compute the new 1025294Seric ** ExitStat -- if we already had an error, stick with 1026294Seric ** that. 1027294Seric */ 1028294Seric 10297680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 10308496Seric logdelivery(&statmsg[4]); 10317858Seric 10324621Seric if (stat != EX_TEMPFAIL) 10334621Seric setstat(stat); 103410105Seric if (stat != EX_OK) 103510105Seric { 103610105Seric if (e->e_message != NULL) 103710105Seric free(e->e_message); 103810105Seric e->e_message = newstr(&statmsg[4]); 103910105Seric } 104010124Seric errno = 0; 104125527Smiriam h_errno = 0; 1042294Seric } 1043294Seric /* 10448496Seric ** LOGDELIVERY -- log the delivery in the system log 10458496Seric ** 10468496Seric ** Parameters: 10478496Seric ** stat -- the message to print for the status 10488496Seric ** 10498496Seric ** Returns: 10508496Seric ** none 10518496Seric ** 10528496Seric ** Side Effects: 10538496Seric ** none 10548496Seric */ 10558496Seric 10568496Seric logdelivery(stat) 10578496Seric char *stat; 10588496Seric { 10598496Seric extern char *pintvl(); 10608496Seric 10618496Seric # ifdef LOG 10628496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 10638496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 10648496Seric # endif LOG 10658496Seric } 10668496Seric /* 10676974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1068294Seric ** 10696974Seric ** This can be made an arbitrary message separator by changing $l 1070294Seric ** 107116150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 107216150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 107316150Seric ** does a well-meaning programmer such as myself have to deal with 107416150Seric ** this kind of antique garbage???? 10756974Seric ** 1076294Seric ** Parameters: 10776974Seric ** fp -- the file to output to. 10786974Seric ** m -- the mailer describing this entry. 1079294Seric ** 1080294Seric ** Returns: 10816974Seric ** none 1082294Seric ** 1083294Seric ** Side Effects: 10846974Seric ** outputs some text to fp. 1085294Seric */ 1086294Seric 108710168Seric putfromline(fp, m) 10886974Seric register FILE *fp; 10896974Seric register MAILER *m; 1090294Seric { 109116150Seric char *template = "\001l\n"; 10926974Seric char buf[MAXLINE]; 1093294Seric 109410682Seric if (bitnset(M_NHDR, m->m_flags)) 10956974Seric return; 10964315Seric 10976974Seric # ifdef UGLYUUCP 109810682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 10994205Seric { 110012223Seric char *bang; 110112223Seric char xbuf[MAXLINE]; 11026041Seric 110316150Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 110412223Seric bang = index(buf, '!'); 11056974Seric if (bang == NULL) 110612223Seric syserr("No ! in UUCP! (%s)", buf); 11075099Seric else 11089370Seric { 110912223Seric *bang++ = '\0'; 111016150Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 111112223Seric template = xbuf; 11129370Seric } 11136974Seric } 11145179Seric # endif UGLYUUCP 111512223Seric expand(template, buf, &buf[sizeof buf - 1], CurEnv); 111610168Seric putline(buf, fp, m); 11175981Seric } 11185981Seric /* 11196974Seric ** PUTBODY -- put the body of a message. 11206974Seric ** 11216974Seric ** Parameters: 11226974Seric ** fp -- file to output onto. 112310168Seric ** m -- a mailer descriptor to control output format. 11249538Seric ** e -- the envelope to put out. 11256974Seric ** 11266974Seric ** Returns: 11276974Seric ** none. 11286974Seric ** 11296974Seric ** Side Effects: 11306974Seric ** The message is written onto fp. 11316974Seric */ 11326974Seric 113310168Seric putbody(fp, m, e) 11346974Seric FILE *fp; 11359370Seric MAILER *m; 11369538Seric register ENVELOPE *e; 11376974Seric { 113810168Seric char buf[MAXLINE]; 11396974Seric 11406974Seric /* 11416974Seric ** Output the body of the message 11426974Seric */ 11436974Seric 11449538Seric if (e->e_dfp == NULL) 11456974Seric { 11469538Seric if (e->e_df != NULL) 11479538Seric { 11489538Seric e->e_dfp = fopen(e->e_df, "r"); 11499538Seric if (e->e_dfp == NULL) 11509538Seric syserr("Cannot open %s", e->e_df); 11519538Seric } 11529538Seric else 115310168Seric putline("<<< No Message Collected >>>", fp, m); 11549538Seric } 11559538Seric if (e->e_dfp != NULL) 11569538Seric { 11579538Seric rewind(e->e_dfp); 115810168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 115916875Seric { 116016875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 116116875Seric strncmp(buf, "From", 4) == 0) 116223102Seric (void) putc('>', fp); 116310168Seric putline(buf, fp, m); 116416875Seric } 11656974Seric 11669538Seric if (ferror(e->e_dfp)) 11676974Seric { 11686974Seric syserr("putbody: read error"); 11696974Seric ExitStat = EX_IOERR; 11706974Seric } 11716974Seric } 11726974Seric 11736974Seric (void) fflush(fp); 11746974Seric if (ferror(fp) && errno != EPIPE) 11756974Seric { 11766974Seric syserr("putbody: write error"); 11776974Seric ExitStat = EX_IOERR; 11786974Seric } 11796974Seric errno = 0; 11806974Seric } 11816974Seric /* 1182294Seric ** MAILFILE -- Send a message to a file. 1183294Seric ** 11844327Seric ** If the file has the setuid/setgid bits set, but NO execute 11854327Seric ** bits, sendmail will try to become the owner of that file 11864327Seric ** rather than the real user. Obviously, this only works if 11874327Seric ** sendmail runs as root. 11884327Seric ** 11899370Seric ** This could be done as a subordinate mailer, except that it 11909370Seric ** is used implicitly to save messages in ~/dead.letter. We 11919370Seric ** view this as being sufficiently important as to include it 11929370Seric ** here. For example, if the system is dying, we shouldn't have 11939370Seric ** to create another process plus some pipes to save the message. 11949370Seric ** 1195294Seric ** Parameters: 1196294Seric ** filename -- the name of the file to send to. 11974397Seric ** ctladdr -- the controlling address header -- includes 11984397Seric ** the userid/groupid to be when sending. 1199294Seric ** 1200294Seric ** Returns: 1201294Seric ** The exit code associated with the operation. 1202294Seric ** 1203294Seric ** Side Effects: 1204294Seric ** none. 1205294Seric */ 1206294Seric 12074397Seric mailfile(filename, ctladdr) 1208294Seric char *filename; 12094397Seric ADDRESS *ctladdr; 1210294Seric { 1211294Seric register FILE *f; 12124214Seric register int pid; 1213294Seric 12144214Seric /* 12154214Seric ** Fork so we can change permissions here. 12164214Seric ** Note that we MUST use fork, not vfork, because of 12174214Seric ** the complications of calling subroutines, etc. 12184214Seric */ 12194067Seric 12204214Seric DOFORK(fork); 12214214Seric 12224214Seric if (pid < 0) 12234214Seric return (EX_OSERR); 12244214Seric else if (pid == 0) 12254214Seric { 12264214Seric /* child -- actually write to file */ 12274327Seric struct stat stb; 12284327Seric 12294215Seric (void) signal(SIGINT, SIG_DFL); 12304215Seric (void) signal(SIGHUP, SIG_DFL); 12314215Seric (void) signal(SIGTERM, SIG_DFL); 123223102Seric (void) umask(OldUmask); 12334327Seric if (stat(filename, &stb) < 0) 123411935Seric { 123511935Seric errno = 0; 12364431Seric stb.st_mode = 0666; 123711935Seric } 12384327Seric if (bitset(0111, stb.st_mode)) 12394327Seric exit(EX_CANTCREAT); 12404401Seric if (ctladdr == NULL) 12416900Seric ctladdr = &CurEnv->e_from; 12424327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 12434417Seric { 12444417Seric if (ctladdr->q_uid == 0) 12454417Seric (void) setgid(DefGid); 12464417Seric else 12474417Seric (void) setgid(ctladdr->q_gid); 12484417Seric } 12494327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 12504417Seric { 12514417Seric if (ctladdr->q_uid == 0) 12524417Seric (void) setuid(DefUid); 12534417Seric else 12544417Seric (void) setuid(ctladdr->q_uid); 12554417Seric } 12566887Seric f = dfopen(filename, "a"); 12574214Seric if (f == NULL) 12584214Seric exit(EX_CANTCREAT); 12594214Seric 126010168Seric putfromline(f, ProgMailer); 126110168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 126210168Seric putline("\n", f, ProgMailer); 126310168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 126410168Seric putline("\n", f, ProgMailer); 12654214Seric (void) fclose(f); 12664214Seric (void) fflush(stdout); 12674417Seric 12686887Seric /* reset ISUID & ISGID bits for paranoid systems */ 12694621Seric (void) chmod(filename, (int) stb.st_mode); 12704214Seric exit(EX_OK); 12714315Seric /*NOTREACHED*/ 12724214Seric } 12734214Seric else 12744214Seric { 12754214Seric /* parent -- wait for exit status */ 12769370Seric int st; 12774214Seric 12789370Seric st = waitfor(pid); 12799370Seric if ((st & 0377) != 0) 12809370Seric return (EX_UNAVAILABLE); 12819370Seric else 12829370Seric return ((st >> 8) & 0377); 12834214Seric } 1284294Seric } 12854550Seric /* 12864550Seric ** SENDALL -- actually send all the messages. 12874550Seric ** 12884550Seric ** Parameters: 12897043Seric ** e -- the envelope to send. 129014874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 129114874Seric ** the current SendMode. 12924550Seric ** 12934550Seric ** Returns: 12944550Seric ** none. 12954550Seric ** 12964550Seric ** Side Effects: 12974550Seric ** Scans the send lists and sends everything it finds. 12987043Seric ** Delivers any appropriate error messages. 12999275Seric ** If we are running in a non-interactive mode, takes the 13009275Seric ** appropriate action. 13014550Seric */ 13024550Seric 13039275Seric sendall(e, mode) 13047043Seric ENVELOPE *e; 13059275Seric char mode; 13064550Seric { 13075008Seric register ADDRESS *q; 13087779Seric bool oldverbose; 13099275Seric int pid; 13104550Seric 131114874Seric /* determine actual delivery mode */ 131214874Seric if (mode == SM_DEFAULT) 131314874Seric { 131424941Seric extern bool shouldqueue(); 131514874Seric 131624941Seric if (shouldqueue(e->e_msgpriority)) 131714874Seric mode = SM_QUEUE; 131814874Seric else 131914874Seric mode = SendMode; 132014874Seric } 132114874Seric 13229370Seric #ifdef DEBUG 13238248Seric if (tTd(13, 1)) 13245032Seric { 13259275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 13267043Seric printaddr(e->e_sendqueue, TRUE); 13275032Seric } 13289370Seric #endif DEBUG 13295008Seric 13307043Seric /* 13319275Seric ** Do any preprocessing necessary for the mode we are running. 13329370Seric ** Check to make sure the hop count is reasonable. 13339370Seric ** Delete sends to the sender in mailing lists. 13347043Seric */ 13357043Seric 13369370Seric CurEnv = e; 13379370Seric 13389370Seric if (e->e_hopcount > MAXHOP) 13399275Seric { 13409370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 13419370Seric return; 13429370Seric } 13439275Seric 13449370Seric if (!MeToo) 13459370Seric { 134612611Seric extern ADDRESS *recipient(); 134712611Seric 13489370Seric e->e_from.q_flags |= QDONTSEND; 134912611Seric (void) recipient(&e->e_from, &e->e_sendqueue); 13509275Seric } 13519370Seric 13529370Seric # ifdef QUEUE 13539335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 13549335Seric (mode != SM_VERIFY && SuperSafe)) && 13559335Seric !bitset(EF_INQUEUE, e->e_flags)) 13569370Seric queueup(e, TRUE, mode == SM_QUEUE); 13579275Seric #endif QUEUE 13589275Seric 13597779Seric oldverbose = Verbose; 13609275Seric switch (mode) 13619275Seric { 13629275Seric case SM_VERIFY: 13637779Seric Verbose = TRUE; 13649275Seric break; 13659275Seric 13669275Seric case SM_QUEUE: 13679335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 13689275Seric return; 13699275Seric 13709275Seric case SM_FORK: 13719538Seric if (e->e_xfp != NULL) 13729538Seric (void) fflush(e->e_xfp); 13739275Seric pid = fork(); 13749275Seric if (pid < 0) 13759275Seric { 13769275Seric mode = SM_DELIVER; 13779275Seric break; 13789275Seric } 13799275Seric else if (pid > 0) 13809293Seric { 13819293Seric /* be sure we leave the temp files to our child */ 13829335Seric e->e_id = e->e_df = NULL; 13839275Seric return; 13849293Seric } 13859275Seric 13869275Seric /* double fork to avoid zombies */ 13879275Seric if (fork() > 0) 13889275Seric exit(EX_OK); 13899275Seric 13909293Seric /* be sure we are immune from the terminal */ 139110133Seric disconnect(FALSE); 13929293Seric 13939275Seric break; 13949275Seric } 13959275Seric 13969275Seric /* 13979275Seric ** Run through the list and send everything. 13989275Seric */ 13999275Seric 14007043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14014550Seric { 14029275Seric if (mode == SM_VERIFY) 14034550Seric { 14049293Seric e->e_to = q->q_paddr; 14055008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14067052Seric message(Arpa_Info, "deliverable"); 14074550Seric } 14085008Seric else 14099370Seric (void) deliver(e, q); 14104550Seric } 14117779Seric Verbose = oldverbose; 14127043Seric 14137043Seric /* 14147043Seric ** Now run through and check for errors. 14157043Seric */ 14167043Seric 14179275Seric if (mode == SM_VERIFY) 14187043Seric return; 14197043Seric 14207043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14217043Seric { 14227043Seric register ADDRESS *qq; 14237043Seric 14248248Seric # ifdef DEBUG 14258248Seric if (tTd(13, 3)) 14268248Seric { 14278248Seric printf("Checking "); 14288248Seric printaddr(q, FALSE); 14298248Seric } 14308248Seric # endif DEBUG 14318248Seric 14329335Seric /* only send errors if the message failed */ 14339335Seric if (!bitset(QBADADDR, q->q_flags)) 14349335Seric continue; 14357043Seric 14367043Seric /* we have an address that failed -- find the parent */ 14377043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14387043Seric { 14397043Seric char obuf[MAXNAME + 6]; 14407043Seric extern char *aliaslookup(); 14417043Seric 14427043Seric /* we can only have owners for local addresses */ 144310682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 14447043Seric continue; 14457043Seric 14467043Seric /* see if the owner list exists */ 14477043Seric (void) strcpy(obuf, "owner-"); 14487047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14497047Seric (void) strcat(obuf, "owner"); 14507047Seric else 14517047Seric (void) strcat(obuf, qq->q_user); 14527043Seric if (aliaslookup(obuf) == NULL) 14537043Seric continue; 14547043Seric 14558248Seric # ifdef DEBUG 14568248Seric if (tTd(13, 4)) 14578248Seric printf("Errors to %s\n", obuf); 14588248Seric # endif DEBUG 14598248Seric 14607043Seric /* owner list exists -- add it to the error queue */ 14619615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 146216883Seric ErrorMode = EM_MAIL; 14637043Seric break; 14647043Seric } 14657043Seric 14667043Seric /* if we did not find an owner, send to the sender */ 14678426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 14689615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 14697043Seric } 14709275Seric 14719275Seric if (mode == SM_FORK) 14729275Seric finis(); 14734550Seric } 1474