1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*8248Seric SCCSID(@(#)deliver.c 3.116 09/24/82); 7405Seric 8294Seric /* 94315Seric ** DELIVER -- Deliver a message to a list of addresses. 10294Seric ** 114315Seric ** This routine delivers to everyone on the same host as the 124315Seric ** user on the head of the list. It is clever about mailers 134315Seric ** that don't handle multiple users. It is NOT guaranteed 144315Seric ** that it will deliver to all these addresses however -- so 154315Seric ** deliver should be called once for each address on the 164315Seric ** list. 174315Seric ** 18294Seric ** Parameters: 194621Seric ** firstto -- head of the address list to deliver to. 20294Seric ** 21294Seric ** Returns: 22294Seric ** zero -- successfully delivered. 23294Seric ** else -- some failure, see ExitStat for more info. 24294Seric ** 25294Seric ** Side Effects: 26294Seric ** The standard input is passed off to someone. 27294Seric */ 28294Seric 296974Seric deliver(firstto) 304621Seric ADDRESS *firstto; 31294Seric { 324452Seric char *host; /* host being sent to */ 334452Seric char *user; /* user being sent to */ 34294Seric char **pvp; 353233Seric register char **mvp; 363233Seric register char *p; 374452Seric register struct mailer *m; /* mailer for this recipient */ 382968Seric extern bool checkcompat(); 393233Seric char *pv[MAXPV+1]; 408225Seric char tobuf[MAXLINE-50]; /* text line of to people */ 413233Seric char buf[MAXNAME]; 424397Seric ADDRESS *ctladdr; 434397Seric extern ADDRESS *getctladdr(); 444452Seric char tfrombuf[MAXNAME]; /* translated from person */ 454452Seric extern char **prescan(); 464621Seric register ADDRESS *to = firstto; 474863Seric bool clever = FALSE; /* running user smtp to this mailer */ 485032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 497052Seric bool notopen = TRUE; /* set if connection not quite open */ 508003Seric register int rcode; /* response code */ 51294Seric 524488Seric errno = 0; 537052Seric if (bitset(QDONTSEND, to->q_flags)) 543233Seric return (0); 55294Seric 566974Seric m = to->q_mailer; 576974Seric host = to->q_host; 586974Seric 59294Seric # ifdef DEBUG 607672Seric if (tTd(10, 1)) 613233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 626974Seric m->m_mno, host, to->q_user); 63294Seric # endif DEBUG 64294Seric 65294Seric /* 665903Seric ** If this mailer is expensive, and if we don't want to make 675903Seric ** connections now, just mark these addresses and return. 685903Seric ** This is useful if we want to batch connections to 695903Seric ** reduce load. This will cause the messages to be 705903Seric ** queued up, and a daemon will come along to send the 715903Seric ** messages later. 725903Seric ** This should be on a per-mailer basis. 735903Seric */ 745903Seric 755903Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags)) 765903Seric { 775903Seric for (; to != NULL; to = to->q_next) 787875Seric if (!bitset(QDONTSEND, to->q_flags) && 797875Seric to->q_mailer == firstto->q_mailer) 805903Seric to->q_flags |= QQUEUEUP|QDONTSEND; 815903Seric return (0); 825903Seric } 835903Seric 845903Seric /* 853233Seric ** Do initial argv setup. 863233Seric ** Insert the mailer name. Notice that $x expansion is 873233Seric ** NOT done on the mailer name. Then, if the mailer has 883233Seric ** a picky -f flag, we insert it as appropriate. This 893233Seric ** code does not check for 'pv' overflow; this places a 903233Seric ** manifest lower limit of 4 for MAXPV. 918062Seric ** The from address rewrite is expected to make 928062Seric ** the address relative to the other end. 932968Seric */ 942968Seric 954452Seric /* rewrite from address, using rewriting rules */ 968062Seric expand("$f", buf, &buf[sizeof buf - 1], CurEnv); 974452Seric mvp = prescan(buf, '\0'); 988062Seric rewrite(mvp, m->m_s_rwset); 994452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 1004452Seric 1014452Seric define('g', tfrombuf); /* translated sender address */ 1023233Seric define('h', host); /* to host */ 1033233Seric Errors = 0; 1043233Seric pvp = pv; 1053233Seric *pvp++ = m->m_argv[0]; 1062968Seric 1073233Seric /* insert -f or -r flag as appropriate */ 1083233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1093233Seric { 1103233Seric if (bitset(M_FOPT, m->m_flags)) 1113233Seric *pvp++ = "-f"; 1123233Seric else 1133233Seric *pvp++ = "-r"; 1146974Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1153233Seric *pvp++ = newstr(buf); 1163233Seric } 117294Seric 118294Seric /* 1193233Seric ** Append the other fixed parts of the argv. These run 1203233Seric ** up to the first entry containing "$u". There can only 1213233Seric ** be one of these, and there are only a few more slots 1223233Seric ** in the pv after it. 123294Seric */ 124294Seric 1253233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 126294Seric { 1273233Seric while ((p = index(p, '$')) != NULL) 1283233Seric if (*++p == 'u') 1293233Seric break; 1303233Seric if (p != NULL) 1313233Seric break; 1323233Seric 1333233Seric /* this entry is safe -- go ahead and process it */ 1346974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 1353233Seric *pvp++ = newstr(buf); 1363233Seric if (pvp >= &pv[MAXPV - 3]) 1373233Seric { 1383233Seric syserr("Too many parameters to %s before $u", pv[0]); 1393233Seric return (-1); 1403233Seric } 141294Seric } 1424863Seric 1436038Seric /* 1446038Seric ** If we have no substitution for the user name in the argument 1456038Seric ** list, we know that we must supply the names otherwise -- and 1466038Seric ** SMTP is the answer!! 1476038Seric */ 1486038Seric 1493233Seric if (*mvp == NULL) 1504863Seric { 1514863Seric /* running SMTP */ 1525179Seric # ifdef SMTP 1534863Seric clever = TRUE; 1544863Seric *pvp = NULL; 1555179Seric # else SMTP 1566038Seric /* oops! we don't implement SMTP */ 1575179Seric syserr("SMTP style mailer"); 1585179Seric return (EX_SOFTWARE); 1595179Seric # endif SMTP 1604863Seric } 161294Seric 162294Seric /* 1633233Seric ** At this point *mvp points to the argument with $u. We 1643233Seric ** run through our address list and append all the addresses 1653233Seric ** we can. If we run out of space, do not fret! We can 1663233Seric ** always send another copy later. 167294Seric */ 168294Seric 1693233Seric tobuf[0] = '\0'; 1706900Seric CurEnv->e_to = tobuf; 1714397Seric ctladdr = NULL; 1723233Seric for (; to != NULL; to = to->q_next) 173294Seric { 1743233Seric /* avoid sending multiple recipients to dumb mailers */ 1754382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1763233Seric break; 1773233Seric 1783233Seric /* if already sent or not for this host, don't send */ 1797052Seric if (bitset(QDONTSEND, to->q_flags) || 1807052Seric strcmp(to->q_host, host) != 0 || 1817052Seric to->q_mailer != firstto->q_mailer) 1823233Seric continue; 1834397Seric 1848225Seric /* avoid overflowing tobuf */ 1858225Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 1) < 0) 1868225Seric break; 1878225Seric 1885032Seric # ifdef DEBUG 1897672Seric if (tTd(10, 1)) 1905032Seric { 1915032Seric printf("\nsend to "); 1925032Seric printaddr(to, FALSE); 1935032Seric } 1945032Seric # endif DEBUG 1955032Seric 1964397Seric /* compute effective uid/gid when sending */ 1974596Seric if (to->q_mailer == ProgMailer) 1984397Seric ctladdr = getctladdr(to); 1994397Seric 2003233Seric user = to->q_user; 2016900Seric CurEnv->e_to = to->q_paddr; 2023233Seric to->q_flags |= QDONTSEND; 2033233Seric 2043233Seric /* 2053233Seric ** Check to see that these people are allowed to 2063233Seric ** talk to each other. 2073233Seric */ 2083233Seric 2093233Seric if (!checkcompat(to)) 210294Seric { 2113233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 2123233Seric continue; 213294Seric } 2143233Seric 2153233Seric /* 2164099Seric ** Strip quote bits from names if the mailer is dumb 2174099Seric ** about them. 2183233Seric */ 2193233Seric 2203233Seric if (bitset(M_STRIPQ, m->m_flags)) 221294Seric { 2224099Seric stripquotes(user, TRUE); 2234099Seric stripquotes(host, TRUE); 2243233Seric } 2254099Seric else 2264099Seric { 2274099Seric stripquotes(user, FALSE); 2284099Seric stripquotes(host, FALSE); 2294099Seric } 2303233Seric 2313233Seric /* 2327052Seric ** Do initial connection setup if needed. 2337052Seric */ 2347052Seric 2357052Seric if (notopen) 2367052Seric { 2377052Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 2387052Seric # ifdef SMTP 2397052Seric if (clever) 2407052Seric { 2417052Seric /* send the initial SMTP protocol */ 2428003Seric rcode = smtpinit(m, pv, (ADDRESS *) NULL); 2437052Seric } 2447052Seric # ifdef SMTP 2457052Seric notopen = FALSE; 2467052Seric } 2477052Seric 2487052Seric /* 2496059Seric ** Pass it to the other host if we are running SMTP. 2506059Seric */ 2516059Seric 2526059Seric if (clever) 2536059Seric { 2546059Seric # ifdef SMTP 2558003Seric if (rcode == EX_OK) 2568003Seric rcode = smtprcpt(to); 2578003Seric if (rcode != EX_OK) 2586059Seric { 2598003Seric if (rcode == EX_TEMPFAIL) 2606059Seric to->q_flags |= QQUEUEUP; 2616059Seric else 2626059Seric to->q_flags |= QBADADDR; 2638003Seric giveresponse(rcode, TRUE, m); 2646059Seric } 2656059Seric # else SMTP 2666059Seric syserr("trying to be clever"); 2676059Seric # endif SMTP 2686059Seric } 2696059Seric 2706059Seric /* 2714161Seric ** If an error message has already been given, don't 2724161Seric ** bother to send to this address. 2734161Seric ** 2744161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2754161Seric ** >> NOTE >> cannot do any further aliasing; that 2764161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2774161Seric */ 2784161Seric 2797293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2804161Seric continue; 2814161Seric 2824283Seric /* save statistics.... */ 2834596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2846900Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(CurEnv->e_msgsize); 2854283Seric 2864161Seric /* 2873233Seric ** See if this user name is "special". 2883233Seric ** If the user name has a slash in it, assume that this 2896974Seric ** is a file -- send it off without further ado. Note 2906974Seric ** that this type of addresses is not processed along 2916974Seric ** with the others, so we fudge on the To person. 2923233Seric */ 2933233Seric 2944596Seric if (m == LocalMailer) 2953233Seric { 2965599Seric if (user[0] == '/') 297294Seric { 2988003Seric rcode = mailfile(user, getctladdr(to)); 2998003Seric giveresponse(rcode, TRUE, m); 3003233Seric continue; 301294Seric } 302294Seric } 3033233Seric 3044315Seric /* 3054315Seric ** Address is verified -- add this user to mailer 3064315Seric ** argv, and add it to the print list of recipients. 3074315Seric */ 3084315Seric 3096059Seric /* link together the chain of recipients */ 3106272Seric to->q_tchain = tochain; 3116272Seric tochain = to; 3126059Seric 3133233Seric /* create list of users for error messages */ 3143233Seric if (tobuf[0] != '\0') 3154082Seric (void) strcat(tobuf, ","); 3164082Seric (void) strcat(tobuf, to->q_paddr); 3173233Seric define('u', user); /* to user */ 3184078Seric define('z', to->q_home); /* user's home */ 3193233Seric 3204863Seric /* 3216059Seric ** Expand out this user into argument list. 3224863Seric */ 3234863Seric 3246059Seric if (!clever) 3253233Seric { 3266974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3274863Seric *pvp++ = newstr(buf); 3284863Seric if (pvp >= &pv[MAXPV - 2]) 3294863Seric { 3304863Seric /* allow some space for trailing parms */ 3314863Seric break; 3324863Seric } 3334863Seric } 334294Seric } 335294Seric 3364067Seric /* see if any addresses still exist */ 3374067Seric if (tobuf[0] == '\0') 3384863Seric { 3395179Seric # ifdef SMTP 3404863Seric if (clever) 3417228Seric smtpquit(pv[0], FALSE); 3425179Seric # endif SMTP 3437003Seric define('g', (char *) NULL); 3444067Seric return (0); 3454863Seric } 3464067Seric 3473233Seric /* print out messages as full list */ 3486900Seric CurEnv->e_to = tobuf; 3493233Seric 350294Seric /* 3513233Seric ** Fill out any parameters after the $u parameter. 352294Seric */ 353294Seric 3544863Seric while (!clever && *++mvp != NULL) 355294Seric { 3566974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3573233Seric *pvp++ = newstr(buf); 3583233Seric if (pvp >= &pv[MAXPV]) 3593233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 360294Seric } 3613233Seric *pvp++ = NULL; 362294Seric 363294Seric /* 364294Seric ** Call the mailer. 3652898Seric ** The argument vector gets built, pipes 366294Seric ** are created as necessary, and we fork & exec as 3672898Seric ** appropriate. 3684863Seric ** If we are running SMTP, we just need to clean up. 369294Seric */ 370294Seric 3714397Seric if (ctladdr == NULL) 3726900Seric ctladdr = &CurEnv->e_from; 3735179Seric # ifdef SMTP 3744863Seric if (clever) 3754863Seric { 3768003Seric rcode = smtpfinish(m, CurEnv); 3778003Seric if (rcode != EX_OK) 3788003Seric giveresponse(rcode, TRUE, m); 3798003Seric smtpquit(pv[0], rcode == EX_OK); 3804863Seric } 3814863Seric else 3825179Seric # endif SMTP 3838003Seric rcode = sendoff(m, pv, ctladdr); 3843233Seric 3854621Seric /* 3864621Seric ** If we got a temporary failure, arrange to queue the 3874621Seric ** addressees. 3884621Seric */ 3894621Seric 3908003Seric if (rcode == EX_TEMPFAIL) 3914621Seric { 3925032Seric for (to = tochain; to != NULL; to = to->q_tchain) 3934621Seric to->q_flags |= QQUEUEUP; 3944621Seric } 3954621Seric 3964488Seric errno = 0; 3977003Seric define('g', (char *) NULL); 3988003Seric return (rcode); 3993233Seric } 4003233Seric /* 4014214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4024214Seric ** 4034214Seric ** This MUST be a macro, since after a vfork we are running 4044214Seric ** two processes on the same stack!!! 4054214Seric ** 4064214Seric ** Parameters: 4074214Seric ** none. 4084214Seric ** 4094214Seric ** Returns: 4104214Seric ** From a macro??? You've got to be kidding! 4114214Seric ** 4124214Seric ** Side Effects: 4134214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4144214Seric ** pid of child in parent, zero in child. 4154214Seric ** -1 on unrecoverable error. 4164214Seric ** 4174214Seric ** Notes: 4184214Seric ** I'm awfully sorry this looks so awful. That's 4194214Seric ** vfork for you..... 4204214Seric */ 4214214Seric 4224214Seric # define NFORKTRIES 5 4234214Seric # ifdef VFORK 4244214Seric # define XFORK vfork 4254214Seric # else VFORK 4264214Seric # define XFORK fork 4274214Seric # endif VFORK 4284214Seric 4294214Seric # define DOFORK(fORKfN) \ 4304214Seric {\ 4314214Seric register int i;\ 4324214Seric \ 4334214Seric for (i = NFORKTRIES; i-- > 0; )\ 4344214Seric {\ 4354214Seric pid = fORKfN();\ 4364214Seric if (pid >= 0)\ 4374214Seric break;\ 4387003Seric sleep(NFORKTRIES - i);\ 4394214Seric }\ 4404214Seric } 4414214Seric /* 4424637Seric ** DOFORK -- simple fork interface to DOFORK. 4434637Seric ** 4444637Seric ** Parameters: 4454637Seric ** none. 4464637Seric ** 4474637Seric ** Returns: 4484637Seric ** pid of child in parent. 4494637Seric ** zero in child. 4504637Seric ** -1 on error. 4514637Seric ** 4524637Seric ** Side Effects: 4534637Seric ** returns twice, once in parent and once in child. 4544637Seric */ 4554637Seric 4564637Seric dofork() 4574637Seric { 4584637Seric register int pid; 4594637Seric 4604637Seric DOFORK(fork); 4614637Seric return (pid); 4624637Seric } 4634637Seric /* 4643233Seric ** SENDOFF -- send off call to mailer & collect response. 4653233Seric ** 4663233Seric ** Parameters: 4673233Seric ** m -- mailer descriptor. 4683233Seric ** pvp -- parameter vector to send to it. 4694397Seric ** ctladdr -- an address pointer controlling the 4704397Seric ** user/groupid etc. of the mailer. 4713233Seric ** 4723233Seric ** Returns: 4733233Seric ** exit status of mailer. 4743233Seric ** 4753233Seric ** Side Effects: 4763233Seric ** none. 4773233Seric */ 4783233Seric 4796974Seric sendoff(m, pvp, ctladdr) 4803233Seric struct mailer *m; 4813233Seric char **pvp; 4824397Seric ADDRESS *ctladdr; 4833233Seric { 4844863Seric auto FILE *mfile; 4854863Seric auto FILE *rfile; 4863233Seric register int i; 4873233Seric int pid; 4884863Seric 4894863Seric /* 4904863Seric ** Create connection to mailer. 4914863Seric */ 4924863Seric 4934863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 4944863Seric if (pid < 0) 4954863Seric return (-1); 4964863Seric 4974863Seric /* 4984863Seric ** Format and send message. 4994863Seric */ 5004863Seric 5014863Seric (void) signal(SIGPIPE, SIG_IGN); 5026974Seric putfromline(mfile, m); 5036974Seric (*CurEnv->e_puthdr)(mfile, m, CurEnv); 5046974Seric fprintf(mfile, "\n"); 5056974Seric (*CurEnv->e_putbody)(mfile, m, FALSE); 5064863Seric (void) fclose(mfile); 5074863Seric 5084863Seric i = endmailer(pid, pvp[0]); 5094863Seric giveresponse(i, TRUE, m); 5105981Seric 5115981Seric /* arrange a return receipt if requested */ 5128062Seric if (CurEnv->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 5135981Seric { 5146900Seric CurEnv->e_sendreceipt = TRUE; 5158062Seric if (ExitStat == EX_OK) 5168062Seric fprintf(Xscript, "%s... successfully delivered\n", 5178062Seric CurEnv->e_to); 5185981Seric /* do we want to send back more info? */ 5195981Seric } 5205981Seric 5214863Seric return (i); 5224863Seric } 5234863Seric /* 5244863Seric ** ENDMAILER -- Wait for mailer to terminate. 5254863Seric ** 5264863Seric ** We should never get fatal errors (e.g., segmentation 5274863Seric ** violation), so we report those specially. For other 5284863Seric ** errors, we choose a status message (into statmsg), 5294863Seric ** and if it represents an error, we print it. 5304863Seric ** 5314863Seric ** Parameters: 5324863Seric ** pid -- pid of mailer. 5334863Seric ** name -- name of mailer (for error messages). 5344863Seric ** 5354863Seric ** Returns: 5364863Seric ** exit code of mailer. 5374863Seric ** 5384863Seric ** Side Effects: 5394863Seric ** none. 5404863Seric */ 5414863Seric 5424863Seric endmailer(pid, name) 5434863Seric int pid; 5444863Seric char *name; 5454863Seric { 5464863Seric register int i; 5474863Seric auto int st; 5484863Seric 5496038Seric /* in the IPC case there is nothing to wait for */ 5506038Seric if (pid == 0) 5516038Seric return (EX_OK); 5526038Seric 5536038Seric /* wait for the mailer process to die and collect status */ 5548127Seric do 5558127Seric { 5568127Seric errno = 0; 5578127Seric i = wait(&st); 5588133Seric } while ((i >= 0 && i != pid) || errno == EINTR); 5594863Seric if (i < 0) 5604863Seric { 5614863Seric syserr("wait"); 5624863Seric return (-1); 5634863Seric } 5646038Seric 5656038Seric /* see if it died a horrid death */ 5664863Seric if ((st & 0377) != 0) 5674863Seric { 5684863Seric syserr("%s: stat %o", name, st); 5694863Seric ExitStat = EX_UNAVAILABLE; 5704863Seric return (-1); 5714863Seric } 5726038Seric 5736038Seric /* normal death -- return status */ 5744863Seric i = (st >> 8) & 0377; 5754863Seric return (i); 5764863Seric } 5774863Seric /* 5784863Seric ** OPENMAILER -- open connection to mailer. 5794863Seric ** 5804863Seric ** Parameters: 5814863Seric ** m -- mailer descriptor. 5824863Seric ** pvp -- parameter vector to pass to mailer. 5834863Seric ** ctladdr -- controlling address for user. 5844863Seric ** clever -- create a full duplex connection. 5854863Seric ** pmfile -- pointer to mfile (to mailer) connection. 5864863Seric ** prfile -- pointer to rfile (from mailer) connection. 5874863Seric ** 5884863Seric ** Returns: 5896038Seric ** pid of mailer ( > 0 ). 5904863Seric ** -1 on error. 5916038Seric ** zero on an IPC connection. 5924863Seric ** 5934863Seric ** Side Effects: 5944863Seric ** creates a mailer in a subprocess. 5954863Seric */ 5964863Seric 5974863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 5984863Seric struct mailer *m; 5994863Seric char **pvp; 6004863Seric ADDRESS *ctladdr; 6014863Seric bool clever; 6024863Seric FILE **pmfile; 6034863Seric FILE **prfile; 6044863Seric { 6054863Seric int pid; 6064709Seric int mpvect[2]; 6074863Seric int rpvect[2]; 6083233Seric FILE *mfile; 6094863Seric FILE *rfile; 6103233Seric extern FILE *fdopen(); 6113233Seric 6123233Seric # ifdef DEBUG 6137672Seric if (tTd(11, 1)) 614294Seric { 6158178Seric printf("openmailer:"); 6163233Seric printav(pvp); 617294Seric } 6183233Seric # endif DEBUG 6194488Seric errno = 0; 6203233Seric 6216038Seric # ifdef DAEMON 6226038Seric /* 6236038Seric ** Deal with the special case of mail handled through an IPC 6246038Seric ** connection. 6256038Seric ** In this case we don't actually fork. We must be 6266038Seric ** running SMTP for this to work. We will return a 6276038Seric ** zero pid to indicate that we are running IPC. 6286038Seric */ 6296038Seric 6306038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6316038Seric { 6326038Seric register int i; 6337285Seric register u_short port; 6346038Seric 6356038Seric if (!clever) 6366038Seric syserr("non-clever IPC"); 6376632Seric if (pvp[2] != NULL) 6387285Seric port = atoi(pvp[2]); 6396632Seric else 6407285Seric port = 0; 6417285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 6426038Seric if (i != EX_OK) 6436047Seric { 6446047Seric ExitStat = i; 6456038Seric return (-1); 6466047Seric } 6476038Seric else 6486038Seric return (0); 6496038Seric } 6506038Seric # endif DAEMON 6516038Seric 6522898Seric /* create a pipe to shove the mail through */ 6534709Seric if (pipe(mpvect) < 0) 654294Seric { 6554863Seric syserr("pipe (to mailer)"); 656294Seric return (-1); 657294Seric } 6584863Seric 6595179Seric # ifdef SMTP 6604863Seric /* if this mailer speaks smtp, create a return pipe */ 6614863Seric if (clever && pipe(rpvect) < 0) 6624863Seric { 6634863Seric syserr("pipe (from mailer)"); 6644863Seric (void) close(mpvect[0]); 6654863Seric (void) close(mpvect[1]); 6664863Seric return (-1); 6674863Seric } 6685179Seric # endif SMTP 6694863Seric 6706038Seric /* 6716038Seric ** Actually fork the mailer process. 6726038Seric ** DOFORK is clever about retrying. 6736038Seric */ 6746038Seric 6757672Seric (void) fflush(Xscript); /* for debugging */ 6764214Seric DOFORK(XFORK); 6774327Seric /* pid is set by DOFORK */ 678294Seric if (pid < 0) 679294Seric { 6806038Seric /* failure */ 681294Seric syserr("Cannot fork"); 6824709Seric (void) close(mpvect[0]); 6834709Seric (void) close(mpvect[1]); 6844863Seric if (clever) 6854863Seric { 6864863Seric (void) close(rpvect[0]); 6874863Seric (void) close(rpvect[1]); 6884863Seric } 689294Seric return (-1); 690294Seric } 691294Seric else if (pid == 0) 692294Seric { 693294Seric /* child -- set up input & exec mailer */ 6941621Seric /* make diagnostic output be standard output */ 6954477Seric (void) signal(SIGINT, SIG_IGN); 6964477Seric (void) signal(SIGHUP, SIG_IGN); 6974215Seric (void) signal(SIGTERM, SIG_DFL); 6984709Seric 6994709Seric /* arrange to filter standard & diag output of command */ 7004863Seric if (clever) 7014709Seric { 7024863Seric (void) close(rpvect[0]); 7034709Seric (void) close(1); 7044863Seric (void) dup(rpvect[1]); 7054863Seric (void) close(rpvect[1]); 7064863Seric } 7074863Seric else if (OutChannel != stdout) 7084863Seric { 7094863Seric (void) close(1); 7104709Seric (void) dup(fileno(OutChannel)); 7114709Seric } 7124082Seric (void) close(2); 7134082Seric (void) dup(1); 7144709Seric 7154709Seric /* arrange to get standard input */ 7164709Seric (void) close(mpvect[1]); 7174082Seric (void) close(0); 7184709Seric if (dup(mpvect[0]) < 0) 719294Seric { 7202898Seric syserr("Cannot dup to zero!"); 7212898Seric _exit(EX_OSERR); 722294Seric } 7234709Seric (void) close(mpvect[0]); 7242968Seric if (!bitset(M_RESTR, m->m_flags)) 7254215Seric { 7264417Seric if (ctladdr->q_uid == 0) 7274417Seric { 7284417Seric (void) setgid(DefGid); 7294417Seric (void) setuid(DefUid); 7304417Seric } 7314417Seric else 7324415Seric { 7334417Seric (void) setgid(ctladdr->q_gid); 7344417Seric (void) setuid(ctladdr->q_uid); 7354415Seric } 7364215Seric } 7372774Seric # ifndef VFORK 7382774Seric /* 7392774Seric ** We have to be careful with vfork - we can't mung up the 7402774Seric ** memory but we don't want the mailer to inherit any extra 7412774Seric ** open files. Chances are the mailer won't 7422774Seric ** care about an extra file, but then again you never know. 7432774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7442774Seric ** declared static so we can't. But if we fclose(pwf), which 7452774Seric ** is what endpwent does, it closes it in the parent too and 7462774Seric ** the next getpwnam will be slower. If you have a weird 7472774Seric ** mailer that chokes on the extra file you should do the 7482774Seric ** endpwent(). 7492774Seric ** 7502774Seric ** Similar comments apply to log. However, openlog is 7512774Seric ** clever enough to set the FIOCLEX mode on the file, 7522774Seric ** so it will be closed automatically on the exec. 7532774Seric */ 7542774Seric 7552774Seric endpwent(); 756294Seric # ifdef LOG 7572089Seric closelog(); 758294Seric # endif LOG 7592774Seric # endif VFORK 7606038Seric 7616038Seric /* try to execute the mailer */ 762294Seric execv(m->m_mailer, pvp); 7636038Seric 764294Seric /* syserr fails because log is closed */ 765294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 7664214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 7674082Seric (void) fflush(stdout); 7681619Seric _exit(EX_UNAVAILABLE); 769294Seric } 770294Seric 7714709Seric /* 7724863Seric ** Set up return value. 7734709Seric */ 7744709Seric 7754709Seric (void) close(mpvect[0]); 7764709Seric mfile = fdopen(mpvect[1], "w"); 7774863Seric if (clever) 7784863Seric { 7794863Seric (void) close(rpvect[1]); 7804863Seric rfile = fdopen(rpvect[0], "r"); 7814863Seric } 782294Seric 7834863Seric *pmfile = mfile; 7844863Seric *prfile = rfile; 785294Seric 7864863Seric return (pid); 787294Seric } 788294Seric /* 789294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 790294Seric ** 791294Seric ** Parameters: 792294Seric ** stat -- the status code from the mailer (high byte 793294Seric ** only; core dumps must have been taken care of 794294Seric ** already). 795294Seric ** force -- if set, force an error message output, even 796294Seric ** if the mailer seems to like to print its own 797294Seric ** messages. 798294Seric ** m -- the mailer descriptor for this mailer. 799294Seric ** 800294Seric ** Returns: 8014082Seric ** none. 802294Seric ** 803294Seric ** Side Effects: 8041518Seric ** Errors may be incremented. 805294Seric ** ExitStat may be set. 806294Seric */ 807294Seric 808294Seric giveresponse(stat, force, m) 809294Seric int stat; 8107228Seric bool force; 811294Seric register struct mailer *m; 812294Seric { 813294Seric register char *statmsg; 814294Seric extern char *SysExMsg[]; 815294Seric register int i; 816294Seric extern int N_SysEx; 8171624Seric char buf[30]; 818294Seric 8194315Seric /* 8204315Seric ** Compute status message from code. 8214315Seric */ 8224315Seric 823294Seric i = stat - EX__BASE; 824294Seric if (i < 0 || i > N_SysEx) 825294Seric statmsg = NULL; 826294Seric else 827294Seric statmsg = SysExMsg[i]; 828294Seric if (stat == 0) 8294065Seric { 8308003Seric statmsg = "250 sent"; 8318003Seric message(Arpa_Info, &statmsg[4]); 8324065Seric } 8334621Seric else if (stat == EX_TEMPFAIL) 8344621Seric { 8357875Seric message(Arpa_Info, "deferred"); 8364621Seric } 837294Seric else 838294Seric { 8391518Seric Errors++; 8406047Seric FatalErrors = TRUE; 841294Seric if (statmsg == NULL && m->m_badstat != 0) 842294Seric { 843294Seric stat = m->m_badstat; 844294Seric i = stat - EX__BASE; 845294Seric # ifdef DEBUG 846294Seric if (i < 0 || i >= N_SysEx) 847294Seric syserr("Bad m_badstat %d", stat); 848294Seric else 849294Seric # endif DEBUG 8507344Seric statmsg = SysExMsg[i]; 851294Seric } 852294Seric if (statmsg == NULL) 853294Seric usrerr("unknown mailer response %d", stat); 8544065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 8558003Seric usrerr(statmsg); 8567344Seric else 8578003Seric fprintf(Xscript, "%s\n", &statmsg[4]); 858294Seric } 859294Seric 860294Seric /* 861294Seric ** Final cleanup. 862294Seric ** Log a record of the transaction. Compute the new 863294Seric ** ExitStat -- if we already had an error, stick with 864294Seric ** that. 865294Seric */ 866294Seric 8671624Seric if (statmsg == NULL) 8681624Seric { 8698003Seric (void) sprintf(buf, "554 error %d", stat); 8701624Seric statmsg = buf; 8711624Seric } 8721624Seric 873294Seric # ifdef LOG 8747680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 8757858Seric { 8767858Seric extern char *pintvl(); 8777858Seric 8787858Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 8797883Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), 8808003Seric &statmsg[4]); 8817858Seric } 882294Seric # endif LOG 8834621Seric if (stat != EX_TEMPFAIL) 8844621Seric setstat(stat); 885294Seric } 886294Seric /* 8876974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 888294Seric ** 8896974Seric ** This can be made an arbitrary message separator by changing $l 890294Seric ** 8916974Seric ** One of the ugliest hacks seen by human eyes is 8926974Seric ** contained herein: UUCP wants those stupid 8936974Seric ** "remote from <host>" lines. Why oh why does a 8946974Seric ** well-meaning programmer such as myself have to 8956974Seric ** deal with this kind of antique garbage???? 8966974Seric ** 897294Seric ** Parameters: 8986974Seric ** fp -- the file to output to. 8996974Seric ** m -- the mailer describing this entry. 900294Seric ** 901294Seric ** Returns: 9026974Seric ** none 903294Seric ** 904294Seric ** Side Effects: 9056974Seric ** outputs some text to fp. 906294Seric */ 907294Seric 9086974Seric putfromline(fp, m) 9096974Seric register FILE *fp; 9106974Seric register MAILER *m; 911294Seric { 9126974Seric char buf[MAXLINE]; 913294Seric 9146974Seric if (bitset(M_NHDR, m->m_flags)) 9156974Seric return; 9164315Seric 9176974Seric # ifdef UGLYUUCP 9186974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9194205Seric { 9206974Seric extern char *macvalue(); 9218178Seric char *sys = macvalue('g', CurEnv); 9226974Seric char *bang = index(sys, '!'); 9236041Seric 9246974Seric if (bang == NULL) 9256974Seric syserr("No ! in UUCP! (%s)", sys); 9265099Seric else 9276974Seric *bang = '\0'; 9287232Seric expand("From $f $d remote from $g\n", buf, 9296974Seric &buf[sizeof buf - 1], CurEnv); 9306974Seric *bang = '!'; 9316974Seric } 9326974Seric else 9335179Seric # endif UGLYUUCP 9346974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 9357123Seric putline(buf, fp, bitset(M_FULLSMTP, m->m_flags)); 9365981Seric } 9375981Seric /* 9386974Seric ** PUTHEADER -- put the header part of a message from the in-core copy 9395981Seric ** 9405981Seric ** Parameters: 9415981Seric ** fp -- file to put it on. 9425981Seric ** m -- mailer to use. 9436974Seric ** e -- envelope to use. 9445981Seric ** 9455981Seric ** Returns: 9465981Seric ** none. 9475981Seric ** 9485981Seric ** Side Effects: 9495981Seric ** none. 9505981Seric */ 9515981Seric 9526974Seric putheader(fp, m, e) 9535981Seric register FILE *fp; 9545981Seric register struct mailer *m; 9556974Seric register ENVELOPE *e; 9565981Seric { 9575981Seric char buf[BUFSIZ]; 9585981Seric register HDR *h; 9595981Seric extern char *arpadate(); 9605981Seric extern char *capitalize(); 9615981Seric extern bool samefrom(); 9627123Seric char obuf[MAXLINE]; 9637123Seric register char *obp; 9647123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 9655981Seric 9666974Seric for (h = e->e_header; h != NULL; h = h->h_link) 9671828Seric { 9684315Seric register char *p; 9694315Seric 9703389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 9718062Seric continue; 9724447Seric 9737756Seric p = h->h_value; 9748062Seric if (bitset(H_DEFAULT, h->h_flags)) 9753385Seric { 9767666Seric /* macro expand value if generated internally */ 9778062Seric expand(p, buf, &buf[sizeof buf], e); 9783385Seric p = buf; 9793385Seric } 9804447Seric if (p == NULL || *p == '\0') 9813389Seric continue; 9824209Seric 9838062Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 9844209Seric { 9858062Seric /* address field */ 9868093Seric bool oldstyle = e->e_oldstyle; 9878093Seric 9888093Seric if (bitset(H_FROM, h->h_flags)) 9898093Seric oldstyle = FALSE; 9908093Seric commaize(h, p, fp, oldstyle, m); 9914447Seric } 9928062Seric else 9934447Seric { 9948062Seric /* vanilla header line */ 9957123Seric (void) sprintf(obuf, "%s: %s\n", capitalize(h->h_field), p); 9967123Seric putline(obuf, fp, fullsmtp); 9974209Seric } 9988062Seric h->h_flags |= H_USED; 9992898Seric } 1000294Seric } 1001294Seric /* 10027756Seric ** COMMAIZE -- output a header field, making a comma-translated list. 10037756Seric ** 10047756Seric ** Parameters: 10058062Seric ** h -- the header field to output. 10068062Seric ** p -- the value to put in it. 10077756Seric ** fp -- file to put it to. 10087756Seric ** oldstyle -- TRUE if this is an old style header. 10098235Seric ** m -- a pointer to the mailer descriptor. If NULL, 10108235Seric ** don't transform the name at all. 10117756Seric ** 10127756Seric ** Returns: 10137756Seric ** none. 10147756Seric ** 10157756Seric ** Side Effects: 10167756Seric ** outputs "p" to file "fp". 10177756Seric */ 10187756Seric 10198062Seric commaize(h, p, fp, oldstyle, m) 10208062Seric register HDR *h; 10217756Seric register char *p; 10227756Seric FILE *fp; 10237756Seric bool oldstyle; 10248062Seric register MAILER *m; 10257756Seric { 10268062Seric register char *obp; 10278062Seric int opos; 10288235Seric bool fullsmtp = FALSE; 10297756Seric bool firstone = TRUE; 10307756Seric char obuf[MAXLINE]; 10317756Seric 10327756Seric /* 10337756Seric ** Output the address list translated by the 10347756Seric ** mailer and with commas. 10357756Seric */ 10367756Seric 10377756Seric # ifdef DEBUG 10387756Seric if (tTd(14, 2)) 10398062Seric printf("commaize(%s: %s)\n", h->h_field, p); 10407756Seric # endif DEBUG 10417756Seric 10428235Seric if (m != NULL && bitset(M_FULLSMTP, m->m_flags)) 10438235Seric fullsmtp = TRUE; 10448235Seric 10457756Seric obp = obuf; 10468062Seric (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 10478062Seric opos = strlen(h->h_field) + 2; 10487756Seric obp += opos; 10497756Seric 10507756Seric /* 10517756Seric ** Run through the list of values. 10527756Seric */ 10537756Seric 10547756Seric while (*p != '\0') 10557756Seric { 10567756Seric register char *name; 10577756Seric char savechar; 10588062Seric extern char *remotename(); 10598077Seric extern char *DelimChar; /* defined in prescan */ 10607756Seric 10617756Seric /* 10627756Seric ** Find the end of the name. New style names 10637756Seric ** end with a comma, old style names end with 10647756Seric ** a space character. However, spaces do not 10657756Seric ** necessarily delimit an old-style name -- at 10667756Seric ** signs mean keep going. 10677756Seric */ 10687756Seric 10698077Seric /* find end of name */ 10708077Seric while (isspace(*p) || *p == ',') 10717756Seric p++; 10727756Seric name = p; 10738077Seric for (;;) 10747756Seric { 10758077Seric char *oldp; 10767756Seric extern bool isatword(); 10777756Seric 10788091Seric (void) prescan(p, oldstyle ? ' ' : ','); 10798077Seric p = DelimChar; 10807756Seric 10817756Seric /* look to see if we have an at sign */ 10827756Seric oldp = p; 10837756Seric while (*p != '\0' && isspace(*p)) 10847756Seric p++; 10857756Seric 10867756Seric if (*p != '@' && !isatword(p)) 10877756Seric { 10887756Seric p = oldp; 10897756Seric break; 10907756Seric } 10917756Seric p += *p == '@' ? 1 : 2; 10927756Seric while (*p != '\0' && isspace(*p)) 10937756Seric p++; 10947756Seric } 10957756Seric /* at the end of one complete name */ 10967756Seric 10977756Seric /* strip off trailing white space */ 10987756Seric while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) 10997756Seric p--; 11007756Seric if (++p == name) 11017756Seric continue; 11027756Seric savechar = *p; 11037756Seric *p = '\0'; 11047756Seric 11057756Seric /* translate the name to be relative */ 11068235Seric if (m != NULL) 11078235Seric name = remotename(name, m, bitset(H_FROM, h->h_flags)); 11087756Seric if (*name == '\0') 11097756Seric { 11107756Seric *p = savechar; 11117756Seric continue; 11127756Seric } 11137756Seric 11147756Seric /* output the name with nice formatting */ 11157756Seric opos += strlen(name); 11167756Seric if (!firstone) 11177756Seric opos += 2; 11187756Seric if (opos > 78 && !firstone) 11197756Seric { 11207756Seric (void) sprintf(obp, ",\n"); 11217756Seric putline(obuf, fp, fullsmtp); 11227756Seric obp = obuf; 11237756Seric (void) sprintf(obp, " "); 11247756Seric obp += strlen(obp); 11257756Seric opos = 8 + strlen(name); 11267756Seric } 11277756Seric else if (!firstone) 11287756Seric { 11297756Seric (void) sprintf(obp, ", "); 11307756Seric obp += 2; 11317756Seric } 11327756Seric (void) sprintf(obp, "%s", name); 11337756Seric obp += strlen(obp); 11347756Seric firstone = FALSE; 11357756Seric *p = savechar; 11367756Seric } 11377756Seric (void) strcpy(obp, "\n"); 11387756Seric putline(obuf, fp, fullsmtp); 11397756Seric } 11407756Seric /* 11416974Seric ** PUTBODY -- put the body of a message. 11426974Seric ** 11436974Seric ** Parameters: 11446974Seric ** fp -- file to output onto. 11456974Seric ** m -- a mailer descriptor. 11466974Seric ** xdot -- if set, use SMTP hidden dot algorithm. 11476974Seric ** 11486974Seric ** Returns: 11496974Seric ** none. 11506974Seric ** 11516974Seric ** Side Effects: 11526974Seric ** The message is written onto fp. 11536974Seric */ 11546974Seric 11556974Seric putbody(fp, m, xdot) 11566974Seric FILE *fp; 11576974Seric struct mailer *m; 11586974Seric bool xdot; 11596974Seric { 11606974Seric char buf[MAXLINE + 1]; 11617123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 11626974Seric 11636974Seric /* 11646974Seric ** Output the body of the message 11656974Seric */ 11666974Seric 11677003Seric #ifdef lint 11687003Seric /* m will be needed later for complete smtp emulation */ 11697003Seric if (m == NULL) 11707003Seric return; 11717003Seric #endif lint 11727003Seric 11736974Seric if (TempFile != NULL) 11746974Seric { 11756974Seric rewind(TempFile); 11766974Seric buf[0] = '.'; 11776974Seric while (!ferror(fp) && fgets(&buf[1], sizeof buf - 1, TempFile) != NULL) 11787123Seric putline((xdot && buf[1] == '.') ? buf : &buf[1], fp, fullsmtp); 11796974Seric 11806974Seric if (ferror(TempFile)) 11816974Seric { 11826974Seric syserr("putbody: read error"); 11836974Seric ExitStat = EX_IOERR; 11846974Seric } 11856974Seric } 11866974Seric 11876974Seric (void) fflush(fp); 11886974Seric if (ferror(fp) && errno != EPIPE) 11896974Seric { 11906974Seric syserr("putbody: write error"); 11916974Seric ExitStat = EX_IOERR; 11926974Seric } 11936974Seric errno = 0; 11946974Seric } 11956974Seric /* 11965936Seric ** ISATWORD -- tell if the word we are pointing to is "at". 11975936Seric ** 11985936Seric ** Parameters: 11995936Seric ** p -- word to check. 12005936Seric ** 12015936Seric ** Returns: 12025936Seric ** TRUE -- if p is the word at. 12035936Seric ** FALSE -- otherwise. 12045936Seric ** 12055936Seric ** Side Effects: 12065936Seric ** none. 12075936Seric */ 12085936Seric 12095936Seric bool 12105936Seric isatword(p) 12115936Seric register char *p; 12125936Seric { 12135936Seric extern char lower(); 12145936Seric 12155936Seric if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 12165936Seric p[2] != '\0' && isspace(p[2])) 12175936Seric return (TRUE); 12185936Seric return (FALSE); 12195936Seric } 12205936Seric /* 12214370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 12224370Seric ** 12234370Seric ** Parameters: 12244370Seric ** ifrom -- internally generated form of from address. 12254370Seric ** efrom -- external form of from address. 12264370Seric ** 12274370Seric ** Returns: 12284370Seric ** TRUE -- if they convey the same info. 12294370Seric ** FALSE -- if any information has been lost. 12304370Seric ** 12314370Seric ** Side Effects: 12324370Seric ** none. 12334370Seric */ 12344370Seric 12354370Seric bool 12364370Seric samefrom(ifrom, efrom) 12374370Seric char *ifrom; 12384370Seric char *efrom; 12394370Seric { 12404447Seric register char *p; 12414447Seric char buf[MAXNAME + 4]; 12424447Seric 12434447Seric # ifdef DEBUG 12447672Seric if (tTd(3, 8)) 12454447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 12464447Seric # endif DEBUG 12474447Seric if (strcmp(ifrom, efrom) == 0) 12484447Seric goto success; 12494447Seric p = index(ifrom, '@'); 12504447Seric if (p == NULL) 12514447Seric goto failure; 12524447Seric *p = '\0'; 12537003Seric (void) strcpy(buf, ifrom); 12547003Seric (void) strcat(buf, " at "); 12554447Seric *p++ = '@'; 12567003Seric (void) strcat(buf, p); 12574447Seric if (strcmp(buf, efrom) == 0) 12584447Seric goto success; 12594447Seric 12604447Seric failure: 12614447Seric # ifdef DEBUG 12627672Seric if (tTd(3, 8)) 12634447Seric printf("FALSE\n"); 12644447Seric # endif DEBUG 12654447Seric return (FALSE); 12664447Seric 12674447Seric success: 12684447Seric # ifdef DEBUG 12697672Seric if (tTd(3, 8)) 12704447Seric printf("TRUE\n"); 12714447Seric # endif DEBUG 12724447Seric return (TRUE); 12734370Seric } 12744370Seric /* 1275294Seric ** MAILFILE -- Send a message to a file. 1276294Seric ** 12774327Seric ** If the file has the setuid/setgid bits set, but NO execute 12784327Seric ** bits, sendmail will try to become the owner of that file 12794327Seric ** rather than the real user. Obviously, this only works if 12804327Seric ** sendmail runs as root. 12814327Seric ** 1282294Seric ** Parameters: 1283294Seric ** filename -- the name of the file to send to. 12844397Seric ** ctladdr -- the controlling address header -- includes 12854397Seric ** the userid/groupid to be when sending. 1286294Seric ** 1287294Seric ** Returns: 1288294Seric ** The exit code associated with the operation. 1289294Seric ** 1290294Seric ** Side Effects: 1291294Seric ** none. 1292294Seric */ 1293294Seric 12944397Seric mailfile(filename, ctladdr) 1295294Seric char *filename; 12964397Seric ADDRESS *ctladdr; 1297294Seric { 1298294Seric register FILE *f; 12994214Seric register int pid; 1300294Seric 13014214Seric /* 13024214Seric ** Fork so we can change permissions here. 13034214Seric ** Note that we MUST use fork, not vfork, because of 13044214Seric ** the complications of calling subroutines, etc. 13054214Seric */ 13064067Seric 13074214Seric DOFORK(fork); 13084214Seric 13094214Seric if (pid < 0) 13104214Seric return (EX_OSERR); 13114214Seric else if (pid == 0) 13124214Seric { 13134214Seric /* child -- actually write to file */ 13144327Seric struct stat stb; 13154327Seric 13164215Seric (void) signal(SIGINT, SIG_DFL); 13174215Seric (void) signal(SIGHUP, SIG_DFL); 13184215Seric (void) signal(SIGTERM, SIG_DFL); 13194327Seric umask(OldUmask); 13204327Seric if (stat(filename, &stb) < 0) 13214431Seric stb.st_mode = 0666; 13224327Seric if (bitset(0111, stb.st_mode)) 13234327Seric exit(EX_CANTCREAT); 13244401Seric if (ctladdr == NULL) 13256900Seric ctladdr = &CurEnv->e_from; 13264327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 13274417Seric { 13284417Seric if (ctladdr->q_uid == 0) 13294417Seric (void) setgid(DefGid); 13304417Seric else 13314417Seric (void) setgid(ctladdr->q_gid); 13324417Seric } 13334327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 13344417Seric { 13354417Seric if (ctladdr->q_uid == 0) 13364417Seric (void) setuid(DefUid); 13374417Seric else 13384417Seric (void) setuid(ctladdr->q_uid); 13394417Seric } 13406887Seric f = dfopen(filename, "a"); 13414214Seric if (f == NULL) 13424214Seric exit(EX_CANTCREAT); 13434214Seric 13446974Seric putfromline(f, Mailer[1]); 13456974Seric (*CurEnv->e_puthdr)(f, Mailer[1], CurEnv); 13467123Seric fputs("\n", f); 13476974Seric (*CurEnv->e_putbody)(f, Mailer[1], FALSE); 13484214Seric fputs("\n", f); 13494214Seric (void) fclose(f); 13504214Seric (void) fflush(stdout); 13514417Seric 13526887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13534621Seric (void) chmod(filename, (int) stb.st_mode); 13544214Seric exit(EX_OK); 13554315Seric /*NOTREACHED*/ 13564214Seric } 13574214Seric else 13584214Seric { 13594214Seric /* parent -- wait for exit status */ 13604214Seric register int i; 13614214Seric auto int stat; 13624214Seric 13634214Seric while ((i = wait(&stat)) != pid) 13644214Seric { 13654214Seric if (i < 0) 13664214Seric { 13674214Seric stat = EX_OSERR << 8; 13684214Seric break; 13694214Seric } 13704214Seric } 13714215Seric if ((stat & 0377) != 0) 13724215Seric stat = EX_UNAVAILABLE << 8; 13734214Seric return ((stat >> 8) & 0377); 13744214Seric } 1375294Seric } 13764550Seric /* 13774550Seric ** SENDALL -- actually send all the messages. 13784550Seric ** 13794550Seric ** Parameters: 13807043Seric ** e -- the envelope to send. 13814550Seric ** verifyonly -- if set, only give verification messages. 13824550Seric ** 13834550Seric ** Returns: 13844550Seric ** none. 13854550Seric ** 13864550Seric ** Side Effects: 13874550Seric ** Scans the send lists and sends everything it finds. 13887043Seric ** Delivers any appropriate error messages. 13894550Seric */ 13904550Seric 13917043Seric sendall(e, verifyonly) 13927043Seric ENVELOPE *e; 13934550Seric bool verifyonly; 13944550Seric { 13955008Seric register ADDRESS *q; 13967779Seric bool oldverbose; 13974550Seric 13985032Seric # ifdef DEBUG 1399*8248Seric if (tTd(13, 1)) 14005032Seric { 1401*8248Seric printf("\nSENDALL: verify %d, sendqueue:\n"); 14027043Seric printaddr(e->e_sendqueue, TRUE); 14035032Seric } 14045032Seric # endif DEBUG 14055008Seric 14067043Seric /* 14077043Seric ** Run through the list and send everything. 14087043Seric */ 14097043Seric 14107779Seric oldverbose = Verbose; 14117779Seric if (verifyonly) 14127779Seric Verbose = TRUE; 14137043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14144550Seric { 14155008Seric if (verifyonly) 14164550Seric { 14176900Seric CurEnv->e_to = q->q_paddr; 14185008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14197052Seric message(Arpa_Info, "deliverable"); 14204550Seric } 14215008Seric else 14226974Seric (void) deliver(q); 14234550Seric } 14247779Seric Verbose = oldverbose; 14257043Seric 14267043Seric /* 14277043Seric ** Now run through and check for errors. 14287043Seric */ 14297043Seric 14307043Seric if (verifyonly) 14317043Seric return; 14327043Seric 14337043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14347043Seric { 14357043Seric register ADDRESS *qq; 14367043Seric 1437*8248Seric # ifdef DEBUG 1438*8248Seric if (tTd(13, 3)) 1439*8248Seric { 1440*8248Seric printf("Checking "); 1441*8248Seric printaddr(q, FALSE); 1442*8248Seric } 1443*8248Seric # endif DEBUG 1444*8248Seric 14457043Seric if (bitset(QQUEUEUP, q->q_flags)) 14467043Seric e->e_queueup = TRUE; 14477043Seric 14487043Seric /* we have an address that failed -- find the parent */ 14497043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14507043Seric { 14517043Seric char obuf[MAXNAME + 6]; 14527043Seric extern char *aliaslookup(); 14537043Seric 14547043Seric /* we can only have owners for local addresses */ 14557043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 14567043Seric continue; 14577043Seric 14587043Seric /* see if the owner list exists */ 14597043Seric (void) strcpy(obuf, "owner-"); 14607047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14617047Seric (void) strcat(obuf, "owner"); 14627047Seric else 14637047Seric (void) strcat(obuf, qq->q_user); 14647043Seric if (aliaslookup(obuf) == NULL) 14657043Seric continue; 14667043Seric 1467*8248Seric # ifdef DEBUG 1468*8248Seric if (tTd(13, 4)) 1469*8248Seric printf("Errors to %s\n", obuf); 1470*8248Seric # endif DEBUG 1471*8248Seric 1472*8248Seric /* add in an errors-to field */ 1473*8248Seric /* ugh... must happen before delivery..... 1474*8248Seric addheader("errors-to", newstr(obuf), e); 1475*8248Seric .... i guess this should go in sendto */ 1476*8248Seric 1477*8248Seric /* only send errors if the message failed */ 1478*8248Seric if (!bitset(QBADADDR, q->q_flags)) 1479*8248Seric break; 1480*8248Seric 14817043Seric /* owner list exists -- add it to the error queue */ 14827043Seric qq->q_flags &= ~QPRIMARY; 14838077Seric sendto(obuf, qq, &e->e_errorqueue); 14847043Seric MailBack = TRUE; 14857043Seric break; 14867043Seric } 14877043Seric 14887043Seric /* if we did not find an owner, send to the sender */ 14897043Seric if (qq == NULL) 14908077Seric sendto(e->e_from.q_paddr, qq, &e->e_errorqueue); 14917043Seric } 14924550Seric } 14937043Seric /* 14947043Seric ** CHECKERRORS -- check a queue of addresses and process errors. 14957043Seric ** 14967043Seric ** Parameters: 14977043Seric ** e -- the envelope to check. 14987043Seric ** 14997043Seric ** Returns: 15007043Seric ** none. 15017043Seric ** 15027043Seric ** Side Effects: 15037043Seric ** Arranges to queue all tempfailed messages in q 15047043Seric ** or deliver error responses. 15057043Seric */ 15067043Seric 15077043Seric checkerrors(e) 15087043Seric register ENVELOPE *e; 15097043Seric { 15107808Seric register ADDRESS *q; 15117808Seric 15127043Seric # ifdef DEBUG 15137672Seric if (tTd(4, 1)) 15147043Seric { 15157371Seric printf("\ncheckerrors: FatalErrors %d, errorqueue:\n"); 15167043Seric printaddr(e->e_errorqueue, TRUE); 15177043Seric } 15187043Seric # endif DEBUG 15197043Seric 15207043Seric /* mail back the transcript on errors */ 15217043Seric if (FatalErrors) 15227043Seric savemail(); 15237043Seric 15247043Seric /* queue up anything laying around */ 15257858Seric if (e->e_dontqueue) 15267858Seric return; 15277808Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15287043Seric { 15297808Seric if (bitset(QQUEUEUP, q->q_flags)) 15307808Seric { 15317043Seric # ifdef QUEUE 15327808Seric queueup(e, FALSE); 15337043Seric # else QUEUE 15347808Seric syserr("checkerrors: trying to queue %s", e->e_df); 15357043Seric # endif QUEUE 15367808Seric break; 15377808Seric } 15387043Seric } 15397043Seric } 1540