125a99e2eSeric # include <signal.h> 254aa2b0fSeric # include <errno.h> 3b20b3270Seric # include "sendmail.h" 4c77d1c25Seric # include <sys/stat.h> 525a99e2eSeric # ifdef LOG 6e374fd72Seric # include <syslog.h> 725a99e2eSeric # endif LOG 825a99e2eSeric 9*772e6e50Seric static char SccsId[] = "@(#)deliver.c 3.56 11/22/81"; 10259cace7Seric 1125a99e2eSeric /* 1213bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 1313bbc08cSeric ** 1413bbc08cSeric ** This routine delivers to everyone on the same host as the 1513bbc08cSeric ** user on the head of the list. It is clever about mailers 1613bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 1713bbc08cSeric ** that it will deliver to all these addresses however -- so 1813bbc08cSeric ** deliver should be called once for each address on the 1913bbc08cSeric ** list. 2025a99e2eSeric ** 2125a99e2eSeric ** Parameters: 22c77d1c25Seric ** firstto -- head of the address list to deliver to. 2325a99e2eSeric ** editfcn -- if non-NULL, we want to call this function 2425a99e2eSeric ** to output the letter (instead of just out- 2525a99e2eSeric ** putting it raw). 2625a99e2eSeric ** 2725a99e2eSeric ** Returns: 2825a99e2eSeric ** zero -- successfully delivered. 2925a99e2eSeric ** else -- some failure, see ExitStat for more info. 3025a99e2eSeric ** 3125a99e2eSeric ** Side Effects: 3225a99e2eSeric ** The standard input is passed off to someone. 3325a99e2eSeric */ 3425a99e2eSeric 35c77d1c25Seric deliver(firstto, editfcn) 36c77d1c25Seric ADDRESS *firstto; 3725a99e2eSeric int (*editfcn)(); 3825a99e2eSeric { 3978442df3Seric char *host; /* host being sent to */ 4078442df3Seric char *user; /* user being sent to */ 4125a99e2eSeric char **pvp; 425dfc646bSeric register char **mvp; 4325a99e2eSeric register char *p; 4478442df3Seric register struct mailer *m; /* mailer for this recipient */ 455dfc646bSeric register int i; 466328bdf7Seric extern putmessage(); 472a6e0786Seric extern bool checkcompat(); 485dfc646bSeric char *pv[MAXPV+1]; 4978442df3Seric char tobuf[MAXLINE]; /* text line of to people */ 505dfc646bSeric char buf[MAXNAME]; 516259796dSeric ADDRESS *ctladdr; 526259796dSeric extern ADDRESS *getctladdr(); 5378442df3Seric char tfrombuf[MAXNAME]; /* translated from person */ 5478442df3Seric extern char **prescan(); 55c77d1c25Seric register ADDRESS *to = firstto; 56c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 57c579ef51Seric bool tempfail = FALSE; 58*772e6e50Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 5925a99e2eSeric 6035490626Seric errno = 0; 61e77e673fSeric if (!ForceMail && bitset(QDONTSEND, to->q_flags)) 625dfc646bSeric return (0); 6325a99e2eSeric 6425a99e2eSeric # ifdef DEBUG 6525a99e2eSeric if (Debug) 665dfc646bSeric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 677da1035fSeric to->q_mailer->m_mno, to->q_host, to->q_user); 6825a99e2eSeric # endif DEBUG 6925a99e2eSeric 7025a99e2eSeric /* 715dfc646bSeric ** Do initial argv setup. 725dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 735dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 745dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 755dfc646bSeric ** code does not check for 'pv' overflow; this places a 765dfc646bSeric ** manifest lower limit of 4 for MAXPV. 775dfc646bSeric */ 785dfc646bSeric 797da1035fSeric m = to->q_mailer; 805dfc646bSeric host = to->q_host; 8178442df3Seric 8278442df3Seric /* rewrite from address, using rewriting rules */ 8378442df3Seric (void) expand(m->m_from, buf, &buf[sizeof buf - 1]); 8478442df3Seric mvp = prescan(buf, '\0'); 8578442df3Seric if (mvp == NULL) 8678442df3Seric { 8778442df3Seric syserr("bad mailer from translate \"%s\"", buf); 8878442df3Seric return (EX_SOFTWARE); 8978442df3Seric } 9078442df3Seric rewrite(mvp, 2); 9178442df3Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 9278442df3Seric 9378442df3Seric define('g', tfrombuf); /* translated sender address */ 945dfc646bSeric define('h', host); /* to host */ 955dfc646bSeric Errors = 0; 965dfc646bSeric pvp = pv; 975dfc646bSeric *pvp++ = m->m_argv[0]; 985dfc646bSeric 995dfc646bSeric /* insert -f or -r flag as appropriate */ 1005dfc646bSeric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1015dfc646bSeric { 1025dfc646bSeric if (bitset(M_FOPT, m->m_flags)) 1035dfc646bSeric *pvp++ = "-f"; 1045dfc646bSeric else 1055dfc646bSeric *pvp++ = "-r"; 106db8841e9Seric (void) expand("$g", buf, &buf[sizeof buf - 1]); 1075dfc646bSeric *pvp++ = newstr(buf); 1085dfc646bSeric } 1095dfc646bSeric 1105dfc646bSeric /* 1115dfc646bSeric ** Append the other fixed parts of the argv. These run 1125dfc646bSeric ** up to the first entry containing "$u". There can only 1135dfc646bSeric ** be one of these, and there are only a few more slots 1145dfc646bSeric ** in the pv after it. 1155dfc646bSeric */ 1165dfc646bSeric 1175dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1185dfc646bSeric { 1195dfc646bSeric while ((p = index(p, '$')) != NULL) 1205dfc646bSeric if (*++p == 'u') 1215dfc646bSeric break; 1225dfc646bSeric if (p != NULL) 1235dfc646bSeric break; 1245dfc646bSeric 1255dfc646bSeric /* this entry is safe -- go ahead and process it */ 126db8841e9Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 1275dfc646bSeric *pvp++ = newstr(buf); 1285dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 1295dfc646bSeric { 1305dfc646bSeric syserr("Too many parameters to %s before $u", pv[0]); 1315dfc646bSeric return (-1); 1325dfc646bSeric } 1335dfc646bSeric } 134c579ef51Seric 1355dfc646bSeric if (*mvp == NULL) 136c579ef51Seric { 137c579ef51Seric /* running SMTP */ 138c579ef51Seric clever = TRUE; 139c579ef51Seric *pvp = NULL; 140c579ef51Seric i = smtpinit(m, pv, (ADDRESS *) NULL); 141c579ef51Seric giveresponse(i, TRUE, m); 142c579ef51Seric if (i == EX_TEMPFAIL) 143c579ef51Seric { 144c579ef51Seric QueueUp = TRUE; 145c579ef51Seric tempfail = TRUE; 146c579ef51Seric } 147c579ef51Seric } 1485dfc646bSeric 1495dfc646bSeric /* 1505dfc646bSeric ** At this point *mvp points to the argument with $u. We 1515dfc646bSeric ** run through our address list and append all the addresses 1525dfc646bSeric ** we can. If we run out of space, do not fret! We can 1535dfc646bSeric ** always send another copy later. 1545dfc646bSeric */ 1555dfc646bSeric 1565dfc646bSeric tobuf[0] = '\0'; 1575dfc646bSeric To = tobuf; 1586259796dSeric ctladdr = NULL; 1595dfc646bSeric for (; to != NULL; to = to->q_next) 1605dfc646bSeric { 1615dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 162bea22b26Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1635dfc646bSeric break; 1645dfc646bSeric 1655dfc646bSeric /* if already sent or not for this host, don't send */ 166e77e673fSeric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 167e77e673fSeric strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) 1685dfc646bSeric continue; 1696259796dSeric 170*772e6e50Seric # ifdef DEBUG 171*772e6e50Seric if (Debug) 172*772e6e50Seric { 173*772e6e50Seric printf("\nsend to "); 174*772e6e50Seric printaddr(to, FALSE); 175*772e6e50Seric } 176*772e6e50Seric # endif DEBUG 177*772e6e50Seric 178*772e6e50Seric /* link together the chain of recipients */ 179*772e6e50Seric if (!bitset(QDONTSEND, to->q_flags)) 180*772e6e50Seric { 181*772e6e50Seric to->q_tchain = tochain; 182*772e6e50Seric tochain = to; 183*772e6e50Seric } 184*772e6e50Seric 1856259796dSeric /* compute effective uid/gid when sending */ 1867da1035fSeric if (to->q_mailer == ProgMailer) 1876259796dSeric ctladdr = getctladdr(to); 1886259796dSeric 1895dfc646bSeric user = to->q_user; 1905dfc646bSeric To = to->q_paddr; 1915dfc646bSeric to->q_flags |= QDONTSEND; 192c579ef51Seric if (tempfail) 193*772e6e50Seric { 194c579ef51Seric to->q_flags |= QQUEUEUP; 195*772e6e50Seric continue; 196*772e6e50Seric } 1975dfc646bSeric 1985dfc646bSeric /* 1995dfc646bSeric ** Check to see that these people are allowed to 2005dfc646bSeric ** talk to each other. 2012a6e0786Seric */ 2022a6e0786Seric 2032a6e0786Seric if (!checkcompat(to)) 2045dfc646bSeric { 2055dfc646bSeric giveresponse(EX_UNAVAILABLE, TRUE, m); 2065dfc646bSeric continue; 2075dfc646bSeric } 2082a6e0786Seric 2092a6e0786Seric /* 2109ec9501bSeric ** Strip quote bits from names if the mailer is dumb 2119ec9501bSeric ** about them. 21225a99e2eSeric */ 21325a99e2eSeric 2142a6e0786Seric if (bitset(M_STRIPQ, m->m_flags)) 21525a99e2eSeric { 2169ec9501bSeric stripquotes(user, TRUE); 2179ec9501bSeric stripquotes(host, TRUE); 2189ec9501bSeric } 2199ec9501bSeric else 2209ec9501bSeric { 2219ec9501bSeric stripquotes(user, FALSE); 2229ec9501bSeric stripquotes(host, FALSE); 22325a99e2eSeric } 22425a99e2eSeric 22525a99e2eSeric /* 2263efaed6eSeric ** If an error message has already been given, don't 2273efaed6eSeric ** bother to send to this address. 2283efaed6eSeric ** 2293efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 2303efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 2313efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 2323efaed6eSeric */ 2333efaed6eSeric 2343efaed6eSeric if (bitset(QBADADDR, to->q_flags)) 2353efaed6eSeric continue; 2363efaed6eSeric 237f2fec898Seric /* save statistics.... */ 2387da1035fSeric Stat.stat_nt[to->q_mailer->m_mno]++; 2397da1035fSeric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(MsgSize); 240f2fec898Seric 2413efaed6eSeric /* 24225a99e2eSeric ** See if this user name is "special". 24325a99e2eSeric ** If the user name has a slash in it, assume that this 24425a99e2eSeric ** is a file -- send it off without further ado. 24525a99e2eSeric ** Note that this means that editfcn's will not 2465dfc646bSeric ** be applied to the message. Also note that 2475dfc646bSeric ** this type of addresses is not processed along 2485dfc646bSeric ** with the others, so we fudge on the To person. 24925a99e2eSeric */ 25025a99e2eSeric 2517da1035fSeric if (m == LocalMailer) 25225a99e2eSeric { 25325a99e2eSeric if (index(user, '/') != NULL) 25425a99e2eSeric { 2556259796dSeric i = mailfile(user, getctladdr(to)); 25625a99e2eSeric giveresponse(i, TRUE, m); 2575dfc646bSeric continue; 25825a99e2eSeric } 25925a99e2eSeric } 26025a99e2eSeric 26113bbc08cSeric /* 26213bbc08cSeric ** Address is verified -- add this user to mailer 26313bbc08cSeric ** argv, and add it to the print list of recipients. 26413bbc08cSeric */ 26513bbc08cSeric 2665dfc646bSeric /* create list of users for error messages */ 2675dfc646bSeric if (tobuf[0] != '\0') 268db8841e9Seric (void) strcat(tobuf, ","); 269db8841e9Seric (void) strcat(tobuf, to->q_paddr); 2705dfc646bSeric define('u', user); /* to user */ 271c2567733Seric define('z', to->q_home); /* user's home */ 2725dfc646bSeric 273c579ef51Seric /* 274c579ef51Seric ** Expand out this user into argument list or 275c579ef51Seric ** send it to our SMTP server. 276c579ef51Seric */ 277c579ef51Seric 278c579ef51Seric if (clever) 279c579ef51Seric { 280d2b7d202Seric i = smtprcpt(to); 281c579ef51Seric if (i == EX_TEMPFAIL) 282c579ef51Seric { 283c579ef51Seric QueueUp = TRUE; 284c579ef51Seric to->q_flags |= QQUEUEUP; 285c579ef51Seric } 286c579ef51Seric else if (i != EX_OK) 287c579ef51Seric { 288c579ef51Seric to->q_flags |= QBADADDR; 289c579ef51Seric giveresponse(i, TRUE, m); 290c579ef51Seric } 291c579ef51Seric } 292c579ef51Seric else 293c579ef51Seric { 294d4ccc802Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 2955dfc646bSeric *pvp++ = newstr(buf); 2965dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 2975dfc646bSeric { 2985dfc646bSeric /* allow some space for trailing parms */ 2995dfc646bSeric break; 3005dfc646bSeric } 3015dfc646bSeric } 302c579ef51Seric } 3035dfc646bSeric 304145b49b1Seric /* see if any addresses still exist */ 305145b49b1Seric if (tobuf[0] == '\0') 306c579ef51Seric { 307c579ef51Seric if (clever) 308c579ef51Seric smtpquit(pv[0]); 309145b49b1Seric return (0); 310c579ef51Seric } 311145b49b1Seric 3125dfc646bSeric /* print out messages as full list */ 3135dfc646bSeric To = tobuf; 3145dfc646bSeric 3155dfc646bSeric /* 3165dfc646bSeric ** Fill out any parameters after the $u parameter. 3175dfc646bSeric */ 3185dfc646bSeric 319c579ef51Seric while (!clever && *++mvp != NULL) 3205dfc646bSeric { 321db8841e9Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3225dfc646bSeric *pvp++ = newstr(buf); 3235dfc646bSeric if (pvp >= &pv[MAXPV]) 3245dfc646bSeric syserr("deliver: pv overflow after $u for %s", pv[0]); 3255dfc646bSeric } 3265dfc646bSeric *pvp++ = NULL; 3275dfc646bSeric 32825a99e2eSeric /* 32925a99e2eSeric ** Call the mailer. 3306328bdf7Seric ** The argument vector gets built, pipes 33125a99e2eSeric ** are created as necessary, and we fork & exec as 3326328bdf7Seric ** appropriate. 333c579ef51Seric ** If we are running SMTP, we just need to clean up. 33425a99e2eSeric */ 33525a99e2eSeric 3365dfc646bSeric if (editfcn == NULL) 3375dfc646bSeric editfcn = putmessage; 3386259796dSeric if (ctladdr == NULL) 3396259796dSeric ctladdr = &From; 340c579ef51Seric if (clever) 341c579ef51Seric { 342c579ef51Seric i = smtpfinish(m, editfcn); 343c579ef51Seric smtpquit(pv[0]); 344c579ef51Seric } 345c579ef51Seric else 3466259796dSeric i = sendoff(m, pv, editfcn, ctladdr); 3475dfc646bSeric 348c77d1c25Seric /* 349c77d1c25Seric ** If we got a temporary failure, arrange to queue the 350c77d1c25Seric ** addressees. 351c77d1c25Seric */ 352c77d1c25Seric 353c77d1c25Seric if (i == EX_TEMPFAIL) 354c77d1c25Seric { 355c77d1c25Seric QueueUp = TRUE; 356*772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 357c77d1c25Seric to->q_flags |= QQUEUEUP; 358c77d1c25Seric } 359c77d1c25Seric 36035490626Seric errno = 0; 3615dfc646bSeric return (i); 36225a99e2eSeric } 3635dfc646bSeric /* 36432d19d43Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 36532d19d43Seric ** 36632d19d43Seric ** This MUST be a macro, since after a vfork we are running 36732d19d43Seric ** two processes on the same stack!!! 36832d19d43Seric ** 36932d19d43Seric ** Parameters: 37032d19d43Seric ** none. 37132d19d43Seric ** 37232d19d43Seric ** Returns: 37332d19d43Seric ** From a macro??? You've got to be kidding! 37432d19d43Seric ** 37532d19d43Seric ** Side Effects: 37632d19d43Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 37732d19d43Seric ** pid of child in parent, zero in child. 37832d19d43Seric ** -1 on unrecoverable error. 37932d19d43Seric ** 38032d19d43Seric ** Notes: 38132d19d43Seric ** I'm awfully sorry this looks so awful. That's 38232d19d43Seric ** vfork for you..... 38332d19d43Seric */ 38432d19d43Seric 38532d19d43Seric # define NFORKTRIES 5 38632d19d43Seric # ifdef VFORK 38732d19d43Seric # define XFORK vfork 38832d19d43Seric # else VFORK 38932d19d43Seric # define XFORK fork 39032d19d43Seric # endif VFORK 39132d19d43Seric 39232d19d43Seric # define DOFORK(fORKfN) \ 39332d19d43Seric {\ 39432d19d43Seric register int i;\ 39532d19d43Seric \ 39632d19d43Seric for (i = NFORKTRIES; i-- > 0; )\ 39732d19d43Seric {\ 39832d19d43Seric pid = fORKfN();\ 39932d19d43Seric if (pid >= 0)\ 40032d19d43Seric break;\ 40132d19d43Seric sleep((unsigned) NFORKTRIES - i);\ 40232d19d43Seric }\ 40332d19d43Seric } 40432d19d43Seric /* 4052ed72599Seric ** DOFORK -- simple fork interface to DOFORK. 4062ed72599Seric ** 4072ed72599Seric ** Parameters: 4082ed72599Seric ** none. 4092ed72599Seric ** 4102ed72599Seric ** Returns: 4112ed72599Seric ** pid of child in parent. 4122ed72599Seric ** zero in child. 4132ed72599Seric ** -1 on error. 4142ed72599Seric ** 4152ed72599Seric ** Side Effects: 4162ed72599Seric ** returns twice, once in parent and once in child. 4172ed72599Seric */ 4182ed72599Seric 4192ed72599Seric dofork() 4202ed72599Seric { 4212ed72599Seric register int pid; 4222ed72599Seric 4232ed72599Seric DOFORK(fork); 4242ed72599Seric return (pid); 4252ed72599Seric } 4262ed72599Seric /* 4275dfc646bSeric ** SENDOFF -- send off call to mailer & collect response. 4285dfc646bSeric ** 4295dfc646bSeric ** Parameters: 4305dfc646bSeric ** m -- mailer descriptor. 4315dfc646bSeric ** pvp -- parameter vector to send to it. 4325dfc646bSeric ** editfcn -- function to pipe it through. 4336259796dSeric ** ctladdr -- an address pointer controlling the 4346259796dSeric ** user/groupid etc. of the mailer. 4355dfc646bSeric ** 4365dfc646bSeric ** Returns: 4375dfc646bSeric ** exit status of mailer. 4385dfc646bSeric ** 4395dfc646bSeric ** Side Effects: 4405dfc646bSeric ** none. 4415dfc646bSeric */ 4425dfc646bSeric 4436259796dSeric sendoff(m, pvp, editfcn, ctladdr) 4445dfc646bSeric struct mailer *m; 4455dfc646bSeric char **pvp; 4465dfc646bSeric int (*editfcn)(); 4476259796dSeric ADDRESS *ctladdr; 4485dfc646bSeric { 449c579ef51Seric auto FILE *mfile; 450c579ef51Seric auto FILE *rfile; 4515dfc646bSeric register int i; 452c579ef51Seric extern putmessage(); 453c579ef51Seric int pid; 454c579ef51Seric 455c579ef51Seric /* 456c579ef51Seric ** Create connection to mailer. 457c579ef51Seric */ 458c579ef51Seric 459c579ef51Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 460c579ef51Seric if (pid < 0) 461c579ef51Seric return (-1); 462c579ef51Seric 463c579ef51Seric /* 464c579ef51Seric ** Format and send message. 465c579ef51Seric */ 466c579ef51Seric 467c579ef51Seric (void) signal(SIGPIPE, SIG_IGN); 468c579ef51Seric if (editfcn == NULL) 469c579ef51Seric editfcn = putmessage; 470c579ef51Seric 471c579ef51Seric (*editfcn)(mfile, m, FALSE); 472c579ef51Seric (void) fclose(mfile); 473c579ef51Seric 474c579ef51Seric i = endmailer(pid, pvp[0]); 475c579ef51Seric giveresponse(i, TRUE, m); 476c579ef51Seric return (i); 477c579ef51Seric } 478c579ef51Seric /* 479c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 480c579ef51Seric ** 481c579ef51Seric ** We should never get fatal errors (e.g., segmentation 482c579ef51Seric ** violation), so we report those specially. For other 483c579ef51Seric ** errors, we choose a status message (into statmsg), 484c579ef51Seric ** and if it represents an error, we print it. 485c579ef51Seric ** 486c579ef51Seric ** Parameters: 487c579ef51Seric ** pid -- pid of mailer. 488c579ef51Seric ** name -- name of mailer (for error messages). 489c579ef51Seric ** 490c579ef51Seric ** Returns: 491c579ef51Seric ** exit code of mailer. 492c579ef51Seric ** 493c579ef51Seric ** Side Effects: 494c579ef51Seric ** none. 495c579ef51Seric */ 496c579ef51Seric 497c579ef51Seric endmailer(pid, name) 498c579ef51Seric int pid; 499c579ef51Seric char *name; 500c579ef51Seric { 501c579ef51Seric register int i; 502c579ef51Seric auto int st; 503c579ef51Seric 504c579ef51Seric while ((i = wait(&st)) > 0 && i != pid) 505c579ef51Seric continue; 506c579ef51Seric if (i < 0) 507c579ef51Seric { 508c579ef51Seric syserr("wait"); 509c579ef51Seric return (-1); 510c579ef51Seric } 511c579ef51Seric if ((st & 0377) != 0) 512c579ef51Seric { 513c579ef51Seric syserr("%s: stat %o", name, st); 514c579ef51Seric ExitStat = EX_UNAVAILABLE; 515c579ef51Seric return (-1); 516c579ef51Seric } 517c579ef51Seric i = (st >> 8) & 0377; 518c579ef51Seric return (i); 519c579ef51Seric } 520c579ef51Seric /* 521c579ef51Seric ** OPENMAILER -- open connection to mailer. 522c579ef51Seric ** 523c579ef51Seric ** Parameters: 524c579ef51Seric ** m -- mailer descriptor. 525c579ef51Seric ** pvp -- parameter vector to pass to mailer. 526c579ef51Seric ** ctladdr -- controlling address for user. 527c579ef51Seric ** clever -- create a full duplex connection. 528c579ef51Seric ** pmfile -- pointer to mfile (to mailer) connection. 529c579ef51Seric ** prfile -- pointer to rfile (from mailer) connection. 530c579ef51Seric ** 531c579ef51Seric ** Returns: 532c579ef51Seric ** pid of mailer. 533c579ef51Seric ** -1 on error. 534c579ef51Seric ** 535c579ef51Seric ** Side Effects: 536c579ef51Seric ** creates a mailer in a subprocess. 537c579ef51Seric */ 538c579ef51Seric 539c579ef51Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 540c579ef51Seric struct mailer *m; 541c579ef51Seric char **pvp; 542c579ef51Seric ADDRESS *ctladdr; 543c579ef51Seric bool clever; 544c579ef51Seric FILE **pmfile; 545c579ef51Seric FILE **prfile; 546c579ef51Seric { 5475dfc646bSeric int pid; 548f8952a83Seric int mpvect[2]; 549c579ef51Seric int rpvect[2]; 5505dfc646bSeric FILE *mfile; 551c579ef51Seric FILE *rfile; 5525dfc646bSeric extern FILE *fdopen(); 5535dfc646bSeric 5545dfc646bSeric # ifdef DEBUG 5555dfc646bSeric if (Debug) 5565dfc646bSeric { 557c579ef51Seric printf("openmailer:\n"); 5585dfc646bSeric printav(pvp); 5595dfc646bSeric } 5605dfc646bSeric # endif DEBUG 56135490626Seric errno = 0; 5625dfc646bSeric 5636328bdf7Seric /* create a pipe to shove the mail through */ 564f8952a83Seric if (pipe(mpvect) < 0) 56525a99e2eSeric { 566c579ef51Seric syserr("pipe (to mailer)"); 56725a99e2eSeric return (-1); 56825a99e2eSeric } 569c579ef51Seric 570c579ef51Seric /* if this mailer speaks smtp, create a return pipe */ 571c579ef51Seric if (clever && pipe(rpvect) < 0) 572c579ef51Seric { 573c579ef51Seric syserr("pipe (from mailer)"); 574c579ef51Seric (void) close(mpvect[0]); 575c579ef51Seric (void) close(mpvect[1]); 576c579ef51Seric return (-1); 577c579ef51Seric } 578c579ef51Seric 57932d19d43Seric DOFORK(XFORK); 580f129ec7dSeric /* pid is set by DOFORK */ 58125a99e2eSeric if (pid < 0) 58225a99e2eSeric { 58325a99e2eSeric syserr("Cannot fork"); 584f8952a83Seric (void) close(mpvect[0]); 585f8952a83Seric (void) close(mpvect[1]); 586c579ef51Seric if (clever) 587c579ef51Seric { 588c579ef51Seric (void) close(rpvect[0]); 589c579ef51Seric (void) close(rpvect[1]); 590c579ef51Seric } 59125a99e2eSeric return (-1); 59225a99e2eSeric } 59325a99e2eSeric else if (pid == 0) 59425a99e2eSeric { 59525a99e2eSeric /* child -- set up input & exec mailer */ 59603ab8e55Seric /* make diagnostic output be standard output */ 5978f0e7860Seric (void) signal(SIGINT, SIG_IGN); 5988f0e7860Seric (void) signal(SIGHUP, SIG_IGN); 5990984da9fSeric (void) signal(SIGTERM, SIG_DFL); 600f8952a83Seric 601f8952a83Seric /* arrange to filter standard & diag output of command */ 602c579ef51Seric if (clever) 603c579ef51Seric { 604c579ef51Seric (void) close(rpvect[0]); 605c579ef51Seric (void) close(1); 606c579ef51Seric (void) dup(rpvect[1]); 607c579ef51Seric (void) close(rpvect[1]); 608c579ef51Seric } 609c579ef51Seric else if (OutChannel != stdout) 610f8952a83Seric { 611f8952a83Seric (void) close(1); 612f8952a83Seric (void) dup(fileno(OutChannel)); 613f8952a83Seric } 614db8841e9Seric (void) close(2); 615db8841e9Seric (void) dup(1); 616f8952a83Seric 617f8952a83Seric /* arrange to get standard input */ 618f8952a83Seric (void) close(mpvect[1]); 619db8841e9Seric (void) close(0); 620f8952a83Seric if (dup(mpvect[0]) < 0) 62125a99e2eSeric { 62225a99e2eSeric syserr("Cannot dup to zero!"); 623a590b978Seric _exit(EX_OSERR); 62425a99e2eSeric } 625f8952a83Seric (void) close(mpvect[0]); 6262a6e0786Seric if (!bitset(M_RESTR, m->m_flags)) 6270984da9fSeric { 628e36b99e2Seric if (ctladdr->q_uid == 0) 629e36b99e2Seric { 63069f29479Seric extern int DefUid, DefGid; 63169f29479Seric 632e36b99e2Seric (void) setgid(DefGid); 633e36b99e2Seric (void) setuid(DefUid); 634e36b99e2Seric } 635e36b99e2Seric else 63669f29479Seric { 637e36b99e2Seric (void) setgid(ctladdr->q_gid); 638e36b99e2Seric (void) setuid(ctladdr->q_uid); 63969f29479Seric } 6400984da9fSeric } 641e374fd72Seric # ifndef VFORK 642e374fd72Seric /* 643e374fd72Seric ** We have to be careful with vfork - we can't mung up the 644e374fd72Seric ** memory but we don't want the mailer to inherit any extra 645e374fd72Seric ** open files. Chances are the mailer won't 646e374fd72Seric ** care about an extra file, but then again you never know. 647e374fd72Seric ** Actually, we would like to close(fileno(pwf)), but it's 648e374fd72Seric ** declared static so we can't. But if we fclose(pwf), which 649e374fd72Seric ** is what endpwent does, it closes it in the parent too and 650e374fd72Seric ** the next getpwnam will be slower. If you have a weird 651e374fd72Seric ** mailer that chokes on the extra file you should do the 652e374fd72Seric ** endpwent(). 653e374fd72Seric ** 654e374fd72Seric ** Similar comments apply to log. However, openlog is 655e374fd72Seric ** clever enough to set the FIOCLEX mode on the file, 656e374fd72Seric ** so it will be closed automatically on the exec. 657e374fd72Seric */ 658e374fd72Seric 659e374fd72Seric endpwent(); 66025a99e2eSeric # ifdef LOG 661f9fe028fSeric closelog(); 66225a99e2eSeric # endif LOG 663e374fd72Seric # endif VFORK 66425a99e2eSeric execv(m->m_mailer, pvp); 66525a99e2eSeric /* syserr fails because log is closed */ 66625a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 66732d19d43Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 668db8841e9Seric (void) fflush(stdout); 669a590b978Seric _exit(EX_UNAVAILABLE); 67025a99e2eSeric } 67125a99e2eSeric 672f8952a83Seric /* 673c579ef51Seric ** Set up return value. 674f8952a83Seric */ 675f8952a83Seric 676f8952a83Seric (void) close(mpvect[0]); 677f8952a83Seric mfile = fdopen(mpvect[1], "w"); 678c579ef51Seric if (clever) 67925a99e2eSeric { 680c579ef51Seric (void) close(rpvect[1]); 681c579ef51Seric rfile = fdopen(rpvect[0], "r"); 68225a99e2eSeric } 683c579ef51Seric 684c579ef51Seric *pmfile = mfile; 685c579ef51Seric *prfile = rfile; 686c579ef51Seric 687c579ef51Seric return (pid); 68825a99e2eSeric } 68925a99e2eSeric /* 69025a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 69125a99e2eSeric ** 69225a99e2eSeric ** Parameters: 69325a99e2eSeric ** stat -- the status code from the mailer (high byte 69425a99e2eSeric ** only; core dumps must have been taken care of 69525a99e2eSeric ** already). 69625a99e2eSeric ** force -- if set, force an error message output, even 69725a99e2eSeric ** if the mailer seems to like to print its own 69825a99e2eSeric ** messages. 69925a99e2eSeric ** m -- the mailer descriptor for this mailer. 70025a99e2eSeric ** 70125a99e2eSeric ** Returns: 702db8841e9Seric ** none. 70325a99e2eSeric ** 70425a99e2eSeric ** Side Effects: 705c1f9df2cSeric ** Errors may be incremented. 70625a99e2eSeric ** ExitStat may be set. 70725a99e2eSeric */ 70825a99e2eSeric 70925a99e2eSeric giveresponse(stat, force, m) 71025a99e2eSeric int stat; 71125a99e2eSeric int force; 71225a99e2eSeric register struct mailer *m; 71325a99e2eSeric { 71425a99e2eSeric register char *statmsg; 71525a99e2eSeric extern char *SysExMsg[]; 71625a99e2eSeric register int i; 71725a99e2eSeric extern int N_SysEx; 71829dd97a3Seric char buf[30]; 71925a99e2eSeric 72013bbc08cSeric /* 72113bbc08cSeric ** Compute status message from code. 72213bbc08cSeric */ 72313bbc08cSeric 72425a99e2eSeric i = stat - EX__BASE; 72525a99e2eSeric if (i < 0 || i > N_SysEx) 72625a99e2eSeric statmsg = NULL; 72725a99e2eSeric else 72825a99e2eSeric statmsg = SysExMsg[i]; 72925a99e2eSeric if (stat == 0) 730c38ba59cSeric { 7316cbfa739Seric if (bitset(M_LOCAL, m->m_flags)) 7323efaed6eSeric statmsg = "delivered"; 7333efaed6eSeric else 7343efaed6eSeric statmsg = "queued"; 735c38ba59cSeric if (Verbose) 736544026c5Seric message(Arpa_Info, statmsg); 737c38ba59cSeric } 738c77d1c25Seric else if (stat == EX_TEMPFAIL) 739c77d1c25Seric { 740c77d1c25Seric if (Verbose) 741c77d1c25Seric message(Arpa_Info, "transmission deferred"); 742c77d1c25Seric } 74325a99e2eSeric else 74425a99e2eSeric { 745c1f9df2cSeric Errors++; 74625a99e2eSeric if (statmsg == NULL && m->m_badstat != 0) 74725a99e2eSeric { 74825a99e2eSeric stat = m->m_badstat; 74925a99e2eSeric i = stat - EX__BASE; 75025a99e2eSeric # ifdef DEBUG 75125a99e2eSeric if (i < 0 || i >= N_SysEx) 75225a99e2eSeric syserr("Bad m_badstat %d", stat); 75325a99e2eSeric else 75425a99e2eSeric # endif DEBUG 75525a99e2eSeric statmsg = SysExMsg[i]; 75625a99e2eSeric } 75725a99e2eSeric if (statmsg == NULL) 75825a99e2eSeric usrerr("unknown mailer response %d", stat); 759c38ba59cSeric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 76025a99e2eSeric usrerr("%s", statmsg); 76125a99e2eSeric } 76225a99e2eSeric 76325a99e2eSeric /* 76425a99e2eSeric ** Final cleanup. 76525a99e2eSeric ** Log a record of the transaction. Compute the new 76625a99e2eSeric ** ExitStat -- if we already had an error, stick with 76725a99e2eSeric ** that. 76825a99e2eSeric */ 76925a99e2eSeric 77025a99e2eSeric if (statmsg == NULL) 77129dd97a3Seric { 772db8841e9Seric (void) sprintf(buf, "error %d", stat); 77329dd97a3Seric statmsg = buf; 77429dd97a3Seric } 77529dd97a3Seric 77629dd97a3Seric # ifdef LOG 777e374fd72Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 77825a99e2eSeric # endif LOG 779c77d1c25Seric if (stat != EX_TEMPFAIL) 780243921eeSeric setstat(stat); 78125a99e2eSeric } 78225a99e2eSeric /* 7836328bdf7Seric ** PUTMESSAGE -- output a message to the final mailer. 78425a99e2eSeric ** 7856328bdf7Seric ** This routine takes care of recreating the header from the 7866328bdf7Seric ** in-core copy, etc. 78725a99e2eSeric ** 78825a99e2eSeric ** Parameters: 7896328bdf7Seric ** fp -- file to output onto. 7906328bdf7Seric ** m -- a mailer descriptor. 791c579ef51Seric ** xdot -- if set, hide lines beginning with dot. 79225a99e2eSeric ** 79325a99e2eSeric ** Returns: 7946328bdf7Seric ** none. 79525a99e2eSeric ** 79625a99e2eSeric ** Side Effects: 7976328bdf7Seric ** The message is written onto fp. 79825a99e2eSeric */ 79925a99e2eSeric 800c579ef51Seric putmessage(fp, m, xdot) 8016328bdf7Seric FILE *fp; 8026328bdf7Seric struct mailer *m; 803c579ef51Seric bool xdot; 80425a99e2eSeric { 8056328bdf7Seric char buf[BUFSIZ]; 80613bbc08cSeric register HDR *h; 8076328bdf7Seric extern char *arpadate(); 8086328bdf7Seric bool anyheader = FALSE; 809e9ff65b0Seric extern char *capitalize(); 81087bd9a02Seric extern char *hvalue(); 81187bd9a02Seric extern bool samefrom(); 812894de7daSeric char *of_line; 81325a99e2eSeric 81413bbc08cSeric /* 81513bbc08cSeric ** Output "From" line unless supressed 81613bbc08cSeric */ 81713bbc08cSeric 81840e4ab56Seric if (!bitset(M_NHDR, m->m_flags)) 8191412cc7cSeric { 8201412cc7cSeric (void) expand("$l", buf, &buf[sizeof buf - 1]); 8211412cc7cSeric fprintf(fp, "%s\n", buf); 8221412cc7cSeric } 82340e4ab56Seric 82413bbc08cSeric /* 82513bbc08cSeric ** Output all header lines 82613bbc08cSeric */ 82713bbc08cSeric 828894de7daSeric of_line = hvalue("original-from"); 8296328bdf7Seric for (h = Header; h != NULL; h = h->h_link) 8306328bdf7Seric { 83113bbc08cSeric register char *p; 83287bd9a02Seric char *origfrom = OrigFrom; 833894de7daSeric bool nooutput; 83413bbc08cSeric 835894de7daSeric nooutput = FALSE; 8369e9163a0Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 8375a0dcb5fSeric { 8385a0dcb5fSeric p = ")><("; /* can't happen (I hope) */ 839894de7daSeric nooutput = TRUE; 8405a0dcb5fSeric } 841894de7daSeric 842894de7daSeric /* use From: line from message if generated is the same */ 84387bd9a02Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 844894de7daSeric strcmp(m->m_from, "$f") == 0 && of_line == NULL) 84587bd9a02Seric { 84687bd9a02Seric p = origfrom; 84787bd9a02Seric origfrom = NULL; 84887bd9a02Seric } 84987bd9a02Seric else if (bitset(H_DEFAULT, h->h_flags)) 8504ae18d0eSeric { 851db8841e9Seric (void) expand(h->h_value, buf, &buf[sizeof buf]); 8524ae18d0eSeric p = buf; 8534ae18d0eSeric } 8544ae18d0eSeric else 8554ae18d0eSeric p = h->h_value; 856894de7daSeric if (p == NULL || *p == '\0') 8579e9163a0Seric continue; 8585a0dcb5fSeric 8595a0dcb5fSeric /* hack, hack -- output Original-From field if different */ 860894de7daSeric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL) 861894de7daSeric { 862894de7daSeric /* output new Original-From line if needed */ 863894de7daSeric if (of_line == NULL && !samefrom(p, origfrom)) 8645a0dcb5fSeric { 86587bd9a02Seric fprintf(fp, "Original-From: %s\n", origfrom); 86687bd9a02Seric anyheader = TRUE; 8675a0dcb5fSeric } 868894de7daSeric if (of_line != NULL && !nooutput && samefrom(p, of_line)) 869894de7daSeric { 870894de7daSeric /* delete Original-From: line if redundant */ 871894de7daSeric p = of_line; 872894de7daSeric of_line = NULL; 873894de7daSeric } 874894de7daSeric } 875894de7daSeric else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL) 876894de7daSeric nooutput = TRUE; 877894de7daSeric 878894de7daSeric /* finally, output the header line */ 879894de7daSeric if (!nooutput) 880894de7daSeric { 881894de7daSeric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 882894de7daSeric h->h_flags |= H_USED; 883894de7daSeric anyheader = TRUE; 884894de7daSeric } 8856328bdf7Seric } 8866328bdf7Seric if (anyheader) 8876328bdf7Seric fprintf(fp, "\n"); 8886328bdf7Seric 88913bbc08cSeric /* 89013bbc08cSeric ** Output the body of the message 89113bbc08cSeric */ 89213bbc08cSeric 89378442df3Seric if (TempFile != NULL) 89478442df3Seric { 895b7902a1dSeric rewind(TempFile); 896c579ef51Seric while (!ferror(fp) && fgets(buf, sizeof buf, TempFile) != NULL) 897c579ef51Seric fprintf(fp, "%s%s", xdot && buf[0] == '.' ? "." : "", buf); 8986328bdf7Seric 89978442df3Seric if (ferror(TempFile)) 90078442df3Seric { 90178442df3Seric syserr("putmessage: read error"); 90278442df3Seric setstat(EX_IOERR); 90378442df3Seric } 90478442df3Seric } 90578442df3Seric 906c77d1c25Seric (void) fflush(fp); 90754aa2b0fSeric if (ferror(fp) && errno != EPIPE) 90825a99e2eSeric { 9096328bdf7Seric syserr("putmessage: write error"); 91025a99e2eSeric setstat(EX_IOERR); 91125a99e2eSeric } 91254aa2b0fSeric errno = 0; 91325a99e2eSeric } 91425a99e2eSeric /* 91587bd9a02Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 91687bd9a02Seric ** 91787bd9a02Seric ** Parameters: 91887bd9a02Seric ** ifrom -- internally generated form of from address. 91987bd9a02Seric ** efrom -- external form of from address. 92087bd9a02Seric ** 92187bd9a02Seric ** Returns: 92287bd9a02Seric ** TRUE -- if they convey the same info. 92387bd9a02Seric ** FALSE -- if any information has been lost. 92487bd9a02Seric ** 92587bd9a02Seric ** Side Effects: 92687bd9a02Seric ** none. 92787bd9a02Seric */ 92887bd9a02Seric 92987bd9a02Seric bool 93087bd9a02Seric samefrom(ifrom, efrom) 93187bd9a02Seric char *ifrom; 93287bd9a02Seric char *efrom; 93387bd9a02Seric { 934894de7daSeric register char *p; 935894de7daSeric char buf[MAXNAME + 4]; 936894de7daSeric 937894de7daSeric # ifdef DEBUG 938894de7daSeric if (Debug > 7) 939894de7daSeric printf("samefrom(%s,%s)-->", ifrom, efrom); 940894de7daSeric # endif DEBUG 941894de7daSeric if (strcmp(ifrom, efrom) == 0) 942894de7daSeric goto success; 943894de7daSeric p = index(ifrom, '@'); 944894de7daSeric if (p == NULL) 945894de7daSeric goto failure; 946894de7daSeric *p = '\0'; 947894de7daSeric strcpy(buf, ifrom); 948894de7daSeric strcat(buf, " at "); 949894de7daSeric *p++ = '@'; 950894de7daSeric strcat(buf, p); 951894de7daSeric if (strcmp(buf, efrom) == 0) 952894de7daSeric goto success; 953894de7daSeric 954894de7daSeric failure: 955894de7daSeric # ifdef DEBUG 956894de7daSeric if (Debug > 7) 957894de7daSeric printf("FALSE\n"); 958894de7daSeric # endif DEBUG 959894de7daSeric return (FALSE); 960894de7daSeric 961894de7daSeric success: 962894de7daSeric # ifdef DEBUG 963894de7daSeric if (Debug > 7) 964894de7daSeric printf("TRUE\n"); 965894de7daSeric # endif DEBUG 966894de7daSeric return (TRUE); 96787bd9a02Seric } 96887bd9a02Seric /* 96925a99e2eSeric ** MAILFILE -- Send a message to a file. 97025a99e2eSeric ** 971f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 972f129ec7dSeric ** bits, sendmail will try to become the owner of that file 973f129ec7dSeric ** rather than the real user. Obviously, this only works if 974f129ec7dSeric ** sendmail runs as root. 975f129ec7dSeric ** 97625a99e2eSeric ** Parameters: 97725a99e2eSeric ** filename -- the name of the file to send to. 9786259796dSeric ** ctladdr -- the controlling address header -- includes 9796259796dSeric ** the userid/groupid to be when sending. 98025a99e2eSeric ** 98125a99e2eSeric ** Returns: 98225a99e2eSeric ** The exit code associated with the operation. 98325a99e2eSeric ** 98425a99e2eSeric ** Side Effects: 98525a99e2eSeric ** none. 98625a99e2eSeric */ 98725a99e2eSeric 9886259796dSeric mailfile(filename, ctladdr) 98925a99e2eSeric char *filename; 9906259796dSeric ADDRESS *ctladdr; 99125a99e2eSeric { 99225a99e2eSeric register FILE *f; 99332d19d43Seric register int pid; 99425a99e2eSeric 99532d19d43Seric /* 99632d19d43Seric ** Fork so we can change permissions here. 99732d19d43Seric ** Note that we MUST use fork, not vfork, because of 99832d19d43Seric ** the complications of calling subroutines, etc. 99932d19d43Seric */ 100032d19d43Seric 100132d19d43Seric DOFORK(fork); 100232d19d43Seric 100332d19d43Seric if (pid < 0) 100432d19d43Seric return (EX_OSERR); 100532d19d43Seric else if (pid == 0) 100632d19d43Seric { 100732d19d43Seric /* child -- actually write to file */ 1008f129ec7dSeric struct stat stb; 1009e36b99e2Seric extern int DefUid, DefGid; 1010f129ec7dSeric 10110984da9fSeric (void) signal(SIGINT, SIG_DFL); 10120984da9fSeric (void) signal(SIGHUP, SIG_DFL); 10130984da9fSeric (void) signal(SIGTERM, SIG_DFL); 1014f129ec7dSeric umask(OldUmask); 1015f129ec7dSeric if (stat(filename, &stb) < 0) 1016e6e1265fSeric stb.st_mode = 0666; 1017f129ec7dSeric if (bitset(0111, stb.st_mode)) 1018f129ec7dSeric exit(EX_CANTCREAT); 101903827b5fSeric if (ctladdr == NULL) 102003827b5fSeric ctladdr = &From; 1021f129ec7dSeric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 1022e36b99e2Seric { 1023e36b99e2Seric if (ctladdr->q_uid == 0) 1024e36b99e2Seric (void) setgid(DefGid); 1025e36b99e2Seric else 10266259796dSeric (void) setgid(ctladdr->q_gid); 1027e36b99e2Seric } 1028f129ec7dSeric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 1029e36b99e2Seric { 1030e36b99e2Seric if (ctladdr->q_uid == 0) 1031e36b99e2Seric (void) setuid(DefUid); 1032e36b99e2Seric else 10336259796dSeric (void) setuid(ctladdr->q_uid); 1034e36b99e2Seric } 103525a99e2eSeric f = fopen(filename, "a"); 103625a99e2eSeric if (f == NULL) 103732d19d43Seric exit(EX_CANTCREAT); 103825a99e2eSeric 1039c579ef51Seric putmessage(f, Mailer[1], FALSE); 104025a99e2eSeric fputs("\n", f); 1041db8841e9Seric (void) fclose(f); 104232d19d43Seric (void) fflush(stdout); 1043e36b99e2Seric 1044e36b99e2Seric /* reset ISUID & ISGID bits */ 1045c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 104632d19d43Seric exit(EX_OK); 104713bbc08cSeric /*NOTREACHED*/ 104832d19d43Seric } 104932d19d43Seric else 105032d19d43Seric { 105132d19d43Seric /* parent -- wait for exit status */ 105232d19d43Seric register int i; 105332d19d43Seric auto int stat; 105432d19d43Seric 105532d19d43Seric while ((i = wait(&stat)) != pid) 105632d19d43Seric { 105732d19d43Seric if (i < 0) 105832d19d43Seric { 105932d19d43Seric stat = EX_OSERR << 8; 106032d19d43Seric break; 106132d19d43Seric } 106232d19d43Seric } 10630984da9fSeric if ((stat & 0377) != 0) 10640984da9fSeric stat = EX_UNAVAILABLE << 8; 106532d19d43Seric return ((stat >> 8) & 0377); 106632d19d43Seric } 106725a99e2eSeric } 1068ea4dc939Seric /* 1069ea4dc939Seric ** SENDALL -- actually send all the messages. 1070ea4dc939Seric ** 1071ea4dc939Seric ** Parameters: 1072ea4dc939Seric ** verifyonly -- if set, only give verification messages. 1073ea4dc939Seric ** 1074ea4dc939Seric ** Returns: 1075ea4dc939Seric ** none. 1076ea4dc939Seric ** 1077ea4dc939Seric ** Side Effects: 1078ea4dc939Seric ** Scans the send lists and sends everything it finds. 1079ea4dc939Seric */ 1080ea4dc939Seric 1081ea4dc939Seric sendall(verifyonly) 1082ea4dc939Seric bool verifyonly; 1083ea4dc939Seric { 1084e77e673fSeric register ADDRESS *q; 1085ea4dc939Seric typedef int (*fnptr)(); 1086ea4dc939Seric 1087*772e6e50Seric # ifdef DEBUG 1088*772e6e50Seric if (Debug > 1) 1089*772e6e50Seric { 1090*772e6e50Seric printf("\nSendQueue:\n"); 1091*772e6e50Seric printaddr(SendQueue, TRUE); 1092*772e6e50Seric } 1093*772e6e50Seric # endif DEBUG 1094ea4dc939Seric 1095e77e673fSeric for (q = SendQueue; q != NULL; q = q->q_next) 1096ea4dc939Seric { 1097ea4dc939Seric if (verifyonly) 1098ea4dc939Seric { 1099ea4dc939Seric To = q->q_paddr; 1100e77e673fSeric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 1101ea4dc939Seric { 11027da1035fSeric if (bitset(M_LOCAL, q->q_mailer->m_flags)) 1103ea4dc939Seric message(Arpa_Info, "deliverable"); 1104ea4dc939Seric else 1105ea4dc939Seric message(Arpa_Info, "queueable"); 1106ea4dc939Seric } 1107ea4dc939Seric } 1108ea4dc939Seric else 1109ea4dc939Seric (void) deliver(q, (fnptr) NULL); 1110ea4dc939Seric } 1111ea4dc939Seric } 1112