1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric # ifdef LOG 62774Seric # include <syslog.h> 7294Seric # endif LOG 8294Seric 9*6820Seric SCCSID(@(#)deliver.c 3.77 05/15/82); 10405Seric 11294Seric /* 124315Seric ** DELIVER -- Deliver a message to a list of addresses. 13294Seric ** 144315Seric ** This routine delivers to everyone on the same host as the 154315Seric ** user on the head of the list. It is clever about mailers 164315Seric ** that don't handle multiple users. It is NOT guaranteed 174315Seric ** that it will deliver to all these addresses however -- so 184315Seric ** deliver should be called once for each address on the 194315Seric ** list. 204315Seric ** 21294Seric ** Parameters: 224621Seric ** firstto -- head of the address list to deliver to. 23294Seric ** editfcn -- if non-NULL, we want to call this function 24294Seric ** to output the letter (instead of just out- 25294Seric ** putting it raw). 26294Seric ** 27294Seric ** Returns: 28294Seric ** zero -- successfully delivered. 29294Seric ** else -- some failure, see ExitStat for more info. 30294Seric ** 31294Seric ** Side Effects: 32294Seric ** The standard input is passed off to someone. 33294Seric */ 34294Seric 354621Seric deliver(firstto, editfcn) 364621Seric ADDRESS *firstto; 37294Seric int (*editfcn)(); 38294Seric { 394452Seric char *host; /* host being sent to */ 404452Seric char *user; /* user being sent to */ 41294Seric char **pvp; 423233Seric register char **mvp; 433233Seric register char *p; 444452Seric register struct mailer *m; /* mailer for this recipient */ 45294Seric register int i; 462898Seric extern putmessage(); 472968Seric extern bool checkcompat(); 483233Seric char *pv[MAXPV+1]; 494452Seric char tobuf[MAXLINE]; /* text line of to people */ 503233Seric char buf[MAXNAME]; 514397Seric ADDRESS *ctladdr; 524397Seric extern ADDRESS *getctladdr(); 534452Seric char tfrombuf[MAXNAME]; /* translated from person */ 544452Seric extern char **prescan(); 554621Seric register ADDRESS *to = firstto; 564863Seric bool clever = FALSE; /* running user smtp to this mailer */ 574863Seric bool tempfail = FALSE; 585032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 59294Seric 604488Seric errno = 0; 615008Seric if (!ForceMail && bitset(QDONTSEND, to->q_flags)) 623233Seric return (0); 63294Seric 64294Seric # ifdef DEBUG 65294Seric if (Debug) 663233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 674596Seric to->q_mailer->m_mno, to->q_host, to->q_user); 68294Seric # endif DEBUG 69294Seric 705903Seric m = to->q_mailer; 715903Seric host = to->q_host; 725903Seric 73294Seric /* 745903Seric ** If this mailer is expensive, and if we don't want to make 755903Seric ** connections now, just mark these addresses and return. 765903Seric ** This is useful if we want to batch connections to 775903Seric ** reduce load. This will cause the messages to be 785903Seric ** queued up, and a daemon will come along to send the 795903Seric ** messages later. 805903Seric ** This should be on a per-mailer basis. 815903Seric */ 825903Seric 835903Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags)) 845903Seric { 855903Seric QueueUp = TRUE; 865903Seric for (; to != NULL; to = to->q_next) 875903Seric if (!bitset(QDONTSEND, to->q_flags)) 885903Seric to->q_flags |= QQUEUEUP|QDONTSEND; 895903Seric return (0); 905903Seric } 915903Seric 925903Seric /* 933233Seric ** Do initial argv setup. 943233Seric ** Insert the mailer name. Notice that $x expansion is 953233Seric ** NOT done on the mailer name. Then, if the mailer has 963233Seric ** a picky -f flag, we insert it as appropriate. This 973233Seric ** code does not check for 'pv' overflow; this places a 983233Seric ** manifest lower limit of 4 for MAXPV. 995903Seric ** We rewrite the from address here, being careful 1005903Seric ** to also rewrite it again using ruleset 2 to 1015903Seric ** eliminate redundancies. 1022968Seric */ 1032968Seric 1044452Seric /* rewrite from address, using rewriting rules */ 1054452Seric (void) expand(m->m_from, buf, &buf[sizeof buf - 1]); 1064452Seric mvp = prescan(buf, '\0'); 1074452Seric if (mvp == NULL) 1084452Seric { 1094452Seric syserr("bad mailer from translate \"%s\"", buf); 1104452Seric return (EX_SOFTWARE); 1114452Seric } 1124452Seric rewrite(mvp, 2); 1134452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 1144452Seric 1154452Seric define('g', tfrombuf); /* translated sender address */ 1163233Seric define('h', host); /* to host */ 1173233Seric Errors = 0; 1183233Seric pvp = pv; 1193233Seric *pvp++ = m->m_argv[0]; 1202968Seric 1213233Seric /* insert -f or -r flag as appropriate */ 1223233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1233233Seric { 1243233Seric if (bitset(M_FOPT, m->m_flags)) 1253233Seric *pvp++ = "-f"; 1263233Seric else 1273233Seric *pvp++ = "-r"; 1284082Seric (void) expand("$g", buf, &buf[sizeof buf - 1]); 1293233Seric *pvp++ = newstr(buf); 1303233Seric } 131294Seric 132294Seric /* 1333233Seric ** Append the other fixed parts of the argv. These run 1343233Seric ** up to the first entry containing "$u". There can only 1353233Seric ** be one of these, and there are only a few more slots 1363233Seric ** in the pv after it. 137294Seric */ 138294Seric 1393233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 140294Seric { 1413233Seric while ((p = index(p, '$')) != NULL) 1423233Seric if (*++p == 'u') 1433233Seric break; 1443233Seric if (p != NULL) 1453233Seric break; 1463233Seric 1473233Seric /* this entry is safe -- go ahead and process it */ 1484082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 1493233Seric *pvp++ = newstr(buf); 1503233Seric if (pvp >= &pv[MAXPV - 3]) 1513233Seric { 1523233Seric syserr("Too many parameters to %s before $u", pv[0]); 1533233Seric return (-1); 1543233Seric } 155294Seric } 1564863Seric 1576038Seric /* 1586038Seric ** If we have no substitution for the user name in the argument 1596038Seric ** list, we know that we must supply the names otherwise -- and 1606038Seric ** SMTP is the answer!! 1616038Seric */ 1626038Seric 1633233Seric if (*mvp == NULL) 1644863Seric { 1654863Seric /* running SMTP */ 1665179Seric # ifdef SMTP 1674863Seric clever = TRUE; 1684863Seric *pvp = NULL; 1696038Seric 1706038Seric /* send the initial SMTP protocol */ 1716047Seric smtpinit(m, pv, (ADDRESS *) NULL); 1725179Seric # ifdef QUEUE 1734863Seric if (i == EX_TEMPFAIL) 1744863Seric { 1754863Seric QueueUp = TRUE; 1764863Seric tempfail = TRUE; 1774863Seric } 1785179Seric # endif QUEUE 1795179Seric # else SMTP 1806038Seric /* oops! we don't implement SMTP */ 1815179Seric syserr("SMTP style mailer"); 1825179Seric return (EX_SOFTWARE); 1835179Seric # endif SMTP 1844863Seric } 185294Seric 186294Seric /* 1873233Seric ** At this point *mvp points to the argument with $u. We 1883233Seric ** run through our address list and append all the addresses 1893233Seric ** we can. If we run out of space, do not fret! We can 1903233Seric ** always send another copy later. 191294Seric */ 192294Seric 1933233Seric tobuf[0] = '\0'; 1943233Seric To = tobuf; 1954397Seric ctladdr = NULL; 1963233Seric for (; to != NULL; to = to->q_next) 197294Seric { 1983233Seric /* avoid sending multiple recipients to dumb mailers */ 1994382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 2003233Seric break; 2013233Seric 2023233Seric /* if already sent or not for this host, don't send */ 2035008Seric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 2045008Seric strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) 2053233Seric continue; 2064397Seric 2075032Seric # ifdef DEBUG 2085032Seric if (Debug) 2095032Seric { 2105032Seric printf("\nsend to "); 2115032Seric printaddr(to, FALSE); 2125032Seric } 2135032Seric # endif DEBUG 2145032Seric 2154397Seric /* compute effective uid/gid when sending */ 2164596Seric if (to->q_mailer == ProgMailer) 2174397Seric ctladdr = getctladdr(to); 2184397Seric 2193233Seric user = to->q_user; 2203233Seric To = to->q_paddr; 2213233Seric to->q_flags |= QDONTSEND; 2224863Seric if (tempfail) 2235032Seric { 2244863Seric to->q_flags |= QQUEUEUP; 2255032Seric continue; 2265032Seric } 2273233Seric 2283233Seric /* 2293233Seric ** Check to see that these people are allowed to 2303233Seric ** talk to each other. 2313233Seric */ 2323233Seric 2333233Seric if (!checkcompat(to)) 234294Seric { 2353233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 2363233Seric continue; 237294Seric } 2383233Seric 2393233Seric /* 2404099Seric ** Strip quote bits from names if the mailer is dumb 2414099Seric ** about them. 2423233Seric */ 2433233Seric 2443233Seric if (bitset(M_STRIPQ, m->m_flags)) 245294Seric { 2464099Seric stripquotes(user, TRUE); 2474099Seric stripquotes(host, TRUE); 2483233Seric } 2494099Seric else 2504099Seric { 2514099Seric stripquotes(user, FALSE); 2524099Seric stripquotes(host, FALSE); 2534099Seric } 2543233Seric 2553233Seric /* 2566059Seric ** Pass it to the other host if we are running SMTP. 2576059Seric */ 2586059Seric 2596059Seric if (clever) 2606059Seric { 2616059Seric # ifdef SMTP 2626059Seric i = smtprcpt(to); 2636059Seric if (i != EX_OK) 2646059Seric { 2656059Seric # ifdef QUEUE 2666059Seric if (i == EX_TEMPFAIL) 2676059Seric { 2686059Seric QueueUp = TRUE; 2696059Seric to->q_flags |= QQUEUEUP; 2706059Seric } 2716059Seric else 2726059Seric # endif QUEUE 2736059Seric { 2746059Seric to->q_flags |= QBADADDR; 2756059Seric giveresponse(i, TRUE, m); 2766059Seric } 2776059Seric } 2786059Seric # else SMTP 2796059Seric syserr("trying to be clever"); 2806059Seric # endif SMTP 2816059Seric } 2826059Seric 2836059Seric /* 2844161Seric ** If an error message has already been given, don't 2854161Seric ** bother to send to this address. 2864161Seric ** 2874161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2884161Seric ** >> NOTE >> cannot do any further aliasing; that 2894161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2904161Seric */ 2914161Seric 2924161Seric if (bitset(QBADADDR, to->q_flags)) 2934161Seric continue; 2944161Seric 2954283Seric /* save statistics.... */ 2964596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2974596Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(MsgSize); 2984283Seric 2994161Seric /* 3003233Seric ** See if this user name is "special". 3013233Seric ** If the user name has a slash in it, assume that this 3023233Seric ** is a file -- send it off without further ado. 3033233Seric ** Note that this means that editfcn's will not 3043233Seric ** be applied to the message. Also note that 3053233Seric ** this type of addresses is not processed along 3063233Seric ** with the others, so we fudge on the To person. 3073233Seric */ 3083233Seric 3094596Seric if (m == LocalMailer) 3103233Seric { 3115599Seric if (user[0] == '/') 312294Seric { 3134397Seric i = mailfile(user, getctladdr(to)); 314294Seric giveresponse(i, TRUE, m); 3153233Seric continue; 316294Seric } 317294Seric } 3183233Seric 3194315Seric /* 3204315Seric ** Address is verified -- add this user to mailer 3214315Seric ** argv, and add it to the print list of recipients. 3224315Seric */ 3234315Seric 3246059Seric /* link together the chain of recipients */ 3256272Seric to->q_tchain = tochain; 3266272Seric tochain = to; 3276059Seric 3283233Seric /* create list of users for error messages */ 3293233Seric if (tobuf[0] != '\0') 3304082Seric (void) strcat(tobuf, ","); 3314082Seric (void) strcat(tobuf, to->q_paddr); 3323233Seric define('u', user); /* to user */ 3334078Seric define('z', to->q_home); /* user's home */ 3343233Seric 3354863Seric /* 3366059Seric ** Expand out this user into argument list. 3374863Seric */ 3384863Seric 3396059Seric if (!clever) 3403233Seric { 3414863Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3424863Seric *pvp++ = newstr(buf); 3434863Seric if (pvp >= &pv[MAXPV - 2]) 3444863Seric { 3454863Seric /* allow some space for trailing parms */ 3464863Seric break; 3474863Seric } 3484863Seric } 349294Seric } 350294Seric 3514067Seric /* see if any addresses still exist */ 3524067Seric if (tobuf[0] == '\0') 3534863Seric { 3545179Seric # ifdef SMTP 3554863Seric if (clever) 3564863Seric smtpquit(pv[0]); 3575179Seric # endif SMTP 3584067Seric return (0); 3594863Seric } 3604067Seric 3613233Seric /* print out messages as full list */ 3623233Seric To = tobuf; 3633233Seric 364294Seric /* 3653233Seric ** Fill out any parameters after the $u parameter. 366294Seric */ 367294Seric 3684863Seric while (!clever && *++mvp != NULL) 369294Seric { 3704082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3713233Seric *pvp++ = newstr(buf); 3723233Seric if (pvp >= &pv[MAXPV]) 3733233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 374294Seric } 3753233Seric *pvp++ = NULL; 376294Seric 377294Seric /* 378294Seric ** Call the mailer. 3792898Seric ** The argument vector gets built, pipes 380294Seric ** are created as necessary, and we fork & exec as 3812898Seric ** appropriate. 3824863Seric ** If we are running SMTP, we just need to clean up. 383294Seric */ 384294Seric 3853233Seric if (editfcn == NULL) 3863233Seric editfcn = putmessage; 3874397Seric if (ctladdr == NULL) 3884397Seric ctladdr = &From; 3895179Seric # ifdef SMTP 3904863Seric if (clever) 3914863Seric { 3924863Seric i = smtpfinish(m, editfcn); 3934863Seric smtpquit(pv[0]); 3944863Seric } 3954863Seric else 3965179Seric # endif SMTP 3974863Seric i = sendoff(m, pv, editfcn, ctladdr); 3983233Seric 3994621Seric /* 4004621Seric ** If we got a temporary failure, arrange to queue the 4014621Seric ** addressees. 4024621Seric */ 4034621Seric 4045179Seric # ifdef QUEUE 4054621Seric if (i == EX_TEMPFAIL) 4064621Seric { 4074621Seric QueueUp = TRUE; 4085032Seric for (to = tochain; to != NULL; to = to->q_tchain) 4094621Seric to->q_flags |= QQUEUEUP; 4104621Seric } 4115179Seric # endif QUEUE 4124621Seric 4134488Seric errno = 0; 4143233Seric return (i); 4153233Seric } 4163233Seric /* 4174214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4184214Seric ** 4194214Seric ** This MUST be a macro, since after a vfork we are running 4204214Seric ** two processes on the same stack!!! 4214214Seric ** 4224214Seric ** Parameters: 4234214Seric ** none. 4244214Seric ** 4254214Seric ** Returns: 4264214Seric ** From a macro??? You've got to be kidding! 4274214Seric ** 4284214Seric ** Side Effects: 4294214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4304214Seric ** pid of child in parent, zero in child. 4314214Seric ** -1 on unrecoverable error. 4324214Seric ** 4334214Seric ** Notes: 4344214Seric ** I'm awfully sorry this looks so awful. That's 4354214Seric ** vfork for you..... 4364214Seric */ 4374214Seric 4384214Seric # define NFORKTRIES 5 4394214Seric # ifdef VFORK 4404214Seric # define XFORK vfork 4414214Seric # else VFORK 4424214Seric # define XFORK fork 4434214Seric # endif VFORK 4444214Seric 4454214Seric # define DOFORK(fORKfN) \ 4464214Seric {\ 4474214Seric register int i;\ 4484214Seric \ 4494214Seric for (i = NFORKTRIES; i-- > 0; )\ 4504214Seric {\ 4514214Seric pid = fORKfN();\ 4524214Seric if (pid >= 0)\ 4534214Seric break;\ 4544214Seric sleep((unsigned) NFORKTRIES - i);\ 4554214Seric }\ 4564214Seric } 4574214Seric /* 4584637Seric ** DOFORK -- simple fork interface to DOFORK. 4594637Seric ** 4604637Seric ** Parameters: 4614637Seric ** none. 4624637Seric ** 4634637Seric ** Returns: 4644637Seric ** pid of child in parent. 4654637Seric ** zero in child. 4664637Seric ** -1 on error. 4674637Seric ** 4684637Seric ** Side Effects: 4694637Seric ** returns twice, once in parent and once in child. 4704637Seric */ 4714637Seric 4724637Seric dofork() 4734637Seric { 4744637Seric register int pid; 4754637Seric 4764637Seric DOFORK(fork); 4774637Seric return (pid); 4784637Seric } 4794637Seric /* 4803233Seric ** SENDOFF -- send off call to mailer & collect response. 4813233Seric ** 4823233Seric ** Parameters: 4833233Seric ** m -- mailer descriptor. 4843233Seric ** pvp -- parameter vector to send to it. 4853233Seric ** editfcn -- function to pipe it through. 4864397Seric ** ctladdr -- an address pointer controlling the 4874397Seric ** user/groupid etc. of the mailer. 4883233Seric ** 4893233Seric ** Returns: 4903233Seric ** exit status of mailer. 4913233Seric ** 4923233Seric ** Side Effects: 4933233Seric ** none. 4943233Seric */ 4953233Seric 4964397Seric sendoff(m, pvp, editfcn, ctladdr) 4973233Seric struct mailer *m; 4983233Seric char **pvp; 4993233Seric int (*editfcn)(); 5004397Seric ADDRESS *ctladdr; 5013233Seric { 5024863Seric auto FILE *mfile; 5034863Seric auto FILE *rfile; 5043233Seric register int i; 5054863Seric extern putmessage(); 5063233Seric int pid; 5074863Seric 5084863Seric /* 5094863Seric ** Create connection to mailer. 5104863Seric */ 5114863Seric 5124863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5134863Seric if (pid < 0) 5144863Seric return (-1); 5154863Seric 5164863Seric /* 5174863Seric ** Format and send message. 5184863Seric */ 5194863Seric 5204863Seric (void) signal(SIGPIPE, SIG_IGN); 5214863Seric if (editfcn == NULL) 5224863Seric editfcn = putmessage; 5234863Seric 5244863Seric (*editfcn)(mfile, m, FALSE); 5254863Seric (void) fclose(mfile); 5264863Seric 5274863Seric i = endmailer(pid, pvp[0]); 5284863Seric giveresponse(i, TRUE, m); 5295981Seric 5305981Seric /* arrange a return receipt if requested */ 5315981Seric if (RetReceipt && bitset(M_LOCAL, m->m_flags) && i == EX_OK) 5325981Seric { 5335981Seric SendReceipt = TRUE; 5345981Seric fprintf(Xscript, "%s... successfully delivered\n", To); 5355981Seric /* do we want to send back more info? */ 5365981Seric } 5375981Seric 5384863Seric return (i); 5394863Seric } 5404863Seric /* 5414863Seric ** ENDMAILER -- Wait for mailer to terminate. 5424863Seric ** 5434863Seric ** We should never get fatal errors (e.g., segmentation 5444863Seric ** violation), so we report those specially. For other 5454863Seric ** errors, we choose a status message (into statmsg), 5464863Seric ** and if it represents an error, we print it. 5474863Seric ** 5484863Seric ** Parameters: 5494863Seric ** pid -- pid of mailer. 5504863Seric ** name -- name of mailer (for error messages). 5514863Seric ** 5524863Seric ** Returns: 5534863Seric ** exit code of mailer. 5544863Seric ** 5554863Seric ** Side Effects: 5564863Seric ** none. 5574863Seric */ 5584863Seric 5594863Seric endmailer(pid, name) 5604863Seric int pid; 5614863Seric char *name; 5624863Seric { 5634863Seric register int i; 5644863Seric auto int st; 5654863Seric 5666038Seric /* in the IPC case there is nothing to wait for */ 5676038Seric if (pid == 0) 5686038Seric return (EX_OK); 5696038Seric 5706038Seric /* wait for the mailer process to die and collect status */ 5714863Seric while ((i = wait(&st)) > 0 && i != pid) 5724863Seric continue; 5734863Seric if (i < 0) 5744863Seric { 5754863Seric syserr("wait"); 5764863Seric return (-1); 5774863Seric } 5786038Seric 5796038Seric /* see if it died a horrid death */ 5804863Seric if ((st & 0377) != 0) 5814863Seric { 5824863Seric syserr("%s: stat %o", name, st); 5834863Seric ExitStat = EX_UNAVAILABLE; 5844863Seric return (-1); 5854863Seric } 5866038Seric 5876038Seric /* normal death -- return status */ 5884863Seric i = (st >> 8) & 0377; 5894863Seric return (i); 5904863Seric } 5914863Seric /* 5924863Seric ** OPENMAILER -- open connection to mailer. 5934863Seric ** 5944863Seric ** Parameters: 5954863Seric ** m -- mailer descriptor. 5964863Seric ** pvp -- parameter vector to pass to mailer. 5974863Seric ** ctladdr -- controlling address for user. 5984863Seric ** clever -- create a full duplex connection. 5994863Seric ** pmfile -- pointer to mfile (to mailer) connection. 6004863Seric ** prfile -- pointer to rfile (from mailer) connection. 6014863Seric ** 6024863Seric ** Returns: 6036038Seric ** pid of mailer ( > 0 ). 6044863Seric ** -1 on error. 6056038Seric ** zero on an IPC connection. 6064863Seric ** 6074863Seric ** Side Effects: 6084863Seric ** creates a mailer in a subprocess. 6094863Seric */ 6104863Seric 6114863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6124863Seric struct mailer *m; 6134863Seric char **pvp; 6144863Seric ADDRESS *ctladdr; 6154863Seric bool clever; 6164863Seric FILE **pmfile; 6174863Seric FILE **prfile; 6184863Seric { 6194863Seric int pid; 6204709Seric int mpvect[2]; 6214863Seric int rpvect[2]; 6223233Seric FILE *mfile; 6234863Seric FILE *rfile; 6243233Seric extern FILE *fdopen(); 6253233Seric 6263233Seric # ifdef DEBUG 6273233Seric if (Debug) 628294Seric { 6294863Seric printf("openmailer:\n"); 6303233Seric printav(pvp); 631294Seric } 6323233Seric # endif DEBUG 6334488Seric errno = 0; 6343233Seric 6356038Seric # ifdef DAEMON 6366038Seric /* 6376038Seric ** Deal with the special case of mail handled through an IPC 6386038Seric ** connection. 6396038Seric ** In this case we don't actually fork. We must be 6406038Seric ** running SMTP for this to work. We will return a 6416038Seric ** zero pid to indicate that we are running IPC. 6426038Seric */ 6436038Seric 6446038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6456038Seric { 6466038Seric register int i; 6476038Seric 6486038Seric if (!clever) 6496038Seric syserr("non-clever IPC"); 6506632Seric if (pvp[2] != NULL) 6516632Seric i = atoi(pvp[2]); 6526632Seric else 6536632Seric i = 0; 6546632Seric i = makeconnection(pvp[1], i, pmfile, prfile); 6556038Seric if (i != EX_OK) 6566047Seric { 6576047Seric ExitStat = i; 6586038Seric return (-1); 6596047Seric } 6606038Seric else 6616038Seric return (0); 6626038Seric } 6636038Seric # endif DAEMON 6646038Seric 6652898Seric /* create a pipe to shove the mail through */ 6664709Seric if (pipe(mpvect) < 0) 667294Seric { 6684863Seric syserr("pipe (to mailer)"); 669294Seric return (-1); 670294Seric } 6714863Seric 6725179Seric # ifdef SMTP 6734863Seric /* if this mailer speaks smtp, create a return pipe */ 6744863Seric if (clever && pipe(rpvect) < 0) 6754863Seric { 6764863Seric syserr("pipe (from mailer)"); 6774863Seric (void) close(mpvect[0]); 6784863Seric (void) close(mpvect[1]); 6794863Seric return (-1); 6804863Seric } 6815179Seric # endif SMTP 6824863Seric 6836038Seric /* 6846038Seric ** Actually fork the mailer process. 6856038Seric ** DOFORK is clever about retrying. 6866038Seric */ 6876038Seric 6884214Seric DOFORK(XFORK); 6894327Seric /* pid is set by DOFORK */ 690294Seric if (pid < 0) 691294Seric { 6926038Seric /* failure */ 693294Seric syserr("Cannot fork"); 6944709Seric (void) close(mpvect[0]); 6954709Seric (void) close(mpvect[1]); 6964863Seric if (clever) 6974863Seric { 6984863Seric (void) close(rpvect[0]); 6994863Seric (void) close(rpvect[1]); 7004863Seric } 701294Seric return (-1); 702294Seric } 703294Seric else if (pid == 0) 704294Seric { 705294Seric /* child -- set up input & exec mailer */ 7061621Seric /* make diagnostic output be standard output */ 7074477Seric (void) signal(SIGINT, SIG_IGN); 7084477Seric (void) signal(SIGHUP, SIG_IGN); 7094215Seric (void) signal(SIGTERM, SIG_DFL); 7104709Seric 7114709Seric /* arrange to filter standard & diag output of command */ 7124863Seric if (clever) 7134709Seric { 7144863Seric (void) close(rpvect[0]); 7154709Seric (void) close(1); 7164863Seric (void) dup(rpvect[1]); 7174863Seric (void) close(rpvect[1]); 7184863Seric } 7194863Seric else if (OutChannel != stdout) 7204863Seric { 7214863Seric (void) close(1); 7224709Seric (void) dup(fileno(OutChannel)); 7234709Seric } 7244082Seric (void) close(2); 7254082Seric (void) dup(1); 7264709Seric 7274709Seric /* arrange to get standard input */ 7284709Seric (void) close(mpvect[1]); 7294082Seric (void) close(0); 7304709Seric if (dup(mpvect[0]) < 0) 731294Seric { 7322898Seric syserr("Cannot dup to zero!"); 7332898Seric _exit(EX_OSERR); 734294Seric } 7354709Seric (void) close(mpvect[0]); 7362968Seric if (!bitset(M_RESTR, m->m_flags)) 7374215Seric { 7384417Seric if (ctladdr->q_uid == 0) 7394417Seric { 7404417Seric (void) setgid(DefGid); 7414417Seric (void) setuid(DefUid); 7424417Seric } 7434417Seric else 7444415Seric { 7454417Seric (void) setgid(ctladdr->q_gid); 7464417Seric (void) setuid(ctladdr->q_uid); 7474415Seric } 7484215Seric } 7492774Seric # ifndef VFORK 7502774Seric /* 7512774Seric ** We have to be careful with vfork - we can't mung up the 7522774Seric ** memory but we don't want the mailer to inherit any extra 7532774Seric ** open files. Chances are the mailer won't 7542774Seric ** care about an extra file, but then again you never know. 7552774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7562774Seric ** declared static so we can't. But if we fclose(pwf), which 7572774Seric ** is what endpwent does, it closes it in the parent too and 7582774Seric ** the next getpwnam will be slower. If you have a weird 7592774Seric ** mailer that chokes on the extra file you should do the 7602774Seric ** endpwent(). 7612774Seric ** 7622774Seric ** Similar comments apply to log. However, openlog is 7632774Seric ** clever enough to set the FIOCLEX mode on the file, 7642774Seric ** so it will be closed automatically on the exec. 7652774Seric */ 7662774Seric 7672774Seric endpwent(); 768294Seric # ifdef LOG 7692089Seric closelog(); 770294Seric # endif LOG 7712774Seric # endif VFORK 7726038Seric 7736038Seric /* try to execute the mailer */ 774294Seric execv(m->m_mailer, pvp); 7756038Seric 776294Seric /* syserr fails because log is closed */ 777294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 7784214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 7794082Seric (void) fflush(stdout); 7801619Seric _exit(EX_UNAVAILABLE); 781294Seric } 782294Seric 7834709Seric /* 7844863Seric ** Set up return value. 7854709Seric */ 7864709Seric 7874709Seric (void) close(mpvect[0]); 7884709Seric mfile = fdopen(mpvect[1], "w"); 7894863Seric if (clever) 7904863Seric { 7914863Seric (void) close(rpvect[1]); 7924863Seric rfile = fdopen(rpvect[0], "r"); 7934863Seric } 794294Seric 7954863Seric *pmfile = mfile; 7964863Seric *prfile = rfile; 797294Seric 7984863Seric return (pid); 799294Seric } 800294Seric /* 801294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 802294Seric ** 803294Seric ** Parameters: 804294Seric ** stat -- the status code from the mailer (high byte 805294Seric ** only; core dumps must have been taken care of 806294Seric ** already). 807294Seric ** force -- if set, force an error message output, even 808294Seric ** if the mailer seems to like to print its own 809294Seric ** messages. 810294Seric ** m -- the mailer descriptor for this mailer. 811294Seric ** 812294Seric ** Returns: 8134082Seric ** none. 814294Seric ** 815294Seric ** Side Effects: 8161518Seric ** Errors may be incremented. 817294Seric ** ExitStat may be set. 818294Seric */ 819294Seric 820294Seric giveresponse(stat, force, m) 821294Seric int stat; 822294Seric int force; 823294Seric register struct mailer *m; 824294Seric { 825294Seric register char *statmsg; 826294Seric extern char *SysExMsg[]; 827294Seric register int i; 828294Seric extern int N_SysEx; 8291624Seric char buf[30]; 830294Seric 8314315Seric /* 8324315Seric ** Compute status message from code. 8334315Seric */ 8344315Seric 835294Seric i = stat - EX__BASE; 836294Seric if (i < 0 || i > N_SysEx) 837294Seric statmsg = NULL; 838294Seric else 839294Seric statmsg = SysExMsg[i]; 840294Seric if (stat == 0) 8414065Seric { 8424194Seric if (bitset(M_LOCAL, m->m_flags)) 8434161Seric statmsg = "delivered"; 8444161Seric else 8454161Seric statmsg = "queued"; 8464065Seric if (Verbose) 8474166Seric message(Arpa_Info, statmsg); 8484065Seric } 8495179Seric # ifdef QUEUE 8504621Seric else if (stat == EX_TEMPFAIL) 8514621Seric { 8524621Seric if (Verbose) 8534621Seric message(Arpa_Info, "transmission deferred"); 8544621Seric } 8555179Seric # endif QUEUE 856294Seric else 857294Seric { 8581518Seric Errors++; 8596047Seric FatalErrors = TRUE; 860294Seric if (statmsg == NULL && m->m_badstat != 0) 861294Seric { 862294Seric stat = m->m_badstat; 863294Seric i = stat - EX__BASE; 864294Seric # ifdef DEBUG 865294Seric if (i < 0 || i >= N_SysEx) 866294Seric syserr("Bad m_badstat %d", stat); 867294Seric else 868294Seric # endif DEBUG 869294Seric statmsg = SysExMsg[i]; 870294Seric } 871294Seric if (statmsg == NULL) 872294Seric usrerr("unknown mailer response %d", stat); 8734065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 874294Seric usrerr("%s", statmsg); 875294Seric } 876294Seric 877294Seric /* 878294Seric ** Final cleanup. 879294Seric ** Log a record of the transaction. Compute the new 880294Seric ** ExitStat -- if we already had an error, stick with 881294Seric ** that. 882294Seric */ 883294Seric 8841624Seric if (statmsg == NULL) 8851624Seric { 8864082Seric (void) sprintf(buf, "error %d", stat); 8871624Seric statmsg = buf; 8881624Seric } 8891624Seric 890294Seric # ifdef LOG 8912774Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 892294Seric # endif LOG 8935179Seric # ifdef QUEUE 8944621Seric if (stat != EX_TEMPFAIL) 8955179Seric # endif QUEUE 8964621Seric setstat(stat); 897294Seric } 898294Seric /* 8992898Seric ** PUTMESSAGE -- output a message to the final mailer. 900294Seric ** 9012898Seric ** This routine takes care of recreating the header from the 9022898Seric ** in-core copy, etc. 903294Seric ** 904294Seric ** Parameters: 9052898Seric ** fp -- file to output onto. 9062898Seric ** m -- a mailer descriptor. 9074863Seric ** xdot -- if set, hide lines beginning with dot. 908294Seric ** 909294Seric ** Returns: 9102898Seric ** none. 911294Seric ** 912294Seric ** Side Effects: 9132898Seric ** The message is written onto fp. 914294Seric */ 915294Seric 9164863Seric putmessage(fp, m, xdot) 9172898Seric FILE *fp; 9182898Seric struct mailer *m; 9194863Seric bool xdot; 920294Seric { 9212898Seric char buf[BUFSIZ]; 922294Seric 9234315Seric /* 9244315Seric ** Output "From" line unless supressed 9255099Seric ** 9265099Seric ** >>>>>>>>>> One of the ugliest hacks seen by human eyes is 9275099Seric ** >>>>>>>>>> contained herein: UUCP wants those stupid 9286041Seric ** >> NOTE >> "remote from <host>" lines. Why oh why does a 9296041Seric ** >>>>>>>>>> well-meaning programmer such as myself have to 9305099Seric ** >>>>>>>>>> deal with this kind of antique garbage???? 9314315Seric */ 9324315Seric 9333186Seric if (!bitset(M_NHDR, m->m_flags)) 9344205Seric { 9355179Seric # ifdef UGLYUUCP 9365599Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9376041Seric { 9386041Seric extern char *macvalue(); 9396041Seric char *sys = macvalue('g'); 9406041Seric char *bang = index(sys, '!'); 9416041Seric 9426041Seric if (bang == NULL) 9436041Seric syserr("No ! in UUCP! (%s)", sys); 9446041Seric else 9456041Seric *bang = '\0'; 9466041Seric (void) expand("From $f $d remote from $g", buf, 9475099Seric &buf[sizeof buf - 1]); 9486041Seric *bang = '!'; 9496041Seric } 9505099Seric else 9515179Seric # endif UGLYUUCP 9525099Seric (void) expand("$l", buf, &buf[sizeof buf - 1]); 9534205Seric fprintf(fp, "%s\n", buf); 9544205Seric } 9553186Seric 9564315Seric /* 9574315Seric ** Output all header lines 9584315Seric */ 9594315Seric 9605981Seric putheader(fp, m); 9615981Seric 9625981Seric /* 9635981Seric ** Output the body of the message 9645981Seric */ 9655981Seric 9665981Seric if (TempFile != NULL) 9675981Seric { 9685981Seric rewind(TempFile); 9695981Seric while (!ferror(fp) && fgets(buf, sizeof buf, TempFile) != NULL) 9705981Seric fprintf(fp, "%s%s", xdot && buf[0] == '.' ? "." : "", buf); 9715981Seric 9725981Seric if (ferror(TempFile)) 9735981Seric { 9745981Seric syserr("putmessage: read error"); 9756047Seric ExitStat = EX_IOERR; 9765981Seric } 9775981Seric } 9785981Seric 9795981Seric (void) fflush(fp); 9805981Seric if (ferror(fp) && errno != EPIPE) 9815981Seric { 9825981Seric syserr("putmessage: write error"); 9836047Seric ExitStat = EX_IOERR; 9845981Seric } 9855981Seric errno = 0; 9865981Seric } 9875981Seric /* 9885981Seric ** PUTHEADER -- put the header part of a message 9895981Seric ** 9905981Seric ** Parameters: 9915981Seric ** fp -- file to put it on. 9925981Seric ** m -- mailer to use. 9935981Seric ** 9945981Seric ** Returns: 9955981Seric ** none. 9965981Seric ** 9975981Seric ** Side Effects: 9985981Seric ** none. 9995981Seric */ 10005981Seric 10015981Seric putheader(fp, m) 10025981Seric register FILE *fp; 10035981Seric register struct mailer *m; 10045981Seric { 10055981Seric char buf[BUFSIZ]; 10065981Seric register HDR *h; 10075981Seric extern char *arpadate(); 10085981Seric bool anyheader = FALSE; 10095981Seric extern char *capitalize(); 10105981Seric extern char *hvalue(); 10115981Seric extern bool samefrom(); 10125981Seric char *of_line; 10135981Seric 10144447Seric of_line = hvalue("original-from"); 10152898Seric for (h = Header; h != NULL; h = h->h_link) 10161828Seric { 10174315Seric register char *p; 10184370Seric char *origfrom = OrigFrom; 10194447Seric bool nooutput; 10204315Seric 10214447Seric nooutput = FALSE; 10223389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 10234447Seric nooutput = TRUE; 10244447Seric 10254447Seric /* use From: line from message if generated is the same */ 10264370Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 10274447Seric strcmp(m->m_from, "$f") == 0 && of_line == NULL) 10283385Seric { 10294370Seric p = origfrom; 10304370Seric origfrom = NULL; 10314370Seric } 10324370Seric else if (bitset(H_DEFAULT, h->h_flags)) 10334370Seric { 10344082Seric (void) expand(h->h_value, buf, &buf[sizeof buf]); 10353385Seric p = buf; 10363385Seric } 10375913Seric else if (bitset(H_ADDR, h->h_flags)) 10385913Seric { 10395913Seric register int opos; 10405913Seric bool firstone = TRUE; 10415913Seric 10425913Seric /* 10435913Seric ** Output the address list translated by the 10445913Seric ** mailer and with commas. 10455913Seric */ 10465913Seric 10475913Seric p = h->h_value; 10485913Seric if (p == NULL || *p == '\0' || nooutput) 10495913Seric continue; 10505913Seric fprintf(fp, "%s: ", capitalize(h->h_field)); 10515913Seric opos = strlen(h->h_field) + 2; 10525913Seric while (*p != '\0') 10535913Seric { 10545913Seric register char *name = p; 10555913Seric extern char *remotename(); 10565913Seric char savechar; 10575913Seric 10585913Seric /* find the end of the name */ 10595936Seric while (*p != '\0' && *p != ',') 10605936Seric { 10615936Seric extern bool isatword(); 10625936Seric char *oldp; 10635936Seric 10645936Seric if (!OldStyle || !isspace(*p)) 10655936Seric { 10665936Seric p++; 10675936Seric continue; 10685936Seric } 10695936Seric oldp = p; 10705936Seric while (*p != '\0' && isspace(*p)) 10715936Seric p++; 10725936Seric if (*p != '@' && !isatword(p)) 10735936Seric { 10745936Seric p = oldp; 10755936Seric break; 10765936Seric } 10775936Seric p += *p == '@' ? 1 : 2; 10785936Seric while (*p != '\0' && isspace(*p)) 10795936Seric p++; 10805936Seric } 10815913Seric savechar = *p; 10825913Seric *p = '\0'; 10835913Seric 10845913Seric /* translate the name to be relative */ 1085*6820Seric name = remotename(name, m, FALSE); 10865913Seric if (*name == '\0') 10875913Seric continue; 10885913Seric 10895913Seric /* output the name with nice formatting */ 10905913Seric opos += strlen(name); 10915913Seric if (!firstone) 10925913Seric opos += 2; 10935913Seric if (opos > 78 && !firstone) 10945913Seric { 10955913Seric fprintf(fp, ",\n "); 10965916Seric opos = 8 + strlen(name); 10975913Seric } 10985913Seric else if (!firstone) 10995913Seric fprintf(fp, ", "); 11005913Seric fprintf(fp, "%s", name); 11015913Seric firstone = FALSE; 11025913Seric 11035913Seric /* clean up the source string */ 11045913Seric *p = savechar; 11055913Seric while (*p != '\0' && (isspace(*p) || *p == ',')) 11065913Seric p++; 11075913Seric } 11085913Seric fprintf(fp, "\n"); 11095913Seric nooutput = TRUE; 11105913Seric } 11112898Seric else 11123385Seric p = h->h_value; 11134447Seric if (p == NULL || *p == '\0') 11143389Seric continue; 11154209Seric 11164209Seric /* hack, hack -- output Original-From field if different */ 11174447Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL) 11184209Seric { 11194447Seric /* output new Original-From line if needed */ 11204447Seric if (of_line == NULL && !samefrom(p, origfrom)) 11214447Seric { 11224447Seric fprintf(fp, "Original-From: %s\n", origfrom); 11234447Seric anyheader = TRUE; 11244447Seric } 11254447Seric if (of_line != NULL && !nooutput && samefrom(p, of_line)) 11264447Seric { 11274447Seric /* delete Original-From: line if redundant */ 11284447Seric p = of_line; 11294447Seric of_line = NULL; 11304447Seric } 11314447Seric } 11324447Seric else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL) 11334447Seric nooutput = TRUE; 11344447Seric 11354447Seric /* finally, output the header line */ 11364447Seric if (!nooutput) 11374447Seric { 11384447Seric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 11394447Seric h->h_flags |= H_USED; 11404370Seric anyheader = TRUE; 11414209Seric } 11422898Seric } 11432898Seric if (anyheader) 11442898Seric fprintf(fp, "\n"); 1145294Seric } 1146294Seric /* 11475936Seric ** ISATWORD -- tell if the word we are pointing to is "at". 11485936Seric ** 11495936Seric ** Parameters: 11505936Seric ** p -- word to check. 11515936Seric ** 11525936Seric ** Returns: 11535936Seric ** TRUE -- if p is the word at. 11545936Seric ** FALSE -- otherwise. 11555936Seric ** 11565936Seric ** Side Effects: 11575936Seric ** none. 11585936Seric */ 11595936Seric 11605936Seric bool 11615936Seric isatword(p) 11625936Seric register char *p; 11635936Seric { 11645936Seric extern char lower(); 11655936Seric 11665936Seric if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 11675936Seric p[2] != '\0' && isspace(p[2])) 11685936Seric return (TRUE); 11695936Seric return (FALSE); 11705936Seric } 11715936Seric /* 11725913Seric ** REMOTENAME -- return the name relative to the current mailer 11735913Seric ** 11745913Seric ** Parameters: 11755913Seric ** name -- the name to translate. 1176*6820Seric ** force -- if set, forces rewriting even if the mailer 1177*6820Seric ** does not request it. Used for rewriting 1178*6820Seric ** sender addresses. 11795913Seric ** 11805913Seric ** Returns: 11815913Seric ** the text string representing this address relative to 11825913Seric ** the receiving mailer. 11835913Seric ** 11845913Seric ** Side Effects: 11855913Seric ** none. 11865913Seric ** 11875913Seric ** Warnings: 11885913Seric ** The text string returned is tucked away locally; 11895913Seric ** copy it if you intend to save it. 11905913Seric */ 11915913Seric 11925913Seric char * 1193*6820Seric remotename(name, m, force) 11945913Seric char *name; 11955916Seric struct mailer *m; 1196*6820Seric bool force; 11975913Seric { 11985913Seric static char buf[MAXNAME]; 11995913Seric char lbuf[MAXNAME]; 12005913Seric extern char *macvalue(); 12015913Seric char *oldf = macvalue('f'); 12025916Seric char *oldx = macvalue('x'); 12035916Seric char *oldg = macvalue('g'); 12045913Seric extern char **prescan(); 12055913Seric register char **pvp; 12065916Seric extern char *getxpart(); 12075913Seric 12085913Seric /* 1209*6820Seric ** See if this mailer wants the name to be rewritten. There are 1210*6820Seric ** many problems here, owing to the standards for doing replies. 1211*6820Seric ** In general, these names should only be rewritten if we are 1212*6820Seric ** sending to another host that runs sendmail. 1213*6820Seric */ 1214*6820Seric 1215*6820Seric if (!bitset(M_RELRCPT, m->m_flags) && !force) 1216*6820Seric return; 1217*6820Seric 1218*6820Seric /* 12195913Seric ** Do general rewriting of name. 12205913Seric ** This will also take care of doing global name translation. 12215913Seric */ 12225913Seric 12235916Seric define('x', getxpart(name)); 12245913Seric pvp = prescan(name, '\0'); 12255913Seric for (;;) 12265913Seric { 12275913Seric rewrite(pvp, 1); 12285913Seric rewrite(pvp, 3); 12295913Seric if (**pvp == CANONNET) 12305913Seric { 12315913Seric auto ADDRESS a; 12325913Seric register char *p; 12335913Seric extern char *hostalias(); 12345913Seric 12355913Seric /* oops... resolved to something */ 12365913Seric if (buildaddr(pvp, &a) == NULL) 12375913Seric return (name); 12385913Seric p = hostalias(&a); 12395913Seric if (p == NULL) 12405913Seric return (name); 12415913Seric pvp = prescan(p, '\0'); 12425913Seric } 12435913Seric else 12445913Seric { 12455913Seric cataddr(pvp, lbuf, sizeof lbuf); 12465913Seric break; 12475913Seric } 12485913Seric } 12495913Seric 12505913Seric /* make the name relative to the receiving mailer */ 12515913Seric define('f', lbuf); 12525916Seric (void) expand(m->m_from, buf, &buf[sizeof buf - 1]); 12535913Seric 12545913Seric /* rewrite to get rid of garbage we added in the expand above */ 12555913Seric pvp = prescan(buf, '\0'); 12565913Seric rewrite(pvp, 2); 12575916Seric cataddr(pvp, lbuf, sizeof lbuf); 12585913Seric 12595916Seric /* now add any comment info we had before back */ 12605916Seric define('g', lbuf); 12615916Seric (void) expand("$q", buf, &buf[sizeof buf - 1]); 12625916Seric 12635913Seric define('f', oldf); 12645916Seric define('g', oldg); 12655916Seric define('x', oldx); 12665913Seric 12675913Seric # ifdef DEBUG 12685913Seric if (Debug > 0) 12695913Seric printf("remotename(%s) => `%s'\n", name, buf); 12705913Seric # endif DEBUG 12715913Seric return (buf); 12725913Seric } 12735913Seric /* 12744370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 12754370Seric ** 12764370Seric ** Parameters: 12774370Seric ** ifrom -- internally generated form of from address. 12784370Seric ** efrom -- external form of from address. 12794370Seric ** 12804370Seric ** Returns: 12814370Seric ** TRUE -- if they convey the same info. 12824370Seric ** FALSE -- if any information has been lost. 12834370Seric ** 12844370Seric ** Side Effects: 12854370Seric ** none. 12864370Seric */ 12874370Seric 12884370Seric bool 12894370Seric samefrom(ifrom, efrom) 12904370Seric char *ifrom; 12914370Seric char *efrom; 12924370Seric { 12934447Seric register char *p; 12944447Seric char buf[MAXNAME + 4]; 12954447Seric 12964447Seric # ifdef DEBUG 12974447Seric if (Debug > 7) 12984447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 12994447Seric # endif DEBUG 13004447Seric if (strcmp(ifrom, efrom) == 0) 13014447Seric goto success; 13024447Seric p = index(ifrom, '@'); 13034447Seric if (p == NULL) 13044447Seric goto failure; 13054447Seric *p = '\0'; 13064447Seric strcpy(buf, ifrom); 13074447Seric strcat(buf, " at "); 13084447Seric *p++ = '@'; 13094447Seric strcat(buf, p); 13104447Seric if (strcmp(buf, efrom) == 0) 13114447Seric goto success; 13124447Seric 13134447Seric failure: 13144447Seric # ifdef DEBUG 13154447Seric if (Debug > 7) 13164447Seric printf("FALSE\n"); 13174447Seric # endif DEBUG 13184447Seric return (FALSE); 13194447Seric 13204447Seric success: 13214447Seric # ifdef DEBUG 13224447Seric if (Debug > 7) 13234447Seric printf("TRUE\n"); 13244447Seric # endif DEBUG 13254447Seric return (TRUE); 13264370Seric } 13274370Seric /* 1328294Seric ** MAILFILE -- Send a message to a file. 1329294Seric ** 13304327Seric ** If the file has the setuid/setgid bits set, but NO execute 13314327Seric ** bits, sendmail will try to become the owner of that file 13324327Seric ** rather than the real user. Obviously, this only works if 13334327Seric ** sendmail runs as root. 13344327Seric ** 1335294Seric ** Parameters: 1336294Seric ** filename -- the name of the file to send to. 13374397Seric ** ctladdr -- the controlling address header -- includes 13384397Seric ** the userid/groupid to be when sending. 1339294Seric ** 1340294Seric ** Returns: 1341294Seric ** The exit code associated with the operation. 1342294Seric ** 1343294Seric ** Side Effects: 1344294Seric ** none. 1345294Seric */ 1346294Seric 13474397Seric mailfile(filename, ctladdr) 1348294Seric char *filename; 13494397Seric ADDRESS *ctladdr; 1350294Seric { 1351294Seric register FILE *f; 13524214Seric register int pid; 1353294Seric 13544214Seric /* 13554214Seric ** Fork so we can change permissions here. 13564214Seric ** Note that we MUST use fork, not vfork, because of 13574214Seric ** the complications of calling subroutines, etc. 13584214Seric */ 13594067Seric 13604214Seric DOFORK(fork); 13614214Seric 13624214Seric if (pid < 0) 13634214Seric return (EX_OSERR); 13644214Seric else if (pid == 0) 13654214Seric { 13664214Seric /* child -- actually write to file */ 13674327Seric struct stat stb; 13684327Seric 13694215Seric (void) signal(SIGINT, SIG_DFL); 13704215Seric (void) signal(SIGHUP, SIG_DFL); 13714215Seric (void) signal(SIGTERM, SIG_DFL); 13724327Seric umask(OldUmask); 13734327Seric if (stat(filename, &stb) < 0) 13744431Seric stb.st_mode = 0666; 13754327Seric if (bitset(0111, stb.st_mode)) 13764327Seric exit(EX_CANTCREAT); 13774401Seric if (ctladdr == NULL) 13784401Seric ctladdr = &From; 13794327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 13804417Seric { 13814417Seric if (ctladdr->q_uid == 0) 13824417Seric (void) setgid(DefGid); 13834417Seric else 13844417Seric (void) setgid(ctladdr->q_gid); 13854417Seric } 13864327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 13874417Seric { 13884417Seric if (ctladdr->q_uid == 0) 13894417Seric (void) setuid(DefUid); 13904417Seric else 13914417Seric (void) setuid(ctladdr->q_uid); 13924417Seric } 13934214Seric f = fopen(filename, "a"); 13944214Seric if (f == NULL) 13954214Seric exit(EX_CANTCREAT); 13964214Seric 13974863Seric putmessage(f, Mailer[1], FALSE); 13984214Seric fputs("\n", f); 13994214Seric (void) fclose(f); 14004214Seric (void) fflush(stdout); 14014417Seric 14024417Seric /* reset ISUID & ISGID bits */ 14034621Seric (void) chmod(filename, (int) stb.st_mode); 14044214Seric exit(EX_OK); 14054315Seric /*NOTREACHED*/ 14064214Seric } 14074214Seric else 14084214Seric { 14094214Seric /* parent -- wait for exit status */ 14104214Seric register int i; 14114214Seric auto int stat; 14124214Seric 14134214Seric while ((i = wait(&stat)) != pid) 14144214Seric { 14154214Seric if (i < 0) 14164214Seric { 14174214Seric stat = EX_OSERR << 8; 14184214Seric break; 14194214Seric } 14204214Seric } 14214215Seric if ((stat & 0377) != 0) 14224215Seric stat = EX_UNAVAILABLE << 8; 14234214Seric return ((stat >> 8) & 0377); 14244214Seric } 1425294Seric } 14264550Seric /* 14274550Seric ** SENDALL -- actually send all the messages. 14284550Seric ** 14294550Seric ** Parameters: 14304550Seric ** verifyonly -- if set, only give verification messages. 14314550Seric ** 14324550Seric ** Returns: 14334550Seric ** none. 14344550Seric ** 14354550Seric ** Side Effects: 14364550Seric ** Scans the send lists and sends everything it finds. 14374550Seric */ 14384550Seric 14394550Seric sendall(verifyonly) 14404550Seric bool verifyonly; 14414550Seric { 14425008Seric register ADDRESS *q; 14434550Seric typedef int (*fnptr)(); 14444550Seric 14455032Seric # ifdef DEBUG 14465032Seric if (Debug > 1) 14475032Seric { 14485032Seric printf("\nSendQueue:\n"); 14495032Seric printaddr(SendQueue, TRUE); 14505032Seric } 14515032Seric # endif DEBUG 14525008Seric 14535008Seric for (q = SendQueue; q != NULL; q = q->q_next) 14544550Seric { 14555008Seric if (verifyonly) 14564550Seric { 14575008Seric To = q->q_paddr; 14585008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14594550Seric { 14605008Seric if (bitset(M_LOCAL, q->q_mailer->m_flags)) 14615008Seric message(Arpa_Info, "deliverable"); 14625008Seric else 14635008Seric message(Arpa_Info, "queueable"); 14644550Seric } 14654550Seric } 14665008Seric else 14675008Seric (void) deliver(q, (fnptr) NULL); 14684550Seric } 14694550Seric } 1470