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*31952Sbostic static char SccsId[] = "@(#)deliver.c 5.14 (Berkeley) 07/27/87"; 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 { 23129914Seric NoReturn = TRUE; 23210699Seric usrerr("Message is too large; %ld bytes max", m->m_maxsize); 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*31952Sbostic if (host[0] == '[') 36729655Sbloom { 368*31952Sbostic Nmx = 1; 369*31952Sbostic MxHosts[0] = host; 370*31952Sbostic rcode = EX_OK; 371*31952Sbostic } 372*31952Sbostic else if ((Nmx = getmxrr(host, MxHosts, MAXMXHOSTS, buf)) < 0) 373*31952Sbostic { 37429655Sbloom /* 37529655Sbloom * Map errors into standard values 37629655Sbloom */ 37729865Seric if (Nmx == -1) 37829655Sbloom rcode = EX_TEMPFAIL; 37929865Seric else if (Nmx == -3) 38029655Sbloom rcode = EX_NOHOST; 38129655Sbloom else 38229655Sbloom rcode = EX_UNAVAILABLE; 38329655Sbloom } 38429655Sbloom else 38529655Sbloom rcode = EX_OK; 38629655Sbloom #else MXDOMAIN 38729865Seric Nmx = 1; 38829865Seric MxHosts[0] = q->q_host; 38929655Sbloom rcode = EX_OK; 39029655Sbloom #endif 3919370Seric /* send the initial SMTP protocol */ 39229655Sbloom if (rcode == EX_OK) 39329655Sbloom rcode = smtpinit(m, pv); 3949370Seric 3959388Seric if (rcode == EX_OK) 3969370Seric { 3979388Seric /* send the recipient list */ 3989388Seric tobuf[0] = '\0'; 3999388Seric for (to = tochain; to != NULL; to = to->q_tchain) 4009388Seric { 4019388Seric int i; 4029370Seric 4039388Seric e->e_to = to->q_paddr; 40410168Seric i = smtprcpt(to, m); 4059388Seric if (i != EX_OK) 4069388Seric { 40710092Seric markfailure(e, to, i); 40810105Seric giveresponse(i, m, e); 4099388Seric } 4109388Seric else 4119388Seric { 41223102Seric (void) strcat(tobuf, ","); 41323102Seric (void) strcat(tobuf, to->q_paddr); 4149388Seric } 4159388Seric } 4169388Seric 4179388Seric /* now send the data */ 4189388Seric if (tobuf[0] == '\0') 4199388Seric e->e_to = NULL; 4209370Seric else 4219370Seric { 4229388Seric e->e_to = tobuf + 1; 42310168Seric rcode = smtpdata(m, e); 4249370Seric } 4259388Seric 4269388Seric /* now close the connection */ 42715531Seric smtpquit(m); 4289370Seric } 4294863Seric } 4304863Seric else 4315179Seric # endif SMTP 43210168Seric rcode = sendoff(e, m, pv, ctladdr); 4333233Seric 4344621Seric /* 4359388Seric ** Do final status disposal. 4369388Seric ** We check for something in tobuf for the SMTP case. 4379388Seric ** If we got a temporary failure, arrange to queue the 4389388Seric ** addressees. 4394621Seric */ 4404621Seric 4419388Seric if (tobuf[0] != '\0') 44210105Seric giveresponse(rcode, m, e); 4439388Seric if (rcode != EX_OK) 4444621Seric { 4455032Seric for (to = tochain; to != NULL; to = to->q_tchain) 44610092Seric markfailure(e, to, rcode); 4474621Seric } 4484621Seric 4494488Seric errno = 0; 4509370Seric define('g', (char *) NULL, e); 4518003Seric return (rcode); 4523233Seric } 4533233Seric /* 45410092Seric ** MARKFAILURE -- mark a failure on a specific address. 45510092Seric ** 45610092Seric ** Parameters: 45710092Seric ** e -- the envelope we are sending. 45810092Seric ** q -- the address to mark. 45910092Seric ** rcode -- the code signifying the particular failure. 46010092Seric ** 46110092Seric ** Returns: 46210092Seric ** none. 46310092Seric ** 46410092Seric ** Side Effects: 46510092Seric ** marks the address (and possibly the envelope) with the 46610092Seric ** failure so that an error will be returned or 46710092Seric ** the message will be queued, as appropriate. 46810092Seric */ 46910092Seric 47010092Seric markfailure(e, q, rcode) 47110092Seric register ENVELOPE *e; 47210092Seric register ADDRESS *q; 47310092Seric int rcode; 47410092Seric { 47510092Seric if (rcode == EX_OK) 47610092Seric return; 47710092Seric else if (rcode != EX_TEMPFAIL) 47810092Seric q->q_flags |= QBADADDR; 47910092Seric else if (curtime() > e->e_ctime + TimeOut) 48010092Seric { 48110092Seric extern char *pintvl(); 48210105Seric char buf[MAXLINE]; 48310092Seric 48410092Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 48510105Seric { 48610105Seric (void) sprintf(buf, "Cannot send message for %s", 48710092Seric pintvl(TimeOut, FALSE)); 48810105Seric if (e->e_message != NULL) 48910105Seric free(e->e_message); 49010105Seric e->e_message = newstr(buf); 49110105Seric message(Arpa_Info, buf); 49210105Seric } 49310092Seric q->q_flags |= QBADADDR; 49410092Seric e->e_flags |= EF_TIMEOUT; 49510092Seric } 49610092Seric else 49710092Seric q->q_flags |= QQUEUEUP; 49810092Seric } 49910092Seric /* 5004214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5014214Seric ** 5024214Seric ** This MUST be a macro, since after a vfork we are running 5034214Seric ** two processes on the same stack!!! 5044214Seric ** 5054214Seric ** Parameters: 5064214Seric ** none. 5074214Seric ** 5084214Seric ** Returns: 5094214Seric ** From a macro??? You've got to be kidding! 5104214Seric ** 5114214Seric ** Side Effects: 5124214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5134214Seric ** pid of child in parent, zero in child. 5144214Seric ** -1 on unrecoverable error. 5154214Seric ** 5164214Seric ** Notes: 5174214Seric ** I'm awfully sorry this looks so awful. That's 5184214Seric ** vfork for you..... 5194214Seric */ 5204214Seric 5214214Seric # define NFORKTRIES 5 5229148Seric # ifdef VMUNIX 5234214Seric # define XFORK vfork 5249148Seric # else VMUNIX 5254214Seric # define XFORK fork 5269148Seric # endif VMUNIX 5274214Seric 5284214Seric # define DOFORK(fORKfN) \ 5294214Seric {\ 5304214Seric register int i;\ 5314214Seric \ 53223504Seric for (i = NFORKTRIES; --i >= 0; )\ 5334214Seric {\ 5344214Seric pid = fORKfN();\ 5354214Seric if (pid >= 0)\ 5364214Seric break;\ 53723504Seric if (i > 0)\ 53825617Seric sleep((unsigned) NFORKTRIES - i);\ 5394214Seric }\ 5404214Seric } 5414214Seric /* 5424637Seric ** DOFORK -- simple fork interface to DOFORK. 5434637Seric ** 5444637Seric ** Parameters: 5454637Seric ** none. 5464637Seric ** 5474637Seric ** Returns: 5484637Seric ** pid of child in parent. 5494637Seric ** zero in child. 5504637Seric ** -1 on error. 5514637Seric ** 5524637Seric ** Side Effects: 5534637Seric ** returns twice, once in parent and once in child. 5544637Seric */ 5554637Seric 5564637Seric dofork() 5574637Seric { 5584637Seric register int pid; 5594637Seric 5604637Seric DOFORK(fork); 5614637Seric return (pid); 5624637Seric } 5634637Seric /* 5643233Seric ** SENDOFF -- send off call to mailer & collect response. 5653233Seric ** 5663233Seric ** Parameters: 5679370Seric ** e -- the envelope to mail. 5683233Seric ** m -- mailer descriptor. 5693233Seric ** pvp -- parameter vector to send to it. 5704397Seric ** ctladdr -- an address pointer controlling the 5714397Seric ** user/groupid etc. of the mailer. 5723233Seric ** 5733233Seric ** Returns: 5743233Seric ** exit status of mailer. 5753233Seric ** 5763233Seric ** Side Effects: 5773233Seric ** none. 5783233Seric */ 5793233Seric 58010168Seric sendoff(e, m, pvp, ctladdr) 5819370Seric register ENVELOPE *e; 5829370Seric MAILER *m; 5833233Seric char **pvp; 5844397Seric ADDRESS *ctladdr; 5853233Seric { 5864863Seric auto FILE *mfile; 5874863Seric auto FILE *rfile; 5883233Seric register int i; 5893233Seric int pid; 5904863Seric 5914863Seric /* 5924863Seric ** Create connection to mailer. 5934863Seric */ 5944863Seric 5954863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5964863Seric if (pid < 0) 5974863Seric return (-1); 5984863Seric 5994863Seric /* 6004863Seric ** Format and send message. 6014863Seric */ 6024863Seric 60310168Seric putfromline(mfile, m); 60410168Seric (*e->e_puthdr)(mfile, m, e); 60510168Seric putline("\n", mfile, m); 60610168Seric (*e->e_putbody)(mfile, m, e); 6074863Seric (void) fclose(mfile); 6084863Seric 6094863Seric i = endmailer(pid, pvp[0]); 6105981Seric 6115981Seric /* arrange a return receipt if requested */ 61210682Seric if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) 6135981Seric { 6149370Seric e->e_flags |= EF_SENDRECEIPT; 6155981Seric /* do we want to send back more info? */ 6165981Seric } 6175981Seric 6184863Seric return (i); 6194863Seric } 6204863Seric /* 6214863Seric ** ENDMAILER -- Wait for mailer to terminate. 6224863Seric ** 6234863Seric ** We should never get fatal errors (e.g., segmentation 6244863Seric ** violation), so we report those specially. For other 6254863Seric ** errors, we choose a status message (into statmsg), 6264863Seric ** and if it represents an error, we print it. 6274863Seric ** 6284863Seric ** Parameters: 6294863Seric ** pid -- pid of mailer. 6304863Seric ** name -- name of mailer (for error messages). 6314863Seric ** 6324863Seric ** Returns: 6334863Seric ** exit code of mailer. 6344863Seric ** 6354863Seric ** Side Effects: 6364863Seric ** none. 6374863Seric */ 6384863Seric 6394863Seric endmailer(pid, name) 6404863Seric int pid; 6414863Seric char *name; 6424863Seric { 6439370Seric int st; 6444863Seric 6456038Seric /* in the IPC case there is nothing to wait for */ 6466038Seric if (pid == 0) 6476038Seric return (EX_OK); 6486038Seric 6496038Seric /* wait for the mailer process to die and collect status */ 6509370Seric st = waitfor(pid); 6519370Seric if (st == -1) 6528127Seric { 6539370Seric syserr("endmailer %s: wait", name); 6549370Seric return (EX_SOFTWARE); 6554863Seric } 6566038Seric 6576038Seric /* see if it died a horrid death */ 6584863Seric if ((st & 0377) != 0) 6594863Seric { 66024941Seric syserr("mailer %s died with signal %o", name, st); 66124941Seric ExitStat = EX_TEMPFAIL; 66224941Seric return (EX_TEMPFAIL); 6634863Seric } 6646038Seric 6656038Seric /* normal death -- return status */ 6669370Seric st = (st >> 8) & 0377; 6679370Seric return (st); 6684863Seric } 6694863Seric /* 6704863Seric ** OPENMAILER -- open connection to mailer. 6714863Seric ** 6724863Seric ** Parameters: 6734863Seric ** m -- mailer descriptor. 6744863Seric ** pvp -- parameter vector to pass to mailer. 6754863Seric ** ctladdr -- controlling address for user. 6764863Seric ** clever -- create a full duplex connection. 6774863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6784863Seric ** prfile -- pointer to rfile (from mailer) connection. 6794863Seric ** 6804863Seric ** Returns: 6816038Seric ** pid of mailer ( > 0 ). 6824863Seric ** -1 on error. 6836038Seric ** zero on an IPC connection. 6844863Seric ** 6854863Seric ** Side Effects: 6864863Seric ** creates a mailer in a subprocess. 6874863Seric */ 6884863Seric 6894863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6909370Seric MAILER *m; 6914863Seric char **pvp; 6924863Seric ADDRESS *ctladdr; 6934863Seric bool clever; 6944863Seric FILE **pmfile; 6954863Seric FILE **prfile; 6964863Seric { 6974863Seric int pid; 6984709Seric int mpvect[2]; 6994863Seric int rpvect[2]; 7003233Seric FILE *mfile; 7014863Seric FILE *rfile; 7023233Seric extern FILE *fdopen(); 7033233Seric 7043233Seric # ifdef DEBUG 7057672Seric if (tTd(11, 1)) 706294Seric { 7078178Seric printf("openmailer:"); 7083233Seric printav(pvp); 709294Seric } 7103233Seric # endif DEBUG 7114488Seric errno = 0; 7123233Seric 71325050Seric CurHostName = m->m_mailer; 71425050Seric 7156038Seric /* 7166038Seric ** Deal with the special case of mail handled through an IPC 7176038Seric ** connection. 7186038Seric ** In this case we don't actually fork. We must be 7196038Seric ** running SMTP for this to work. We will return a 7206038Seric ** zero pid to indicate that we are running IPC. 72111160Seric ** We also handle a debug version that just talks to stdin/out. 7226038Seric */ 7236038Seric 72411160Seric #ifdef DEBUG 72511160Seric /* check for Local Person Communication -- not for mortals!!! */ 72611160Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 72711160Seric { 72811160Seric *pmfile = stdout; 72911160Seric *prfile = stdin; 73011160Seric return (0); 73111160Seric } 73211160Seric #endif DEBUG 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); 75729433Sbloom if (st == NULL || st->s_host.ho_exitstat == EX_OK) 75829865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 75929433Sbloom else 76029433Sbloom { 76129433Sbloom i = st->s_host.ho_exitstat; 76229433Sbloom errno = st->s_host.ho_errno; 76329433Sbloom } 76424941Seric #else HOSTINFO 76529865Seric i = makeconnection(MxHosts[j], port, pmfile, prfile); 76624941Seric #endif HOSTINFO 76729433Sbloom if (i != EX_OK) 76829433Sbloom { 76924941Seric #ifdef HOSTINFO 77029433Sbloom /* enter status of this host */ 77129433Sbloom if (st == NULL) 77229865Seric st = stab(MxHosts[j], ST_HOST, ST_ENTER); 77329433Sbloom st->s_host.ho_exitstat = i; 77429433Sbloom st->s_host.ho_errno = errno; 77524941Seric #endif HOSTINFO 77629433Sbloom ExitStat = i; 77729433Sbloom continue; 77829433Sbloom } 77929433Sbloom else 78029433Sbloom return (0); 7816047Seric } 78229433Sbloom return (-1); 7839370Seric #else DAEMON 7849370Seric syserr("openmailer: no IPC"); 7859370Seric return (-1); 7869370Seric #endif DAEMON 7876038Seric } 7886038Seric 7892898Seric /* create a pipe to shove the mail through */ 7904709Seric if (pipe(mpvect) < 0) 791294Seric { 7929370Seric syserr("openmailer: pipe (to mailer)"); 793294Seric return (-1); 794294Seric } 7954863Seric 7969370Seric #ifdef SMTP 7974863Seric /* if this mailer speaks smtp, create a return pipe */ 7984863Seric if (clever && pipe(rpvect) < 0) 7994863Seric { 8009370Seric syserr("openmailer: pipe (from mailer)"); 8014863Seric (void) close(mpvect[0]); 8024863Seric (void) close(mpvect[1]); 8034863Seric return (-1); 8044863Seric } 8059370Seric #endif SMTP 8064863Seric 8076038Seric /* 8086038Seric ** Actually fork the mailer process. 8096038Seric ** DOFORK is clever about retrying. 81026434Seric ** 81126434Seric ** Dispose of SIGCHLD signal catchers that may be laying 81226434Seric ** around so that endmail will get it. 8136038Seric */ 8146038Seric 8159538Seric if (CurEnv->e_xfp != NULL) 8169538Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 8179370Seric (void) fflush(stdout); 81826434Seric # ifdef SIGCHLD 81926434Seric (void) signal(SIGCHLD, SIG_DFL); 82026434Seric # endif SIGCHLD 8214214Seric DOFORK(XFORK); 8224327Seric /* pid is set by DOFORK */ 823294Seric if (pid < 0) 824294Seric { 8256038Seric /* failure */ 8269370Seric syserr("openmailer: cannot fork"); 8274709Seric (void) close(mpvect[0]); 8284709Seric (void) close(mpvect[1]); 8299370Seric #ifdef SMTP 8304863Seric if (clever) 8314863Seric { 8324863Seric (void) close(rpvect[0]); 8334863Seric (void) close(rpvect[1]); 8344863Seric } 8359370Seric #endif SMTP 836294Seric return (-1); 837294Seric } 838294Seric else if (pid == 0) 839294Seric { 84015772Seric int i; 84124941Seric extern int DtableSize; 84215772Seric 843294Seric /* child -- set up input & exec mailer */ 8441621Seric /* make diagnostic output be standard output */ 8454477Seric (void) signal(SIGINT, SIG_IGN); 8464477Seric (void) signal(SIGHUP, SIG_IGN); 8474215Seric (void) signal(SIGTERM, SIG_DFL); 8484709Seric 8494709Seric /* arrange to filter standard & diag output of command */ 8504863Seric if (clever) 8514709Seric { 8524863Seric (void) close(rpvect[0]); 8534709Seric (void) close(1); 8544863Seric (void) dup(rpvect[1]); 8554863Seric (void) close(rpvect[1]); 8564863Seric } 8579275Seric else if (OpMode == MD_SMTP || HoldErrs) 8584863Seric { 8599370Seric /* put mailer output in transcript */ 8604863Seric (void) close(1); 8619538Seric (void) dup(fileno(CurEnv->e_xfp)); 8624709Seric } 8634082Seric (void) close(2); 8644082Seric (void) dup(1); 8654709Seric 8664709Seric /* arrange to get standard input */ 8674709Seric (void) close(mpvect[1]); 8684082Seric (void) close(0); 8694709Seric if (dup(mpvect[0]) < 0) 870294Seric { 8712898Seric syserr("Cannot dup to zero!"); 8722898Seric _exit(EX_OSERR); 873294Seric } 8744709Seric (void) close(mpvect[0]); 87510682Seric if (!bitnset(M_RESTR, m->m_flags)) 8764215Seric { 87716883Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 8784417Seric { 8794417Seric (void) setgid(DefGid); 8804417Seric (void) setuid(DefUid); 8814417Seric } 8824417Seric else 8834415Seric { 8844417Seric (void) setgid(ctladdr->q_gid); 8854417Seric (void) setuid(ctladdr->q_uid); 8864415Seric } 8874215Seric } 8889370Seric 88915772Seric /* arrange for all the files to be closed */ 89024941Seric for (i = 3; i < DtableSize; i++) 89115772Seric #ifdef FIOCLEX 89215772Seric (void) ioctl(i, FIOCLEX, 0); 89315772Seric #else FIOCLEX 89415772Seric (void) close(i); 89515772Seric #endif FIOCLEX 8962774Seric 8976038Seric /* try to execute the mailer */ 89825026Seric execve(m->m_mailer, pvp, UserEnviron); 8996038Seric 90015772Seric #ifdef FIOCLEX 90115772Seric syserr("Cannot exec %s", m->m_mailer); 90215772Seric #else FIOCLEX 9034214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 9044082Seric (void) fflush(stdout); 90515772Seric #endif FIOCLEX 90624941Seric if (m == LocalMailer || errno == EIO || errno == EAGAIN || 90724941Seric errno == ENOMEM || errno == EPROCLIM) 90816902Seric _exit(EX_TEMPFAIL); 90916902Seric else 91016902Seric _exit(EX_UNAVAILABLE); 911294Seric } 912294Seric 9134709Seric /* 9144863Seric ** Set up return value. 9154709Seric */ 9164709Seric 9174709Seric (void) close(mpvect[0]); 9184709Seric mfile = fdopen(mpvect[1], "w"); 9194863Seric if (clever) 9204863Seric { 9214863Seric (void) close(rpvect[1]); 9224863Seric rfile = fdopen(rpvect[0], "r"); 9234863Seric } 924294Seric 9254863Seric *pmfile = mfile; 9264863Seric *prfile = rfile; 927294Seric 9284863Seric return (pid); 929294Seric } 930294Seric /* 931294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 932294Seric ** 933294Seric ** Parameters: 934294Seric ** stat -- the status code from the mailer (high byte 935294Seric ** only; core dumps must have been taken care of 936294Seric ** already). 937294Seric ** m -- the mailer descriptor for this mailer. 938294Seric ** 939294Seric ** Returns: 9404082Seric ** none. 941294Seric ** 942294Seric ** Side Effects: 9431518Seric ** Errors may be incremented. 944294Seric ** ExitStat may be set. 945294Seric */ 946294Seric 94710105Seric giveresponse(stat, m, e) 948294Seric int stat; 9499370Seric register MAILER *m; 95010105Seric ENVELOPE *e; 951294Seric { 952294Seric register char *statmsg; 953294Seric extern char *SysExMsg[]; 954294Seric register int i; 955294Seric extern int N_SysEx; 95610105Seric char buf[MAXLINE]; 957294Seric 95812135Seric #ifdef lint 95912135Seric if (m == NULL) 96012135Seric return; 96112135Seric #endif lint 96212135Seric 9634315Seric /* 9644315Seric ** Compute status message from code. 9654315Seric */ 9664315Seric 967294Seric i = stat - EX__BASE; 9689370Seric if (stat == 0) 9699370Seric statmsg = "250 Sent"; 9709370Seric else if (i < 0 || i > N_SysEx) 9719370Seric { 9729370Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 9739370Seric stat = EX_UNAVAILABLE; 9749370Seric statmsg = buf; 9759370Seric } 97610105Seric else if (stat == EX_TEMPFAIL) 97710105Seric { 97810124Seric (void) strcpy(buf, SysExMsg[i]); 97925527Smiriam if (h_errno == TRY_AGAIN) 98010105Seric { 98115137Seric extern char *errstring(); 98215137Seric 98325527Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 98421061Seric } 98521061Seric else 98621061Seric { 98725527Smiriam if (errno != 0) 98825527Smiriam { 98925527Smiriam extern char *errstring(); 99025527Smiriam 99125527Smiriam statmsg = errstring(errno); 99225527Smiriam } 99325527Smiriam else 99425527Smiriam { 99521061Seric #ifdef SMTP 99625527Smiriam extern char SmtpError[]; 99721061Seric 99825527Smiriam statmsg = SmtpError; 99921061Seric #else SMTP 100025527Smiriam statmsg = NULL; 100121061Seric #endif SMTP 100225527Smiriam } 100321061Seric } 100421061Seric if (statmsg != NULL && statmsg[0] != '\0') 100521061Seric { 100610124Seric (void) strcat(buf, ": "); 100721061Seric (void) strcat(buf, statmsg); 100810105Seric } 100910105Seric statmsg = buf; 101010105Seric } 1011294Seric else 101221061Seric { 1013294Seric statmsg = SysExMsg[i]; 101421061Seric } 10159370Seric 10169370Seric /* 10179370Seric ** Print the message as appropriate 10189370Seric */ 10199370Seric 102010105Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 10218003Seric message(Arpa_Info, &statmsg[4]); 1022294Seric else 1023294Seric { 10241518Seric Errors++; 10259370Seric usrerr(statmsg); 1026294Seric } 1027294Seric 1028294Seric /* 1029294Seric ** Final cleanup. 1030294Seric ** Log a record of the transaction. Compute the new 1031294Seric ** ExitStat -- if we already had an error, stick with 1032294Seric ** that. 1033294Seric */ 1034294Seric 10357680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 10368496Seric logdelivery(&statmsg[4]); 10377858Seric 10384621Seric if (stat != EX_TEMPFAIL) 10394621Seric setstat(stat); 104010105Seric if (stat != EX_OK) 104110105Seric { 104210105Seric if (e->e_message != NULL) 104310105Seric free(e->e_message); 104410105Seric e->e_message = newstr(&statmsg[4]); 104510105Seric } 104610124Seric errno = 0; 104725527Smiriam h_errno = 0; 1048294Seric } 1049294Seric /* 10508496Seric ** LOGDELIVERY -- log the delivery in the system log 10518496Seric ** 10528496Seric ** Parameters: 10538496Seric ** stat -- the message to print for the status 10548496Seric ** 10558496Seric ** Returns: 10568496Seric ** none 10578496Seric ** 10588496Seric ** Side Effects: 10598496Seric ** none 10608496Seric */ 10618496Seric 10628496Seric logdelivery(stat) 10638496Seric char *stat; 10648496Seric { 10658496Seric extern char *pintvl(); 10668496Seric 10678496Seric # ifdef LOG 10688496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 10698496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 10708496Seric # endif LOG 10718496Seric } 10728496Seric /* 10736974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 1074294Seric ** 10756974Seric ** This can be made an arbitrary message separator by changing $l 1076294Seric ** 107716150Seric ** One of the ugliest hacks seen by human eyes is contained herein: 107816150Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 107916150Seric ** does a well-meaning programmer such as myself have to deal with 108016150Seric ** this kind of antique garbage???? 10816974Seric ** 1082294Seric ** Parameters: 10836974Seric ** fp -- the file to output to. 10846974Seric ** m -- the mailer describing this entry. 1085294Seric ** 1086294Seric ** Returns: 10876974Seric ** none 1088294Seric ** 1089294Seric ** Side Effects: 10906974Seric ** outputs some text to fp. 1091294Seric */ 1092294Seric 109310168Seric putfromline(fp, m) 10946974Seric register FILE *fp; 10956974Seric register MAILER *m; 1096294Seric { 109716150Seric char *template = "\001l\n"; 10986974Seric char buf[MAXLINE]; 1099294Seric 110010682Seric if (bitnset(M_NHDR, m->m_flags)) 11016974Seric return; 11024315Seric 11036974Seric # ifdef UGLYUUCP 110410682Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 11054205Seric { 110612223Seric char *bang; 110712223Seric char xbuf[MAXLINE]; 11086041Seric 110916150Seric expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 111012223Seric bang = index(buf, '!'); 11116974Seric if (bang == NULL) 111212223Seric syserr("No ! in UUCP! (%s)", buf); 11135099Seric else 11149370Seric { 111512223Seric *bang++ = '\0'; 111616150Seric (void) sprintf(xbuf, "From %s \001d remote from %s\n", bang, buf); 111712223Seric template = xbuf; 11189370Seric } 11196974Seric } 11205179Seric # endif UGLYUUCP 112112223Seric expand(template, buf, &buf[sizeof buf - 1], CurEnv); 112210168Seric putline(buf, fp, m); 11235981Seric } 11245981Seric /* 11256974Seric ** PUTBODY -- put the body of a message. 11266974Seric ** 11276974Seric ** Parameters: 11286974Seric ** fp -- file to output onto. 112910168Seric ** m -- a mailer descriptor to control output format. 11309538Seric ** e -- the envelope to put out. 11316974Seric ** 11326974Seric ** Returns: 11336974Seric ** none. 11346974Seric ** 11356974Seric ** Side Effects: 11366974Seric ** The message is written onto fp. 11376974Seric */ 11386974Seric 113910168Seric putbody(fp, m, e) 11406974Seric FILE *fp; 11419370Seric MAILER *m; 11429538Seric register ENVELOPE *e; 11436974Seric { 114410168Seric char buf[MAXLINE]; 11456974Seric 11466974Seric /* 11476974Seric ** Output the body of the message 11486974Seric */ 11496974Seric 11509538Seric if (e->e_dfp == NULL) 11516974Seric { 11529538Seric if (e->e_df != NULL) 11539538Seric { 11549538Seric e->e_dfp = fopen(e->e_df, "r"); 11559538Seric if (e->e_dfp == NULL) 11569538Seric syserr("Cannot open %s", e->e_df); 11579538Seric } 11589538Seric else 115910168Seric putline("<<< No Message Collected >>>", fp, m); 11609538Seric } 11619538Seric if (e->e_dfp != NULL) 11629538Seric { 11639538Seric rewind(e->e_dfp); 116410168Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 116516875Seric { 116616875Seric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 116716875Seric strncmp(buf, "From", 4) == 0) 116823102Seric (void) putc('>', fp); 116910168Seric putline(buf, fp, m); 117016875Seric } 11716974Seric 11729538Seric if (ferror(e->e_dfp)) 11736974Seric { 11746974Seric syserr("putbody: read error"); 11756974Seric ExitStat = EX_IOERR; 11766974Seric } 11776974Seric } 11786974Seric 11796974Seric (void) fflush(fp); 11806974Seric if (ferror(fp) && errno != EPIPE) 11816974Seric { 11826974Seric syserr("putbody: write error"); 11836974Seric ExitStat = EX_IOERR; 11846974Seric } 11856974Seric errno = 0; 11866974Seric } 11876974Seric /* 1188294Seric ** MAILFILE -- Send a message to a file. 1189294Seric ** 11904327Seric ** If the file has the setuid/setgid bits set, but NO execute 11914327Seric ** bits, sendmail will try to become the owner of that file 11924327Seric ** rather than the real user. Obviously, this only works if 11934327Seric ** sendmail runs as root. 11944327Seric ** 11959370Seric ** This could be done as a subordinate mailer, except that it 11969370Seric ** is used implicitly to save messages in ~/dead.letter. We 11979370Seric ** view this as being sufficiently important as to include it 11989370Seric ** here. For example, if the system is dying, we shouldn't have 11999370Seric ** to create another process plus some pipes to save the message. 12009370Seric ** 1201294Seric ** Parameters: 1202294Seric ** filename -- the name of the file to send to. 12034397Seric ** ctladdr -- the controlling address header -- includes 12044397Seric ** the userid/groupid to be when sending. 1205294Seric ** 1206294Seric ** Returns: 1207294Seric ** The exit code associated with the operation. 1208294Seric ** 1209294Seric ** Side Effects: 1210294Seric ** none. 1211294Seric */ 1212294Seric 12134397Seric mailfile(filename, ctladdr) 1214294Seric char *filename; 12154397Seric ADDRESS *ctladdr; 1216294Seric { 1217294Seric register FILE *f; 12184214Seric register int pid; 1219294Seric 12204214Seric /* 12214214Seric ** Fork so we can change permissions here. 12224214Seric ** Note that we MUST use fork, not vfork, because of 12234214Seric ** the complications of calling subroutines, etc. 12244214Seric */ 12254067Seric 12264214Seric DOFORK(fork); 12274214Seric 12284214Seric if (pid < 0) 12294214Seric return (EX_OSERR); 12304214Seric else if (pid == 0) 12314214Seric { 12324214Seric /* child -- actually write to file */ 12334327Seric struct stat stb; 12344327Seric 12354215Seric (void) signal(SIGINT, SIG_DFL); 12364215Seric (void) signal(SIGHUP, SIG_DFL); 12374215Seric (void) signal(SIGTERM, SIG_DFL); 123823102Seric (void) umask(OldUmask); 12394327Seric if (stat(filename, &stb) < 0) 124011935Seric { 124111935Seric errno = 0; 12424431Seric stb.st_mode = 0666; 124311935Seric } 12444327Seric if (bitset(0111, stb.st_mode)) 12454327Seric exit(EX_CANTCREAT); 12464401Seric if (ctladdr == NULL) 12476900Seric ctladdr = &CurEnv->e_from; 12484327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 12494417Seric { 12504417Seric if (ctladdr->q_uid == 0) 12514417Seric (void) setgid(DefGid); 12524417Seric else 12534417Seric (void) setgid(ctladdr->q_gid); 12544417Seric } 12554327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 12564417Seric { 12574417Seric if (ctladdr->q_uid == 0) 12584417Seric (void) setuid(DefUid); 12594417Seric else 12604417Seric (void) setuid(ctladdr->q_uid); 12614417Seric } 12626887Seric f = dfopen(filename, "a"); 12634214Seric if (f == NULL) 12644214Seric exit(EX_CANTCREAT); 12654214Seric 126610168Seric putfromline(f, ProgMailer); 126710168Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 126810168Seric putline("\n", f, ProgMailer); 126910168Seric (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); 127010168Seric putline("\n", f, ProgMailer); 12714214Seric (void) fclose(f); 12724214Seric (void) fflush(stdout); 12734417Seric 12746887Seric /* reset ISUID & ISGID bits for paranoid systems */ 12754621Seric (void) chmod(filename, (int) stb.st_mode); 12764214Seric exit(EX_OK); 12774315Seric /*NOTREACHED*/ 12784214Seric } 12794214Seric else 12804214Seric { 12814214Seric /* parent -- wait for exit status */ 12829370Seric int st; 12834214Seric 12849370Seric st = waitfor(pid); 12859370Seric if ((st & 0377) != 0) 12869370Seric return (EX_UNAVAILABLE); 12879370Seric else 12889370Seric return ((st >> 8) & 0377); 12894214Seric } 1290294Seric } 12914550Seric /* 12924550Seric ** SENDALL -- actually send all the messages. 12934550Seric ** 12944550Seric ** Parameters: 12957043Seric ** e -- the envelope to send. 129614874Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 129714874Seric ** the current SendMode. 12984550Seric ** 12994550Seric ** Returns: 13004550Seric ** none. 13014550Seric ** 13024550Seric ** Side Effects: 13034550Seric ** Scans the send lists and sends everything it finds. 13047043Seric ** Delivers any appropriate error messages. 13059275Seric ** If we are running in a non-interactive mode, takes the 13069275Seric ** appropriate action. 13074550Seric */ 13084550Seric 13099275Seric sendall(e, mode) 13107043Seric ENVELOPE *e; 13119275Seric char mode; 13124550Seric { 13135008Seric register ADDRESS *q; 13147779Seric bool oldverbose; 13159275Seric int pid; 13164550Seric 131714874Seric /* determine actual delivery mode */ 131814874Seric if (mode == SM_DEFAULT) 131914874Seric { 132024941Seric extern bool shouldqueue(); 132114874Seric 132224941Seric if (shouldqueue(e->e_msgpriority)) 132314874Seric mode = SM_QUEUE; 132414874Seric else 132514874Seric mode = SendMode; 132614874Seric } 132714874Seric 13289370Seric #ifdef DEBUG 13298248Seric if (tTd(13, 1)) 13305032Seric { 13319275Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 13327043Seric printaddr(e->e_sendqueue, TRUE); 13335032Seric } 13349370Seric #endif DEBUG 13355008Seric 13367043Seric /* 13379275Seric ** Do any preprocessing necessary for the mode we are running. 13389370Seric ** Check to make sure the hop count is reasonable. 13399370Seric ** Delete sends to the sender in mailing lists. 13407043Seric */ 13417043Seric 13429370Seric CurEnv = e; 13439370Seric 13449370Seric if (e->e_hopcount > MAXHOP) 13459275Seric { 13469370Seric syserr("sendall: too many hops (%d max)", MAXHOP); 13479370Seric return; 13489370Seric } 13499275Seric 13509370Seric if (!MeToo) 13519370Seric { 135212611Seric extern ADDRESS *recipient(); 135312611Seric 13549370Seric e->e_from.q_flags |= QDONTSEND; 135512611Seric (void) recipient(&e->e_from, &e->e_sendqueue); 13569275Seric } 13579370Seric 13589370Seric # ifdef QUEUE 13599335Seric if ((mode == SM_QUEUE || mode == SM_FORK || 13609335Seric (mode != SM_VERIFY && SuperSafe)) && 13619335Seric !bitset(EF_INQUEUE, e->e_flags)) 13629370Seric queueup(e, TRUE, mode == SM_QUEUE); 13639275Seric #endif QUEUE 13649275Seric 13657779Seric oldverbose = Verbose; 13669275Seric switch (mode) 13679275Seric { 13689275Seric case SM_VERIFY: 13697779Seric Verbose = TRUE; 13709275Seric break; 13719275Seric 13729275Seric case SM_QUEUE: 13739335Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 13749275Seric return; 13759275Seric 13769275Seric case SM_FORK: 13779538Seric if (e->e_xfp != NULL) 13789538Seric (void) fflush(e->e_xfp); 13799275Seric pid = fork(); 13809275Seric if (pid < 0) 13819275Seric { 13829275Seric mode = SM_DELIVER; 13839275Seric break; 13849275Seric } 13859275Seric else if (pid > 0) 13869293Seric { 13879293Seric /* be sure we leave the temp files to our child */ 13889335Seric e->e_id = e->e_df = NULL; 13899275Seric return; 13909293Seric } 13919275Seric 13929275Seric /* double fork to avoid zombies */ 13939275Seric if (fork() > 0) 13949275Seric exit(EX_OK); 13959275Seric 13969293Seric /* be sure we are immune from the terminal */ 139710133Seric disconnect(FALSE); 13989293Seric 13999275Seric break; 14009275Seric } 14019275Seric 14029275Seric /* 14039275Seric ** Run through the list and send everything. 14049275Seric */ 14059275Seric 14067043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14074550Seric { 14089275Seric if (mode == SM_VERIFY) 14094550Seric { 14109293Seric e->e_to = q->q_paddr; 14115008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14127052Seric message(Arpa_Info, "deliverable"); 14134550Seric } 14145008Seric else 14159370Seric (void) deliver(e, q); 14164550Seric } 14177779Seric Verbose = oldverbose; 14187043Seric 14197043Seric /* 14207043Seric ** Now run through and check for errors. 14217043Seric */ 14227043Seric 14239275Seric if (mode == SM_VERIFY) 14247043Seric return; 14257043Seric 14267043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14277043Seric { 14287043Seric register ADDRESS *qq; 14297043Seric 14308248Seric # ifdef DEBUG 14318248Seric if (tTd(13, 3)) 14328248Seric { 14338248Seric printf("Checking "); 14348248Seric printaddr(q, FALSE); 14358248Seric } 14368248Seric # endif DEBUG 14378248Seric 14389335Seric /* only send errors if the message failed */ 14399335Seric if (!bitset(QBADADDR, q->q_flags)) 14409335Seric continue; 14417043Seric 14427043Seric /* we have an address that failed -- find the parent */ 14437043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14447043Seric { 14457043Seric char obuf[MAXNAME + 6]; 14467043Seric extern char *aliaslookup(); 14477043Seric 14487043Seric /* we can only have owners for local addresses */ 144910682Seric if (!bitnset(M_LOCAL, qq->q_mailer->m_flags)) 14507043Seric continue; 14517043Seric 14527043Seric /* see if the owner list exists */ 14537043Seric (void) strcpy(obuf, "owner-"); 14547047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14557047Seric (void) strcat(obuf, "owner"); 14567047Seric else 14577047Seric (void) strcat(obuf, qq->q_user); 14587043Seric if (aliaslookup(obuf) == NULL) 14597043Seric continue; 14607043Seric 14618248Seric # ifdef DEBUG 14628248Seric if (tTd(13, 4)) 14638248Seric printf("Errors to %s\n", obuf); 14648248Seric # endif DEBUG 14658248Seric 14667043Seric /* owner list exists -- add it to the error queue */ 14679615Seric sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 146816883Seric ErrorMode = EM_MAIL; 14697043Seric break; 14707043Seric } 14717043Seric 14727043Seric /* if we did not find an owner, send to the sender */ 14738426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 14749615Seric sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue); 14757043Seric } 14769275Seric 14779275Seric if (mode == SM_FORK) 14789275Seric finis(); 14794550Seric } 1480