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*a49f24c0Seric SCCSID(@(#)deliver.c 3.62 01/23/82); 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; 58772e6e50Seric 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 */ 1382c7e1b8dSeric # ifdef SMTP 139c579ef51Seric clever = TRUE; 140c579ef51Seric *pvp = NULL; 141c579ef51Seric i = smtpinit(m, pv, (ADDRESS *) NULL); 142c579ef51Seric giveresponse(i, TRUE, m); 1432c7e1b8dSeric # ifdef QUEUE 144c579ef51Seric if (i == EX_TEMPFAIL) 145c579ef51Seric { 146c579ef51Seric QueueUp = TRUE; 147c579ef51Seric tempfail = TRUE; 148c579ef51Seric } 1492c7e1b8dSeric # endif QUEUE 1502c7e1b8dSeric # else SMTP 1512c7e1b8dSeric syserr("SMTP style mailer"); 1522c7e1b8dSeric return (EX_SOFTWARE); 1532c7e1b8dSeric # endif SMTP 154c579ef51Seric } 1555dfc646bSeric 1565dfc646bSeric /* 1575dfc646bSeric ** At this point *mvp points to the argument with $u. We 1585dfc646bSeric ** run through our address list and append all the addresses 1595dfc646bSeric ** we can. If we run out of space, do not fret! We can 1605dfc646bSeric ** always send another copy later. 1615dfc646bSeric */ 1625dfc646bSeric 1635dfc646bSeric tobuf[0] = '\0'; 1645dfc646bSeric To = tobuf; 1656259796dSeric ctladdr = NULL; 1665dfc646bSeric for (; to != NULL; to = to->q_next) 1675dfc646bSeric { 1685dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 169bea22b26Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1705dfc646bSeric break; 1715dfc646bSeric 1725dfc646bSeric /* if already sent or not for this host, don't send */ 173e77e673fSeric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 174e77e673fSeric strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) 1755dfc646bSeric continue; 1766259796dSeric 177772e6e50Seric # ifdef DEBUG 178772e6e50Seric if (Debug) 179772e6e50Seric { 180772e6e50Seric printf("\nsend to "); 181772e6e50Seric printaddr(to, FALSE); 182772e6e50Seric } 183772e6e50Seric # endif DEBUG 184772e6e50Seric 185772e6e50Seric /* link together the chain of recipients */ 186772e6e50Seric if (!bitset(QDONTSEND, to->q_flags)) 187772e6e50Seric { 188772e6e50Seric to->q_tchain = tochain; 189772e6e50Seric tochain = to; 190772e6e50Seric } 191772e6e50Seric 1926259796dSeric /* compute effective uid/gid when sending */ 1937da1035fSeric if (to->q_mailer == ProgMailer) 1946259796dSeric ctladdr = getctladdr(to); 1956259796dSeric 1965dfc646bSeric user = to->q_user; 1975dfc646bSeric To = to->q_paddr; 1985dfc646bSeric to->q_flags |= QDONTSEND; 199c579ef51Seric if (tempfail) 200772e6e50Seric { 201c579ef51Seric to->q_flags |= QQUEUEUP; 202772e6e50Seric continue; 203772e6e50Seric } 2045dfc646bSeric 2055dfc646bSeric /* 2065dfc646bSeric ** Check to see that these people are allowed to 2075dfc646bSeric ** talk to each other. 2082a6e0786Seric */ 2092a6e0786Seric 2102a6e0786Seric if (!checkcompat(to)) 2115dfc646bSeric { 2125dfc646bSeric giveresponse(EX_UNAVAILABLE, TRUE, m); 2135dfc646bSeric continue; 2145dfc646bSeric } 2152a6e0786Seric 2162a6e0786Seric /* 2179ec9501bSeric ** Strip quote bits from names if the mailer is dumb 2189ec9501bSeric ** about them. 21925a99e2eSeric */ 22025a99e2eSeric 2212a6e0786Seric if (bitset(M_STRIPQ, m->m_flags)) 22225a99e2eSeric { 2239ec9501bSeric stripquotes(user, TRUE); 2249ec9501bSeric stripquotes(host, TRUE); 2259ec9501bSeric } 2269ec9501bSeric else 2279ec9501bSeric { 2289ec9501bSeric stripquotes(user, FALSE); 2299ec9501bSeric stripquotes(host, FALSE); 23025a99e2eSeric } 23125a99e2eSeric 23225a99e2eSeric /* 2333efaed6eSeric ** If an error message has already been given, don't 2343efaed6eSeric ** bother to send to this address. 2353efaed6eSeric ** 2363efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 2373efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 2383efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 2393efaed6eSeric */ 2403efaed6eSeric 2413efaed6eSeric if (bitset(QBADADDR, to->q_flags)) 2423efaed6eSeric continue; 2433efaed6eSeric 244f2fec898Seric /* save statistics.... */ 2457da1035fSeric Stat.stat_nt[to->q_mailer->m_mno]++; 2467da1035fSeric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(MsgSize); 247f2fec898Seric 2483efaed6eSeric /* 24925a99e2eSeric ** See if this user name is "special". 25025a99e2eSeric ** If the user name has a slash in it, assume that this 25125a99e2eSeric ** is a file -- send it off without further ado. 25225a99e2eSeric ** Note that this means that editfcn's will not 2535dfc646bSeric ** be applied to the message. Also note that 2545dfc646bSeric ** this type of addresses is not processed along 2555dfc646bSeric ** with the others, so we fudge on the To person. 25625a99e2eSeric */ 25725a99e2eSeric 2587da1035fSeric if (m == LocalMailer) 25925a99e2eSeric { 260*a49f24c0Seric if (user[0] == '/') 26125a99e2eSeric { 2626259796dSeric i = mailfile(user, getctladdr(to)); 26325a99e2eSeric giveresponse(i, TRUE, m); 2645dfc646bSeric continue; 26525a99e2eSeric } 26625a99e2eSeric } 26725a99e2eSeric 26813bbc08cSeric /* 26913bbc08cSeric ** Address is verified -- add this user to mailer 27013bbc08cSeric ** argv, and add it to the print list of recipients. 27113bbc08cSeric */ 27213bbc08cSeric 2735dfc646bSeric /* create list of users for error messages */ 2745dfc646bSeric if (tobuf[0] != '\0') 275db8841e9Seric (void) strcat(tobuf, ","); 276db8841e9Seric (void) strcat(tobuf, to->q_paddr); 2775dfc646bSeric define('u', user); /* to user */ 278c2567733Seric define('z', to->q_home); /* user's home */ 2795dfc646bSeric 280c579ef51Seric /* 281c579ef51Seric ** Expand out this user into argument list or 282c579ef51Seric ** send it to our SMTP server. 283c579ef51Seric */ 284c579ef51Seric 285c579ef51Seric if (clever) 286c579ef51Seric { 2872c7e1b8dSeric # ifdef SMTP 288d2b7d202Seric i = smtprcpt(to); 2892c7e1b8dSeric if (i != EX_OK) 2902c7e1b8dSeric { 2912c7e1b8dSeric # ifdef QUEUE 292c579ef51Seric if (i == EX_TEMPFAIL) 293c579ef51Seric { 294c579ef51Seric QueueUp = TRUE; 295c579ef51Seric to->q_flags |= QQUEUEUP; 296c579ef51Seric } 2972c7e1b8dSeric else 2982c7e1b8dSeric # endif QUEUE 299c579ef51Seric { 300c579ef51Seric to->q_flags |= QBADADDR; 301c579ef51Seric giveresponse(i, TRUE, m); 302c579ef51Seric } 303c579ef51Seric } 3042c7e1b8dSeric # else SMTP 3052c7e1b8dSeric syserr("trying to be clever"); 3062c7e1b8dSeric # endif SMTP 3072c7e1b8dSeric } 308c579ef51Seric else 309c579ef51Seric { 310d4ccc802Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3115dfc646bSeric *pvp++ = newstr(buf); 3125dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 3135dfc646bSeric { 3145dfc646bSeric /* allow some space for trailing parms */ 3155dfc646bSeric break; 3165dfc646bSeric } 3175dfc646bSeric } 318c579ef51Seric } 3195dfc646bSeric 320145b49b1Seric /* see if any addresses still exist */ 321145b49b1Seric if (tobuf[0] == '\0') 322c579ef51Seric { 3232c7e1b8dSeric # ifdef SMTP 324c579ef51Seric if (clever) 325c579ef51Seric smtpquit(pv[0]); 3262c7e1b8dSeric # endif SMTP 327145b49b1Seric return (0); 328c579ef51Seric } 329145b49b1Seric 3305dfc646bSeric /* print out messages as full list */ 3315dfc646bSeric To = tobuf; 3325dfc646bSeric 3335dfc646bSeric /* 3345dfc646bSeric ** Fill out any parameters after the $u parameter. 3355dfc646bSeric */ 3365dfc646bSeric 337c579ef51Seric while (!clever && *++mvp != NULL) 3385dfc646bSeric { 339db8841e9Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3405dfc646bSeric *pvp++ = newstr(buf); 3415dfc646bSeric if (pvp >= &pv[MAXPV]) 3425dfc646bSeric syserr("deliver: pv overflow after $u for %s", pv[0]); 3435dfc646bSeric } 3445dfc646bSeric *pvp++ = NULL; 3455dfc646bSeric 34625a99e2eSeric /* 34725a99e2eSeric ** Call the mailer. 3486328bdf7Seric ** The argument vector gets built, pipes 34925a99e2eSeric ** are created as necessary, and we fork & exec as 3506328bdf7Seric ** appropriate. 351c579ef51Seric ** If we are running SMTP, we just need to clean up. 35225a99e2eSeric */ 35325a99e2eSeric 3545dfc646bSeric if (editfcn == NULL) 3555dfc646bSeric editfcn = putmessage; 3566259796dSeric if (ctladdr == NULL) 3576259796dSeric ctladdr = &From; 3582c7e1b8dSeric # ifdef SMTP 359c579ef51Seric if (clever) 360c579ef51Seric { 361c579ef51Seric i = smtpfinish(m, editfcn); 362c579ef51Seric smtpquit(pv[0]); 363c579ef51Seric } 364c579ef51Seric else 3652c7e1b8dSeric # endif SMTP 3666259796dSeric i = sendoff(m, pv, editfcn, ctladdr); 3675dfc646bSeric 368c77d1c25Seric /* 369c77d1c25Seric ** If we got a temporary failure, arrange to queue the 370c77d1c25Seric ** addressees. 371c77d1c25Seric */ 372c77d1c25Seric 3732c7e1b8dSeric # ifdef QUEUE 374c77d1c25Seric if (i == EX_TEMPFAIL) 375c77d1c25Seric { 376c77d1c25Seric QueueUp = TRUE; 377772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 378c77d1c25Seric to->q_flags |= QQUEUEUP; 379c77d1c25Seric } 3802c7e1b8dSeric # endif QUEUE 381c77d1c25Seric 38235490626Seric errno = 0; 3835dfc646bSeric return (i); 38425a99e2eSeric } 3855dfc646bSeric /* 38632d19d43Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 38732d19d43Seric ** 38832d19d43Seric ** This MUST be a macro, since after a vfork we are running 38932d19d43Seric ** two processes on the same stack!!! 39032d19d43Seric ** 39132d19d43Seric ** Parameters: 39232d19d43Seric ** none. 39332d19d43Seric ** 39432d19d43Seric ** Returns: 39532d19d43Seric ** From a macro??? You've got to be kidding! 39632d19d43Seric ** 39732d19d43Seric ** Side Effects: 39832d19d43Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 39932d19d43Seric ** pid of child in parent, zero in child. 40032d19d43Seric ** -1 on unrecoverable error. 40132d19d43Seric ** 40232d19d43Seric ** Notes: 40332d19d43Seric ** I'm awfully sorry this looks so awful. That's 40432d19d43Seric ** vfork for you..... 40532d19d43Seric */ 40632d19d43Seric 40732d19d43Seric # define NFORKTRIES 5 40832d19d43Seric # ifdef VFORK 40932d19d43Seric # define XFORK vfork 41032d19d43Seric # else VFORK 41132d19d43Seric # define XFORK fork 41232d19d43Seric # endif VFORK 41332d19d43Seric 41432d19d43Seric # define DOFORK(fORKfN) \ 41532d19d43Seric {\ 41632d19d43Seric register int i;\ 41732d19d43Seric \ 41832d19d43Seric for (i = NFORKTRIES; i-- > 0; )\ 41932d19d43Seric {\ 42032d19d43Seric pid = fORKfN();\ 42132d19d43Seric if (pid >= 0)\ 42232d19d43Seric break;\ 42332d19d43Seric sleep((unsigned) NFORKTRIES - i);\ 42432d19d43Seric }\ 42532d19d43Seric } 42632d19d43Seric /* 4272ed72599Seric ** DOFORK -- simple fork interface to DOFORK. 4282ed72599Seric ** 4292ed72599Seric ** Parameters: 4302ed72599Seric ** none. 4312ed72599Seric ** 4322ed72599Seric ** Returns: 4332ed72599Seric ** pid of child in parent. 4342ed72599Seric ** zero in child. 4352ed72599Seric ** -1 on error. 4362ed72599Seric ** 4372ed72599Seric ** Side Effects: 4382ed72599Seric ** returns twice, once in parent and once in child. 4392ed72599Seric */ 4402ed72599Seric 4412ed72599Seric dofork() 4422ed72599Seric { 4432ed72599Seric register int pid; 4442ed72599Seric 4452ed72599Seric DOFORK(fork); 4462ed72599Seric return (pid); 4472ed72599Seric } 4482ed72599Seric /* 4495dfc646bSeric ** SENDOFF -- send off call to mailer & collect response. 4505dfc646bSeric ** 4515dfc646bSeric ** Parameters: 4525dfc646bSeric ** m -- mailer descriptor. 4535dfc646bSeric ** pvp -- parameter vector to send to it. 4545dfc646bSeric ** editfcn -- function to pipe it through. 4556259796dSeric ** ctladdr -- an address pointer controlling the 4566259796dSeric ** user/groupid etc. of the mailer. 4575dfc646bSeric ** 4585dfc646bSeric ** Returns: 4595dfc646bSeric ** exit status of mailer. 4605dfc646bSeric ** 4615dfc646bSeric ** Side Effects: 4625dfc646bSeric ** none. 4635dfc646bSeric */ 4645dfc646bSeric 4656259796dSeric sendoff(m, pvp, editfcn, ctladdr) 4665dfc646bSeric struct mailer *m; 4675dfc646bSeric char **pvp; 4685dfc646bSeric int (*editfcn)(); 4696259796dSeric ADDRESS *ctladdr; 4705dfc646bSeric { 471c579ef51Seric auto FILE *mfile; 472c579ef51Seric auto FILE *rfile; 4735dfc646bSeric register int i; 474c579ef51Seric extern putmessage(); 475c579ef51Seric int pid; 476c579ef51Seric 477c579ef51Seric /* 478c579ef51Seric ** Create connection to mailer. 479c579ef51Seric */ 480c579ef51Seric 481c579ef51Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 482c579ef51Seric if (pid < 0) 483c579ef51Seric return (-1); 484c579ef51Seric 485c579ef51Seric /* 486c579ef51Seric ** Format and send message. 487c579ef51Seric */ 488c579ef51Seric 489c579ef51Seric (void) signal(SIGPIPE, SIG_IGN); 490c579ef51Seric if (editfcn == NULL) 491c579ef51Seric editfcn = putmessage; 492c579ef51Seric 493c579ef51Seric (*editfcn)(mfile, m, FALSE); 494c579ef51Seric (void) fclose(mfile); 495c579ef51Seric 496c579ef51Seric i = endmailer(pid, pvp[0]); 497c579ef51Seric giveresponse(i, TRUE, m); 498c579ef51Seric return (i); 499c579ef51Seric } 500c579ef51Seric /* 501c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 502c579ef51Seric ** 503c579ef51Seric ** We should never get fatal errors (e.g., segmentation 504c579ef51Seric ** violation), so we report those specially. For other 505c579ef51Seric ** errors, we choose a status message (into statmsg), 506c579ef51Seric ** and if it represents an error, we print it. 507c579ef51Seric ** 508c579ef51Seric ** Parameters: 509c579ef51Seric ** pid -- pid of mailer. 510c579ef51Seric ** name -- name of mailer (for error messages). 511c579ef51Seric ** 512c579ef51Seric ** Returns: 513c579ef51Seric ** exit code of mailer. 514c579ef51Seric ** 515c579ef51Seric ** Side Effects: 516c579ef51Seric ** none. 517c579ef51Seric */ 518c579ef51Seric 519c579ef51Seric endmailer(pid, name) 520c579ef51Seric int pid; 521c579ef51Seric char *name; 522c579ef51Seric { 523c579ef51Seric register int i; 524c579ef51Seric auto int st; 525c579ef51Seric 526c579ef51Seric while ((i = wait(&st)) > 0 && i != pid) 527c579ef51Seric continue; 528c579ef51Seric if (i < 0) 529c579ef51Seric { 530c579ef51Seric syserr("wait"); 531c579ef51Seric return (-1); 532c579ef51Seric } 533c579ef51Seric if ((st & 0377) != 0) 534c579ef51Seric { 535c579ef51Seric syserr("%s: stat %o", name, st); 536c579ef51Seric ExitStat = EX_UNAVAILABLE; 537c579ef51Seric return (-1); 538c579ef51Seric } 539c579ef51Seric i = (st >> 8) & 0377; 540c579ef51Seric return (i); 541c579ef51Seric } 542c579ef51Seric /* 543c579ef51Seric ** OPENMAILER -- open connection to mailer. 544c579ef51Seric ** 545c579ef51Seric ** Parameters: 546c579ef51Seric ** m -- mailer descriptor. 547c579ef51Seric ** pvp -- parameter vector to pass to mailer. 548c579ef51Seric ** ctladdr -- controlling address for user. 549c579ef51Seric ** clever -- create a full duplex connection. 550c579ef51Seric ** pmfile -- pointer to mfile (to mailer) connection. 551c579ef51Seric ** prfile -- pointer to rfile (from mailer) connection. 552c579ef51Seric ** 553c579ef51Seric ** Returns: 554c579ef51Seric ** pid of mailer. 555c579ef51Seric ** -1 on error. 556c579ef51Seric ** 557c579ef51Seric ** Side Effects: 558c579ef51Seric ** creates a mailer in a subprocess. 559c579ef51Seric */ 560c579ef51Seric 561c579ef51Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 562c579ef51Seric struct mailer *m; 563c579ef51Seric char **pvp; 564c579ef51Seric ADDRESS *ctladdr; 565c579ef51Seric bool clever; 566c579ef51Seric FILE **pmfile; 567c579ef51Seric FILE **prfile; 568c579ef51Seric { 5695dfc646bSeric int pid; 570f8952a83Seric int mpvect[2]; 571c579ef51Seric int rpvect[2]; 5725dfc646bSeric FILE *mfile; 573c579ef51Seric FILE *rfile; 5745dfc646bSeric extern FILE *fdopen(); 5755dfc646bSeric 5765dfc646bSeric # ifdef DEBUG 5775dfc646bSeric if (Debug) 5785dfc646bSeric { 579c579ef51Seric printf("openmailer:\n"); 5805dfc646bSeric printav(pvp); 5815dfc646bSeric } 5825dfc646bSeric # endif DEBUG 58335490626Seric errno = 0; 5845dfc646bSeric 5856328bdf7Seric /* create a pipe to shove the mail through */ 586f8952a83Seric if (pipe(mpvect) < 0) 58725a99e2eSeric { 588c579ef51Seric syserr("pipe (to mailer)"); 58925a99e2eSeric return (-1); 59025a99e2eSeric } 591c579ef51Seric 5922c7e1b8dSeric # ifdef SMTP 593c579ef51Seric /* if this mailer speaks smtp, create a return pipe */ 594c579ef51Seric if (clever && pipe(rpvect) < 0) 595c579ef51Seric { 596c579ef51Seric syserr("pipe (from mailer)"); 597c579ef51Seric (void) close(mpvect[0]); 598c579ef51Seric (void) close(mpvect[1]); 599c579ef51Seric return (-1); 600c579ef51Seric } 6012c7e1b8dSeric # endif SMTP 602c579ef51Seric 60332d19d43Seric DOFORK(XFORK); 604f129ec7dSeric /* pid is set by DOFORK */ 60525a99e2eSeric if (pid < 0) 60625a99e2eSeric { 60725a99e2eSeric syserr("Cannot fork"); 608f8952a83Seric (void) close(mpvect[0]); 609f8952a83Seric (void) close(mpvect[1]); 610c579ef51Seric if (clever) 611c579ef51Seric { 612c579ef51Seric (void) close(rpvect[0]); 613c579ef51Seric (void) close(rpvect[1]); 614c579ef51Seric } 61525a99e2eSeric return (-1); 61625a99e2eSeric } 61725a99e2eSeric else if (pid == 0) 61825a99e2eSeric { 61925a99e2eSeric /* child -- set up input & exec mailer */ 62003ab8e55Seric /* make diagnostic output be standard output */ 6218f0e7860Seric (void) signal(SIGINT, SIG_IGN); 6228f0e7860Seric (void) signal(SIGHUP, SIG_IGN); 6230984da9fSeric (void) signal(SIGTERM, SIG_DFL); 624f8952a83Seric 625f8952a83Seric /* arrange to filter standard & diag output of command */ 626c579ef51Seric if (clever) 627c579ef51Seric { 628c579ef51Seric (void) close(rpvect[0]); 629c579ef51Seric (void) close(1); 630c579ef51Seric (void) dup(rpvect[1]); 631c579ef51Seric (void) close(rpvect[1]); 632c579ef51Seric } 633c579ef51Seric else if (OutChannel != stdout) 634f8952a83Seric { 635f8952a83Seric (void) close(1); 636f8952a83Seric (void) dup(fileno(OutChannel)); 637f8952a83Seric } 638db8841e9Seric (void) close(2); 639db8841e9Seric (void) dup(1); 640f8952a83Seric 641f8952a83Seric /* arrange to get standard input */ 642f8952a83Seric (void) close(mpvect[1]); 643db8841e9Seric (void) close(0); 644f8952a83Seric if (dup(mpvect[0]) < 0) 64525a99e2eSeric { 64625a99e2eSeric syserr("Cannot dup to zero!"); 647a590b978Seric _exit(EX_OSERR); 64825a99e2eSeric } 649f8952a83Seric (void) close(mpvect[0]); 6502a6e0786Seric if (!bitset(M_RESTR, m->m_flags)) 6510984da9fSeric { 652e36b99e2Seric if (ctladdr->q_uid == 0) 653e36b99e2Seric { 65469f29479Seric extern int DefUid, DefGid; 65569f29479Seric 656e36b99e2Seric (void) setgid(DefGid); 657e36b99e2Seric (void) setuid(DefUid); 658e36b99e2Seric } 659e36b99e2Seric else 66069f29479Seric { 661e36b99e2Seric (void) setgid(ctladdr->q_gid); 662e36b99e2Seric (void) setuid(ctladdr->q_uid); 66369f29479Seric } 6640984da9fSeric } 665e374fd72Seric # ifndef VFORK 666e374fd72Seric /* 667e374fd72Seric ** We have to be careful with vfork - we can't mung up the 668e374fd72Seric ** memory but we don't want the mailer to inherit any extra 669e374fd72Seric ** open files. Chances are the mailer won't 670e374fd72Seric ** care about an extra file, but then again you never know. 671e374fd72Seric ** Actually, we would like to close(fileno(pwf)), but it's 672e374fd72Seric ** declared static so we can't. But if we fclose(pwf), which 673e374fd72Seric ** is what endpwent does, it closes it in the parent too and 674e374fd72Seric ** the next getpwnam will be slower. If you have a weird 675e374fd72Seric ** mailer that chokes on the extra file you should do the 676e374fd72Seric ** endpwent(). 677e374fd72Seric ** 678e374fd72Seric ** Similar comments apply to log. However, openlog is 679e374fd72Seric ** clever enough to set the FIOCLEX mode on the file, 680e374fd72Seric ** so it will be closed automatically on the exec. 681e374fd72Seric */ 682e374fd72Seric 683e374fd72Seric endpwent(); 68425a99e2eSeric # ifdef LOG 685f9fe028fSeric closelog(); 68625a99e2eSeric # endif LOG 687e374fd72Seric # endif VFORK 68825a99e2eSeric execv(m->m_mailer, pvp); 68925a99e2eSeric /* syserr fails because log is closed */ 69025a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 69132d19d43Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 692db8841e9Seric (void) fflush(stdout); 693a590b978Seric _exit(EX_UNAVAILABLE); 69425a99e2eSeric } 69525a99e2eSeric 696f8952a83Seric /* 697c579ef51Seric ** Set up return value. 698f8952a83Seric */ 699f8952a83Seric 700f8952a83Seric (void) close(mpvect[0]); 701f8952a83Seric mfile = fdopen(mpvect[1], "w"); 702c579ef51Seric if (clever) 70325a99e2eSeric { 704c579ef51Seric (void) close(rpvect[1]); 705c579ef51Seric rfile = fdopen(rpvect[0], "r"); 70625a99e2eSeric } 707c579ef51Seric 708c579ef51Seric *pmfile = mfile; 709c579ef51Seric *prfile = rfile; 710c579ef51Seric 711c579ef51Seric return (pid); 71225a99e2eSeric } 71325a99e2eSeric /* 71425a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 71525a99e2eSeric ** 71625a99e2eSeric ** Parameters: 71725a99e2eSeric ** stat -- the status code from the mailer (high byte 71825a99e2eSeric ** only; core dumps must have been taken care of 71925a99e2eSeric ** already). 72025a99e2eSeric ** force -- if set, force an error message output, even 72125a99e2eSeric ** if the mailer seems to like to print its own 72225a99e2eSeric ** messages. 72325a99e2eSeric ** m -- the mailer descriptor for this mailer. 72425a99e2eSeric ** 72525a99e2eSeric ** Returns: 726db8841e9Seric ** none. 72725a99e2eSeric ** 72825a99e2eSeric ** Side Effects: 729c1f9df2cSeric ** Errors may be incremented. 73025a99e2eSeric ** ExitStat may be set. 73125a99e2eSeric */ 73225a99e2eSeric 73325a99e2eSeric giveresponse(stat, force, m) 73425a99e2eSeric int stat; 73525a99e2eSeric int force; 73625a99e2eSeric register struct mailer *m; 73725a99e2eSeric { 73825a99e2eSeric register char *statmsg; 73925a99e2eSeric extern char *SysExMsg[]; 74025a99e2eSeric register int i; 74125a99e2eSeric extern int N_SysEx; 74229dd97a3Seric char buf[30]; 74325a99e2eSeric 74413bbc08cSeric /* 74513bbc08cSeric ** Compute status message from code. 74613bbc08cSeric */ 74713bbc08cSeric 74825a99e2eSeric i = stat - EX__BASE; 74925a99e2eSeric if (i < 0 || i > N_SysEx) 75025a99e2eSeric statmsg = NULL; 75125a99e2eSeric else 75225a99e2eSeric statmsg = SysExMsg[i]; 75325a99e2eSeric if (stat == 0) 754c38ba59cSeric { 7556cbfa739Seric if (bitset(M_LOCAL, m->m_flags)) 7563efaed6eSeric statmsg = "delivered"; 7573efaed6eSeric else 7583efaed6eSeric statmsg = "queued"; 759c38ba59cSeric if (Verbose) 760544026c5Seric message(Arpa_Info, statmsg); 761c38ba59cSeric } 7622c7e1b8dSeric # ifdef QUEUE 763c77d1c25Seric else if (stat == EX_TEMPFAIL) 764c77d1c25Seric { 765c77d1c25Seric if (Verbose) 766c77d1c25Seric message(Arpa_Info, "transmission deferred"); 767c77d1c25Seric } 7682c7e1b8dSeric # endif QUEUE 76925a99e2eSeric else 77025a99e2eSeric { 771c1f9df2cSeric Errors++; 77225a99e2eSeric if (statmsg == NULL && m->m_badstat != 0) 77325a99e2eSeric { 77425a99e2eSeric stat = m->m_badstat; 77525a99e2eSeric i = stat - EX__BASE; 77625a99e2eSeric # ifdef DEBUG 77725a99e2eSeric if (i < 0 || i >= N_SysEx) 77825a99e2eSeric syserr("Bad m_badstat %d", stat); 77925a99e2eSeric else 78025a99e2eSeric # endif DEBUG 78125a99e2eSeric statmsg = SysExMsg[i]; 78225a99e2eSeric } 78325a99e2eSeric if (statmsg == NULL) 78425a99e2eSeric usrerr("unknown mailer response %d", stat); 785c38ba59cSeric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 78625a99e2eSeric usrerr("%s", statmsg); 78725a99e2eSeric } 78825a99e2eSeric 78925a99e2eSeric /* 79025a99e2eSeric ** Final cleanup. 79125a99e2eSeric ** Log a record of the transaction. Compute the new 79225a99e2eSeric ** ExitStat -- if we already had an error, stick with 79325a99e2eSeric ** that. 79425a99e2eSeric */ 79525a99e2eSeric 79625a99e2eSeric if (statmsg == NULL) 79729dd97a3Seric { 798db8841e9Seric (void) sprintf(buf, "error %d", stat); 79929dd97a3Seric statmsg = buf; 80029dd97a3Seric } 80129dd97a3Seric 80229dd97a3Seric # ifdef LOG 803e374fd72Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 80425a99e2eSeric # endif LOG 8052c7e1b8dSeric # ifdef QUEUE 806c77d1c25Seric if (stat != EX_TEMPFAIL) 8072c7e1b8dSeric # endif QUEUE 808243921eeSeric setstat(stat); 80925a99e2eSeric } 81025a99e2eSeric /* 8116328bdf7Seric ** PUTMESSAGE -- output a message to the final mailer. 81225a99e2eSeric ** 8136328bdf7Seric ** This routine takes care of recreating the header from the 8146328bdf7Seric ** in-core copy, etc. 81525a99e2eSeric ** 81625a99e2eSeric ** Parameters: 8176328bdf7Seric ** fp -- file to output onto. 8186328bdf7Seric ** m -- a mailer descriptor. 819c579ef51Seric ** xdot -- if set, hide lines beginning with dot. 82025a99e2eSeric ** 82125a99e2eSeric ** Returns: 8226328bdf7Seric ** none. 82325a99e2eSeric ** 82425a99e2eSeric ** Side Effects: 8256328bdf7Seric ** The message is written onto fp. 82625a99e2eSeric */ 82725a99e2eSeric 828c579ef51Seric putmessage(fp, m, xdot) 8296328bdf7Seric FILE *fp; 8306328bdf7Seric struct mailer *m; 831c579ef51Seric bool xdot; 83225a99e2eSeric { 8336328bdf7Seric char buf[BUFSIZ]; 83413bbc08cSeric register HDR *h; 8356328bdf7Seric extern char *arpadate(); 8366328bdf7Seric bool anyheader = FALSE; 837e9ff65b0Seric extern char *capitalize(); 83887bd9a02Seric extern char *hvalue(); 83987bd9a02Seric extern bool samefrom(); 840894de7daSeric char *of_line; 84125a99e2eSeric 84213bbc08cSeric /* 84313bbc08cSeric ** Output "From" line unless supressed 844a36e30c9Seric ** 845a36e30c9Seric ** >>>>>>>>>> One of the ugliest hacks seen by human eyes is 846a36e30c9Seric ** >>>>>>>>>> contained herein: UUCP wants those stupid 847bba2edb3Seric ** >>>>>>>>>> "remote from <host>" lines. Why oh why does a 848bba2edb3Seric ** >> NOTE >> well-meaning programmer such as myself have to 849a36e30c9Seric ** >>>>>>>>>> deal with this kind of antique garbage???? 850bba2edb3Seric ** >>>>>>>>>> This even depends on the local UUCP host name 851bba2edb3Seric ** >>>>>>>>>> being in the $U macro!!!! 85213bbc08cSeric */ 85313bbc08cSeric 85440e4ab56Seric if (!bitset(M_NHDR, m->m_flags)) 8551412cc7cSeric { 8562c7e1b8dSeric # ifdef UGLYUUCP 8572c7e1b8dSeric char *p = rindex(m->m_mailer, '/'); 85862667331Seric 859*a49f24c0Seric if (bitset(M_UGLYUUCP, m->m_flags)) 860bba2edb3Seric (void) expand("From $f $d remote from $U", buf, 861a36e30c9Seric &buf[sizeof buf - 1]); 862a36e30c9Seric else 8632c7e1b8dSeric # endif UGLYUUCP 8641412cc7cSeric (void) expand("$l", buf, &buf[sizeof buf - 1]); 8651412cc7cSeric fprintf(fp, "%s\n", buf); 8661412cc7cSeric } 86740e4ab56Seric 86813bbc08cSeric /* 86913bbc08cSeric ** Output all header lines 87013bbc08cSeric */ 87113bbc08cSeric 872894de7daSeric of_line = hvalue("original-from"); 8736328bdf7Seric for (h = Header; h != NULL; h = h->h_link) 8746328bdf7Seric { 87513bbc08cSeric register char *p; 87687bd9a02Seric char *origfrom = OrigFrom; 877894de7daSeric bool nooutput; 87813bbc08cSeric 879894de7daSeric nooutput = FALSE; 8809e9163a0Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 8815a0dcb5fSeric { 8825a0dcb5fSeric p = ")><("; /* can't happen (I hope) */ 883894de7daSeric nooutput = TRUE; 8845a0dcb5fSeric } 885894de7daSeric 886894de7daSeric /* use From: line from message if generated is the same */ 88787bd9a02Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 888894de7daSeric strcmp(m->m_from, "$f") == 0 && of_line == NULL) 88987bd9a02Seric { 89087bd9a02Seric p = origfrom; 89187bd9a02Seric origfrom = NULL; 89287bd9a02Seric } 89387bd9a02Seric else if (bitset(H_DEFAULT, h->h_flags)) 8944ae18d0eSeric { 895db8841e9Seric (void) expand(h->h_value, buf, &buf[sizeof buf]); 8964ae18d0eSeric p = buf; 8974ae18d0eSeric } 8984ae18d0eSeric else 8994ae18d0eSeric p = h->h_value; 900894de7daSeric if (p == NULL || *p == '\0') 9019e9163a0Seric continue; 9025a0dcb5fSeric 9035a0dcb5fSeric /* hack, hack -- output Original-From field if different */ 904894de7daSeric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL) 905894de7daSeric { 906894de7daSeric /* output new Original-From line if needed */ 907894de7daSeric if (of_line == NULL && !samefrom(p, origfrom)) 9085a0dcb5fSeric { 90987bd9a02Seric fprintf(fp, "Original-From: %s\n", origfrom); 91087bd9a02Seric anyheader = TRUE; 9115a0dcb5fSeric } 912894de7daSeric if (of_line != NULL && !nooutput && samefrom(p, of_line)) 913894de7daSeric { 914894de7daSeric /* delete Original-From: line if redundant */ 915894de7daSeric p = of_line; 916894de7daSeric of_line = NULL; 917894de7daSeric } 918894de7daSeric } 919894de7daSeric else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL) 920894de7daSeric nooutput = TRUE; 921894de7daSeric 922894de7daSeric /* finally, output the header line */ 923894de7daSeric if (!nooutput) 924894de7daSeric { 925894de7daSeric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 926894de7daSeric h->h_flags |= H_USED; 927894de7daSeric anyheader = TRUE; 928894de7daSeric } 9296328bdf7Seric } 9306328bdf7Seric if (anyheader) 9316328bdf7Seric fprintf(fp, "\n"); 9326328bdf7Seric 93313bbc08cSeric /* 93413bbc08cSeric ** Output the body of the message 93513bbc08cSeric */ 93613bbc08cSeric 93778442df3Seric if (TempFile != NULL) 93878442df3Seric { 939b7902a1dSeric rewind(TempFile); 940c579ef51Seric while (!ferror(fp) && fgets(buf, sizeof buf, TempFile) != NULL) 941c579ef51Seric fprintf(fp, "%s%s", xdot && buf[0] == '.' ? "." : "", buf); 9426328bdf7Seric 94378442df3Seric if (ferror(TempFile)) 94478442df3Seric { 94578442df3Seric syserr("putmessage: read error"); 94678442df3Seric setstat(EX_IOERR); 94778442df3Seric } 94878442df3Seric } 94978442df3Seric 950c77d1c25Seric (void) fflush(fp); 95154aa2b0fSeric if (ferror(fp) && errno != EPIPE) 95225a99e2eSeric { 9536328bdf7Seric syserr("putmessage: write error"); 95425a99e2eSeric setstat(EX_IOERR); 95525a99e2eSeric } 95654aa2b0fSeric errno = 0; 95725a99e2eSeric } 95825a99e2eSeric /* 95987bd9a02Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 96087bd9a02Seric ** 96187bd9a02Seric ** Parameters: 96287bd9a02Seric ** ifrom -- internally generated form of from address. 96387bd9a02Seric ** efrom -- external form of from address. 96487bd9a02Seric ** 96587bd9a02Seric ** Returns: 96687bd9a02Seric ** TRUE -- if they convey the same info. 96787bd9a02Seric ** FALSE -- if any information has been lost. 96887bd9a02Seric ** 96987bd9a02Seric ** Side Effects: 97087bd9a02Seric ** none. 97187bd9a02Seric */ 97287bd9a02Seric 97387bd9a02Seric bool 97487bd9a02Seric samefrom(ifrom, efrom) 97587bd9a02Seric char *ifrom; 97687bd9a02Seric char *efrom; 97787bd9a02Seric { 978894de7daSeric register char *p; 979894de7daSeric char buf[MAXNAME + 4]; 980894de7daSeric 981894de7daSeric # ifdef DEBUG 982894de7daSeric if (Debug > 7) 983894de7daSeric printf("samefrom(%s,%s)-->", ifrom, efrom); 984894de7daSeric # endif DEBUG 985894de7daSeric if (strcmp(ifrom, efrom) == 0) 986894de7daSeric goto success; 987894de7daSeric p = index(ifrom, '@'); 988894de7daSeric if (p == NULL) 989894de7daSeric goto failure; 990894de7daSeric *p = '\0'; 991894de7daSeric strcpy(buf, ifrom); 992894de7daSeric strcat(buf, " at "); 993894de7daSeric *p++ = '@'; 994894de7daSeric strcat(buf, p); 995894de7daSeric if (strcmp(buf, efrom) == 0) 996894de7daSeric goto success; 997894de7daSeric 998894de7daSeric failure: 999894de7daSeric # ifdef DEBUG 1000894de7daSeric if (Debug > 7) 1001894de7daSeric printf("FALSE\n"); 1002894de7daSeric # endif DEBUG 1003894de7daSeric return (FALSE); 1004894de7daSeric 1005894de7daSeric success: 1006894de7daSeric # ifdef DEBUG 1007894de7daSeric if (Debug > 7) 1008894de7daSeric printf("TRUE\n"); 1009894de7daSeric # endif DEBUG 1010894de7daSeric return (TRUE); 101187bd9a02Seric } 101287bd9a02Seric /* 101325a99e2eSeric ** MAILFILE -- Send a message to a file. 101425a99e2eSeric ** 1015f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 1016f129ec7dSeric ** bits, sendmail will try to become the owner of that file 1017f129ec7dSeric ** rather than the real user. Obviously, this only works if 1018f129ec7dSeric ** sendmail runs as root. 1019f129ec7dSeric ** 102025a99e2eSeric ** Parameters: 102125a99e2eSeric ** filename -- the name of the file to send to. 10226259796dSeric ** ctladdr -- the controlling address header -- includes 10236259796dSeric ** the userid/groupid to be when sending. 102425a99e2eSeric ** 102525a99e2eSeric ** Returns: 102625a99e2eSeric ** The exit code associated with the operation. 102725a99e2eSeric ** 102825a99e2eSeric ** Side Effects: 102925a99e2eSeric ** none. 103025a99e2eSeric */ 103125a99e2eSeric 10326259796dSeric mailfile(filename, ctladdr) 103325a99e2eSeric char *filename; 10346259796dSeric ADDRESS *ctladdr; 103525a99e2eSeric { 103625a99e2eSeric register FILE *f; 103732d19d43Seric register int pid; 103825a99e2eSeric 103932d19d43Seric /* 104032d19d43Seric ** Fork so we can change permissions here. 104132d19d43Seric ** Note that we MUST use fork, not vfork, because of 104232d19d43Seric ** the complications of calling subroutines, etc. 104332d19d43Seric */ 104432d19d43Seric 104532d19d43Seric DOFORK(fork); 104632d19d43Seric 104732d19d43Seric if (pid < 0) 104832d19d43Seric return (EX_OSERR); 104932d19d43Seric else if (pid == 0) 105032d19d43Seric { 105132d19d43Seric /* child -- actually write to file */ 1052f129ec7dSeric struct stat stb; 1053e36b99e2Seric extern int DefUid, DefGid; 1054f129ec7dSeric 10550984da9fSeric (void) signal(SIGINT, SIG_DFL); 10560984da9fSeric (void) signal(SIGHUP, SIG_DFL); 10570984da9fSeric (void) signal(SIGTERM, SIG_DFL); 1058f129ec7dSeric umask(OldUmask); 1059f129ec7dSeric if (stat(filename, &stb) < 0) 1060e6e1265fSeric stb.st_mode = 0666; 1061f129ec7dSeric if (bitset(0111, stb.st_mode)) 1062f129ec7dSeric exit(EX_CANTCREAT); 106303827b5fSeric if (ctladdr == NULL) 106403827b5fSeric ctladdr = &From; 1065f129ec7dSeric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 1066e36b99e2Seric { 1067e36b99e2Seric if (ctladdr->q_uid == 0) 1068e36b99e2Seric (void) setgid(DefGid); 1069e36b99e2Seric else 10706259796dSeric (void) setgid(ctladdr->q_gid); 1071e36b99e2Seric } 1072f129ec7dSeric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 1073e36b99e2Seric { 1074e36b99e2Seric if (ctladdr->q_uid == 0) 1075e36b99e2Seric (void) setuid(DefUid); 1076e36b99e2Seric else 10776259796dSeric (void) setuid(ctladdr->q_uid); 1078e36b99e2Seric } 107925a99e2eSeric f = fopen(filename, "a"); 108025a99e2eSeric if (f == NULL) 108132d19d43Seric exit(EX_CANTCREAT); 108225a99e2eSeric 1083c579ef51Seric putmessage(f, Mailer[1], FALSE); 108425a99e2eSeric fputs("\n", f); 1085db8841e9Seric (void) fclose(f); 108632d19d43Seric (void) fflush(stdout); 1087e36b99e2Seric 1088e36b99e2Seric /* reset ISUID & ISGID bits */ 1089c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 109032d19d43Seric exit(EX_OK); 109113bbc08cSeric /*NOTREACHED*/ 109232d19d43Seric } 109332d19d43Seric else 109432d19d43Seric { 109532d19d43Seric /* parent -- wait for exit status */ 109632d19d43Seric register int i; 109732d19d43Seric auto int stat; 109832d19d43Seric 109932d19d43Seric while ((i = wait(&stat)) != pid) 110032d19d43Seric { 110132d19d43Seric if (i < 0) 110232d19d43Seric { 110332d19d43Seric stat = EX_OSERR << 8; 110432d19d43Seric break; 110532d19d43Seric } 110632d19d43Seric } 11070984da9fSeric if ((stat & 0377) != 0) 11080984da9fSeric stat = EX_UNAVAILABLE << 8; 110932d19d43Seric return ((stat >> 8) & 0377); 111032d19d43Seric } 111125a99e2eSeric } 1112ea4dc939Seric /* 1113ea4dc939Seric ** SENDALL -- actually send all the messages. 1114ea4dc939Seric ** 1115ea4dc939Seric ** Parameters: 1116ea4dc939Seric ** verifyonly -- if set, only give verification messages. 1117ea4dc939Seric ** 1118ea4dc939Seric ** Returns: 1119ea4dc939Seric ** none. 1120ea4dc939Seric ** 1121ea4dc939Seric ** Side Effects: 1122ea4dc939Seric ** Scans the send lists and sends everything it finds. 1123ea4dc939Seric */ 1124ea4dc939Seric 1125ea4dc939Seric sendall(verifyonly) 1126ea4dc939Seric bool verifyonly; 1127ea4dc939Seric { 1128e77e673fSeric register ADDRESS *q; 1129ea4dc939Seric typedef int (*fnptr)(); 1130ea4dc939Seric 1131772e6e50Seric # ifdef DEBUG 1132772e6e50Seric if (Debug > 1) 1133772e6e50Seric { 1134772e6e50Seric printf("\nSendQueue:\n"); 1135772e6e50Seric printaddr(SendQueue, TRUE); 1136772e6e50Seric } 1137772e6e50Seric # endif DEBUG 1138ea4dc939Seric 1139e77e673fSeric for (q = SendQueue; q != NULL; q = q->q_next) 1140ea4dc939Seric { 1141ea4dc939Seric if (verifyonly) 1142ea4dc939Seric { 1143ea4dc939Seric To = q->q_paddr; 1144e77e673fSeric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 1145ea4dc939Seric { 11467da1035fSeric if (bitset(M_LOCAL, q->q_mailer->m_flags)) 1147ea4dc939Seric message(Arpa_Info, "deliverable"); 1148ea4dc939Seric else 1149ea4dc939Seric message(Arpa_Info, "queueable"); 1150ea4dc939Seric } 1151ea4dc939Seric } 1152ea4dc939Seric else 1153ea4dc939Seric (void) deliver(q, (fnptr) NULL); 1154ea4dc939Seric } 1155ea4dc939Seric } 1156