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*7048Seric SCCSID(@(#)deliver.c 3.84 06/07/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 ** 24294Seric ** Returns: 25294Seric ** zero -- successfully delivered. 26294Seric ** else -- some failure, see ExitStat for more info. 27294Seric ** 28294Seric ** Side Effects: 29294Seric ** The standard input is passed off to someone. 30294Seric */ 31294Seric 326974Seric deliver(firstto) 334621Seric ADDRESS *firstto; 34294Seric { 354452Seric char *host; /* host being sent to */ 364452Seric char *user; /* user being sent to */ 37294Seric char **pvp; 383233Seric register char **mvp; 393233Seric register char *p; 404452Seric register struct mailer *m; /* mailer for this recipient */ 41294Seric register int i; 422968Seric extern bool checkcompat(); 433233Seric char *pv[MAXPV+1]; 444452Seric char tobuf[MAXLINE]; /* text line of to people */ 453233Seric char buf[MAXNAME]; 464397Seric ADDRESS *ctladdr; 474397Seric extern ADDRESS *getctladdr(); 484452Seric char tfrombuf[MAXNAME]; /* translated from person */ 494452Seric extern char **prescan(); 504621Seric register ADDRESS *to = firstto; 514863Seric bool clever = FALSE; /* running user smtp to this mailer */ 524863Seric bool tempfail = FALSE; 535032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 54294Seric 554488Seric errno = 0; 565008Seric if (!ForceMail && bitset(QDONTSEND, to->q_flags)) 573233Seric return (0); 58294Seric 596974Seric m = to->q_mailer; 606974Seric host = to->q_host; 616974Seric 62294Seric # ifdef DEBUG 63294Seric if (Debug) 643233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 656974Seric m->m_mno, host, to->q_user); 66294Seric # endif DEBUG 676974Seric if (Verbose) 686974Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 69294Seric 70294Seric /* 715903Seric ** If this mailer is expensive, and if we don't want to make 725903Seric ** connections now, just mark these addresses and return. 735903Seric ** This is useful if we want to batch connections to 745903Seric ** reduce load. This will cause the messages to be 755903Seric ** queued up, and a daemon will come along to send the 765903Seric ** messages later. 775903Seric ** This should be on a per-mailer basis. 785903Seric */ 795903Seric 805903Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags)) 815903Seric { 825903Seric for (; to != NULL; to = to->q_next) 835903Seric if (!bitset(QDONTSEND, to->q_flags)) 845903Seric to->q_flags |= QQUEUEUP|QDONTSEND; 855903Seric return (0); 865903Seric } 875903Seric 885903Seric /* 893233Seric ** Do initial argv setup. 903233Seric ** Insert the mailer name. Notice that $x expansion is 913233Seric ** NOT done on the mailer name. Then, if the mailer has 923233Seric ** a picky -f flag, we insert it as appropriate. This 933233Seric ** code does not check for 'pv' overflow; this places a 943233Seric ** manifest lower limit of 4 for MAXPV. 955903Seric ** We rewrite the from address here, being careful 965903Seric ** to also rewrite it again using ruleset 2 to 975903Seric ** eliminate redundancies. 982968Seric */ 992968Seric 1004452Seric /* rewrite from address, using rewriting rules */ 1016974Seric expand(m->m_from, buf, &buf[sizeof buf - 1], CurEnv); 1024452Seric mvp = prescan(buf, '\0'); 1034452Seric if (mvp == NULL) 1044452Seric { 1054452Seric syserr("bad mailer from translate \"%s\"", buf); 1064452Seric return (EX_SOFTWARE); 1074452Seric } 1084452Seric rewrite(mvp, 2); 1094452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 1104452Seric 1114452Seric define('g', tfrombuf); /* translated sender address */ 1123233Seric define('h', host); /* to host */ 1133233Seric Errors = 0; 1143233Seric pvp = pv; 1153233Seric *pvp++ = m->m_argv[0]; 1162968Seric 1173233Seric /* insert -f or -r flag as appropriate */ 1183233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1193233Seric { 1203233Seric if (bitset(M_FOPT, m->m_flags)) 1213233Seric *pvp++ = "-f"; 1223233Seric else 1233233Seric *pvp++ = "-r"; 1246974Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1253233Seric *pvp++ = newstr(buf); 1263233Seric } 127294Seric 128294Seric /* 1293233Seric ** Append the other fixed parts of the argv. These run 1303233Seric ** up to the first entry containing "$u". There can only 1313233Seric ** be one of these, and there are only a few more slots 1323233Seric ** in the pv after it. 133294Seric */ 134294Seric 1353233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 136294Seric { 1373233Seric while ((p = index(p, '$')) != NULL) 1383233Seric if (*++p == 'u') 1393233Seric break; 1403233Seric if (p != NULL) 1413233Seric break; 1423233Seric 1433233Seric /* this entry is safe -- go ahead and process it */ 1446974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 1453233Seric *pvp++ = newstr(buf); 1463233Seric if (pvp >= &pv[MAXPV - 3]) 1473233Seric { 1483233Seric syserr("Too many parameters to %s before $u", pv[0]); 1493233Seric return (-1); 1503233Seric } 151294Seric } 1524863Seric 1536038Seric /* 1546038Seric ** If we have no substitution for the user name in the argument 1556038Seric ** list, we know that we must supply the names otherwise -- and 1566038Seric ** SMTP is the answer!! 1576038Seric */ 1586038Seric 1593233Seric if (*mvp == NULL) 1604863Seric { 1614863Seric /* running SMTP */ 1625179Seric # ifdef SMTP 1634863Seric clever = TRUE; 1644863Seric *pvp = NULL; 1656038Seric 1666038Seric /* send the initial SMTP protocol */ 1677003Seric i = smtpinit(m, pv, (ADDRESS *) NULL); 1685179Seric # ifdef QUEUE 1694863Seric if (i == EX_TEMPFAIL) 1704863Seric tempfail = TRUE; 1715179Seric # endif QUEUE 1725179Seric # else SMTP 1736038Seric /* oops! we don't implement SMTP */ 1745179Seric syserr("SMTP style mailer"); 1755179Seric return (EX_SOFTWARE); 1765179Seric # endif SMTP 1774863Seric } 178294Seric 179294Seric /* 1803233Seric ** At this point *mvp points to the argument with $u. We 1813233Seric ** run through our address list and append all the addresses 1823233Seric ** we can. If we run out of space, do not fret! We can 1833233Seric ** always send another copy later. 184294Seric */ 185294Seric 1863233Seric tobuf[0] = '\0'; 1876900Seric CurEnv->e_to = tobuf; 1884397Seric ctladdr = NULL; 1893233Seric for (; to != NULL; to = to->q_next) 190294Seric { 1913233Seric /* avoid sending multiple recipients to dumb mailers */ 1924382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1933233Seric break; 1943233Seric 1953233Seric /* if already sent or not for this host, don't send */ 1965008Seric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 1975008Seric strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) 1983233Seric continue; 1994397Seric 2005032Seric # ifdef DEBUG 2015032Seric if (Debug) 2025032Seric { 2035032Seric printf("\nsend to "); 2045032Seric printaddr(to, FALSE); 2055032Seric } 2065032Seric # endif DEBUG 2075032Seric 2084397Seric /* compute effective uid/gid when sending */ 2094596Seric if (to->q_mailer == ProgMailer) 2104397Seric ctladdr = getctladdr(to); 2114397Seric 2123233Seric user = to->q_user; 2136900Seric CurEnv->e_to = to->q_paddr; 2143233Seric to->q_flags |= QDONTSEND; 2154863Seric if (tempfail) 2165032Seric { 2174863Seric to->q_flags |= QQUEUEUP; 2185032Seric continue; 2195032Seric } 2203233Seric 2213233Seric /* 2223233Seric ** Check to see that these people are allowed to 2233233Seric ** talk to each other. 2243233Seric */ 2253233Seric 2263233Seric if (!checkcompat(to)) 227294Seric { 2283233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 2293233Seric continue; 230294Seric } 2313233Seric 2323233Seric /* 2334099Seric ** Strip quote bits from names if the mailer is dumb 2344099Seric ** about them. 2353233Seric */ 2363233Seric 2373233Seric if (bitset(M_STRIPQ, m->m_flags)) 238294Seric { 2394099Seric stripquotes(user, TRUE); 2404099Seric stripquotes(host, TRUE); 2413233Seric } 2424099Seric else 2434099Seric { 2444099Seric stripquotes(user, FALSE); 2454099Seric stripquotes(host, FALSE); 2464099Seric } 2473233Seric 2483233Seric /* 2496059Seric ** Pass it to the other host if we are running SMTP. 2506059Seric */ 2516059Seric 2526059Seric if (clever) 2536059Seric { 2546059Seric # ifdef SMTP 2556059Seric i = smtprcpt(to); 2566059Seric if (i != EX_OK) 2576059Seric { 2586059Seric # ifdef QUEUE 2596059Seric if (i == EX_TEMPFAIL) 2606059Seric to->q_flags |= QQUEUEUP; 2616059Seric else 2626059Seric # endif QUEUE 2636059Seric { 2646059Seric to->q_flags |= QBADADDR; 2656059Seric giveresponse(i, TRUE, m); 2666059Seric } 2676059Seric } 2686059Seric # else SMTP 2696059Seric syserr("trying to be clever"); 2706059Seric # endif SMTP 2716059Seric } 2726059Seric 2736059Seric /* 2744161Seric ** If an error message has already been given, don't 2754161Seric ** bother to send to this address. 2764161Seric ** 2774161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2784161Seric ** >> NOTE >> cannot do any further aliasing; that 2794161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2804161Seric */ 2814161Seric 2824161Seric if (bitset(QBADADDR, to->q_flags)) 2834161Seric continue; 2844161Seric 2854283Seric /* save statistics.... */ 2864596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2876900Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(CurEnv->e_msgsize); 2884283Seric 2894161Seric /* 2903233Seric ** See if this user name is "special". 2913233Seric ** If the user name has a slash in it, assume that this 2926974Seric ** is a file -- send it off without further ado. Note 2936974Seric ** that this type of addresses is not processed along 2946974Seric ** with the others, so we fudge on the To person. 2953233Seric */ 2963233Seric 2974596Seric if (m == LocalMailer) 2983233Seric { 2995599Seric if (user[0] == '/') 300294Seric { 3014397Seric i = mailfile(user, getctladdr(to)); 302294Seric giveresponse(i, TRUE, m); 3033233Seric continue; 304294Seric } 305294Seric } 3063233Seric 3074315Seric /* 3084315Seric ** Address is verified -- add this user to mailer 3094315Seric ** argv, and add it to the print list of recipients. 3104315Seric */ 3114315Seric 3126059Seric /* link together the chain of recipients */ 3136272Seric to->q_tchain = tochain; 3146272Seric tochain = to; 3156059Seric 3163233Seric /* create list of users for error messages */ 3173233Seric if (tobuf[0] != '\0') 3184082Seric (void) strcat(tobuf, ","); 3194082Seric (void) strcat(tobuf, to->q_paddr); 3203233Seric define('u', user); /* to user */ 3214078Seric define('z', to->q_home); /* user's home */ 3223233Seric 3234863Seric /* 3246059Seric ** Expand out this user into argument list. 3254863Seric */ 3264863Seric 3276059Seric if (!clever) 3283233Seric { 3296974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3304863Seric *pvp++ = newstr(buf); 3314863Seric if (pvp >= &pv[MAXPV - 2]) 3324863Seric { 3334863Seric /* allow some space for trailing parms */ 3344863Seric break; 3354863Seric } 3364863Seric } 337294Seric } 338294Seric 3394067Seric /* see if any addresses still exist */ 3404067Seric if (tobuf[0] == '\0') 3414863Seric { 3425179Seric # ifdef SMTP 3434863Seric if (clever) 3444863Seric smtpquit(pv[0]); 3455179Seric # endif SMTP 3467003Seric define('g', (char *) NULL); 3474067Seric return (0); 3484863Seric } 3494067Seric 3503233Seric /* print out messages as full list */ 3516900Seric CurEnv->e_to = tobuf; 3523233Seric 353294Seric /* 3543233Seric ** Fill out any parameters after the $u parameter. 355294Seric */ 356294Seric 3574863Seric while (!clever && *++mvp != NULL) 358294Seric { 3596974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3603233Seric *pvp++ = newstr(buf); 3613233Seric if (pvp >= &pv[MAXPV]) 3623233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 363294Seric } 3643233Seric *pvp++ = NULL; 365294Seric 366294Seric /* 367294Seric ** Call the mailer. 3682898Seric ** The argument vector gets built, pipes 369294Seric ** are created as necessary, and we fork & exec as 3702898Seric ** appropriate. 3714863Seric ** If we are running SMTP, we just need to clean up. 372294Seric */ 373294Seric 3744397Seric if (ctladdr == NULL) 3756900Seric ctladdr = &CurEnv->e_from; 3765179Seric # ifdef SMTP 3774863Seric if (clever) 3784863Seric { 3796974Seric i = smtpfinish(m, CurEnv); 3804863Seric smtpquit(pv[0]); 3814863Seric } 3824863Seric else 3835179Seric # endif SMTP 3846974Seric i = sendoff(m, pv, ctladdr); 3853233Seric 3864621Seric /* 3874621Seric ** If we got a temporary failure, arrange to queue the 3884621Seric ** addressees. 3894621Seric */ 3904621Seric 3915179Seric # ifdef QUEUE 3924621Seric if (i == EX_TEMPFAIL) 3934621Seric { 3945032Seric for (to = tochain; to != NULL; to = to->q_tchain) 3954621Seric to->q_flags |= QQUEUEUP; 3964621Seric } 3975179Seric # endif QUEUE 3984621Seric 3994488Seric errno = 0; 4007003Seric define('g', (char *) NULL); 4013233Seric return (i); 4023233Seric } 4033233Seric /* 4044214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4054214Seric ** 4064214Seric ** This MUST be a macro, since after a vfork we are running 4074214Seric ** two processes on the same stack!!! 4084214Seric ** 4094214Seric ** Parameters: 4104214Seric ** none. 4114214Seric ** 4124214Seric ** Returns: 4134214Seric ** From a macro??? You've got to be kidding! 4144214Seric ** 4154214Seric ** Side Effects: 4164214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4174214Seric ** pid of child in parent, zero in child. 4184214Seric ** -1 on unrecoverable error. 4194214Seric ** 4204214Seric ** Notes: 4214214Seric ** I'm awfully sorry this looks so awful. That's 4224214Seric ** vfork for you..... 4234214Seric */ 4244214Seric 4254214Seric # define NFORKTRIES 5 4264214Seric # ifdef VFORK 4274214Seric # define XFORK vfork 4284214Seric # else VFORK 4294214Seric # define XFORK fork 4304214Seric # endif VFORK 4314214Seric 4324214Seric # define DOFORK(fORKfN) \ 4334214Seric {\ 4344214Seric register int i;\ 4354214Seric \ 4364214Seric for (i = NFORKTRIES; i-- > 0; )\ 4374214Seric {\ 4384214Seric pid = fORKfN();\ 4394214Seric if (pid >= 0)\ 4404214Seric break;\ 4417003Seric sleep(NFORKTRIES - i);\ 4424214Seric }\ 4434214Seric } 4444214Seric /* 4454637Seric ** DOFORK -- simple fork interface to DOFORK. 4464637Seric ** 4474637Seric ** Parameters: 4484637Seric ** none. 4494637Seric ** 4504637Seric ** Returns: 4514637Seric ** pid of child in parent. 4524637Seric ** zero in child. 4534637Seric ** -1 on error. 4544637Seric ** 4554637Seric ** Side Effects: 4564637Seric ** returns twice, once in parent and once in child. 4574637Seric */ 4584637Seric 4594637Seric dofork() 4604637Seric { 4614637Seric register int pid; 4624637Seric 4634637Seric DOFORK(fork); 4644637Seric return (pid); 4654637Seric } 4664637Seric /* 4673233Seric ** SENDOFF -- send off call to mailer & collect response. 4683233Seric ** 4693233Seric ** Parameters: 4703233Seric ** m -- mailer descriptor. 4713233Seric ** pvp -- parameter vector to send to it. 4724397Seric ** ctladdr -- an address pointer controlling the 4734397Seric ** user/groupid etc. of the mailer. 4743233Seric ** 4753233Seric ** Returns: 4763233Seric ** exit status of mailer. 4773233Seric ** 4783233Seric ** Side Effects: 4793233Seric ** none. 4803233Seric */ 4813233Seric 4826974Seric sendoff(m, pvp, ctladdr) 4833233Seric struct mailer *m; 4843233Seric char **pvp; 4854397Seric ADDRESS *ctladdr; 4863233Seric { 4874863Seric auto FILE *mfile; 4884863Seric auto FILE *rfile; 4893233Seric register int i; 4903233Seric int pid; 4914863Seric 4924863Seric /* 4934863Seric ** Create connection to mailer. 4944863Seric */ 4954863Seric 4964863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 4974863Seric if (pid < 0) 4984863Seric return (-1); 4994863Seric 5004863Seric /* 5014863Seric ** Format and send message. 5024863Seric */ 5034863Seric 5044863Seric (void) signal(SIGPIPE, SIG_IGN); 5056974Seric putfromline(mfile, m); 5066974Seric (*CurEnv->e_puthdr)(mfile, m, CurEnv); 5076974Seric fprintf(mfile, "\n"); 5086974Seric (*CurEnv->e_putbody)(mfile, m, FALSE); 5094863Seric (void) fclose(mfile); 5104863Seric 5114863Seric i = endmailer(pid, pvp[0]); 5124863Seric giveresponse(i, TRUE, m); 5135981Seric 5145981Seric /* arrange a return receipt if requested */ 5156900Seric if (CurEnv->e_retreceipt && bitset(M_LOCAL, m->m_flags) && i == EX_OK) 5165981Seric { 5176900Seric CurEnv->e_sendreceipt = TRUE; 5186900Seric fprintf(Xscript, "%s... successfully delivered\n", CurEnv->e_to); 5195981Seric /* do we want to send back more info? */ 5205981Seric } 5215981Seric 5224863Seric return (i); 5234863Seric } 5244863Seric /* 5254863Seric ** ENDMAILER -- Wait for mailer to terminate. 5264863Seric ** 5274863Seric ** We should never get fatal errors (e.g., segmentation 5284863Seric ** violation), so we report those specially. For other 5294863Seric ** errors, we choose a status message (into statmsg), 5304863Seric ** and if it represents an error, we print it. 5314863Seric ** 5324863Seric ** Parameters: 5334863Seric ** pid -- pid of mailer. 5344863Seric ** name -- name of mailer (for error messages). 5354863Seric ** 5364863Seric ** Returns: 5374863Seric ** exit code of mailer. 5384863Seric ** 5394863Seric ** Side Effects: 5404863Seric ** none. 5414863Seric */ 5424863Seric 5434863Seric endmailer(pid, name) 5444863Seric int pid; 5454863Seric char *name; 5464863Seric { 5474863Seric register int i; 5484863Seric auto int st; 5494863Seric 5506038Seric /* in the IPC case there is nothing to wait for */ 5516038Seric if (pid == 0) 5526038Seric return (EX_OK); 5536038Seric 5546038Seric /* wait for the mailer process to die and collect status */ 5554863Seric while ((i = wait(&st)) > 0 && i != pid) 5564863Seric continue; 5574863Seric if (i < 0) 5584863Seric { 5594863Seric syserr("wait"); 5604863Seric return (-1); 5614863Seric } 5626038Seric 5636038Seric /* see if it died a horrid death */ 5644863Seric if ((st & 0377) != 0) 5654863Seric { 5664863Seric syserr("%s: stat %o", name, st); 5674863Seric ExitStat = EX_UNAVAILABLE; 5684863Seric return (-1); 5694863Seric } 5706038Seric 5716038Seric /* normal death -- return status */ 5724863Seric i = (st >> 8) & 0377; 5734863Seric return (i); 5744863Seric } 5754863Seric /* 5764863Seric ** OPENMAILER -- open connection to mailer. 5774863Seric ** 5784863Seric ** Parameters: 5794863Seric ** m -- mailer descriptor. 5804863Seric ** pvp -- parameter vector to pass to mailer. 5814863Seric ** ctladdr -- controlling address for user. 5824863Seric ** clever -- create a full duplex connection. 5834863Seric ** pmfile -- pointer to mfile (to mailer) connection. 5844863Seric ** prfile -- pointer to rfile (from mailer) connection. 5854863Seric ** 5864863Seric ** Returns: 5876038Seric ** pid of mailer ( > 0 ). 5884863Seric ** -1 on error. 5896038Seric ** zero on an IPC connection. 5904863Seric ** 5914863Seric ** Side Effects: 5924863Seric ** creates a mailer in a subprocess. 5934863Seric */ 5944863Seric 5954863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 5964863Seric struct mailer *m; 5974863Seric char **pvp; 5984863Seric ADDRESS *ctladdr; 5994863Seric bool clever; 6004863Seric FILE **pmfile; 6014863Seric FILE **prfile; 6024863Seric { 6034863Seric int pid; 6044709Seric int mpvect[2]; 6054863Seric int rpvect[2]; 6063233Seric FILE *mfile; 6074863Seric FILE *rfile; 6083233Seric extern FILE *fdopen(); 6093233Seric 6103233Seric # ifdef DEBUG 6113233Seric if (Debug) 612294Seric { 6134863Seric printf("openmailer:\n"); 6143233Seric printav(pvp); 615294Seric } 6163233Seric # endif DEBUG 6174488Seric errno = 0; 6183233Seric 6196038Seric # ifdef DAEMON 6206038Seric /* 6216038Seric ** Deal with the special case of mail handled through an IPC 6226038Seric ** connection. 6236038Seric ** In this case we don't actually fork. We must be 6246038Seric ** running SMTP for this to work. We will return a 6256038Seric ** zero pid to indicate that we are running IPC. 6266038Seric */ 6276038Seric 6286038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6296038Seric { 6306038Seric register int i; 6316038Seric 6326038Seric if (!clever) 6336038Seric syserr("non-clever IPC"); 6346632Seric if (pvp[2] != NULL) 6356632Seric i = atoi(pvp[2]); 6366632Seric else 6376632Seric i = 0; 6386632Seric i = makeconnection(pvp[1], i, pmfile, prfile); 6396038Seric if (i != EX_OK) 6406047Seric { 6416047Seric ExitStat = i; 6426038Seric return (-1); 6436047Seric } 6446038Seric else 6456038Seric return (0); 6466038Seric } 6476038Seric # endif DAEMON 6486038Seric 6492898Seric /* create a pipe to shove the mail through */ 6504709Seric if (pipe(mpvect) < 0) 651294Seric { 6524863Seric syserr("pipe (to mailer)"); 653294Seric return (-1); 654294Seric } 6554863Seric 6565179Seric # ifdef SMTP 6574863Seric /* if this mailer speaks smtp, create a return pipe */ 6584863Seric if (clever && pipe(rpvect) < 0) 6594863Seric { 6604863Seric syserr("pipe (from mailer)"); 6614863Seric (void) close(mpvect[0]); 6624863Seric (void) close(mpvect[1]); 6634863Seric return (-1); 6644863Seric } 6655179Seric # endif SMTP 6664863Seric 6676038Seric /* 6686038Seric ** Actually fork the mailer process. 6696038Seric ** DOFORK is clever about retrying. 6706038Seric */ 6716038Seric 6724214Seric DOFORK(XFORK); 6734327Seric /* pid is set by DOFORK */ 674294Seric if (pid < 0) 675294Seric { 6766038Seric /* failure */ 677294Seric syserr("Cannot fork"); 6784709Seric (void) close(mpvect[0]); 6794709Seric (void) close(mpvect[1]); 6804863Seric if (clever) 6814863Seric { 6824863Seric (void) close(rpvect[0]); 6834863Seric (void) close(rpvect[1]); 6844863Seric } 685294Seric return (-1); 686294Seric } 687294Seric else if (pid == 0) 688294Seric { 689294Seric /* child -- set up input & exec mailer */ 6901621Seric /* make diagnostic output be standard output */ 6914477Seric (void) signal(SIGINT, SIG_IGN); 6924477Seric (void) signal(SIGHUP, SIG_IGN); 6934215Seric (void) signal(SIGTERM, SIG_DFL); 6944709Seric 6954709Seric /* arrange to filter standard & diag output of command */ 6964863Seric if (clever) 6974709Seric { 6984863Seric (void) close(rpvect[0]); 6994709Seric (void) close(1); 7004863Seric (void) dup(rpvect[1]); 7014863Seric (void) close(rpvect[1]); 7024863Seric } 7034863Seric else if (OutChannel != stdout) 7044863Seric { 7054863Seric (void) close(1); 7064709Seric (void) dup(fileno(OutChannel)); 7074709Seric } 7084082Seric (void) close(2); 7094082Seric (void) dup(1); 7104709Seric 7114709Seric /* arrange to get standard input */ 7124709Seric (void) close(mpvect[1]); 7134082Seric (void) close(0); 7144709Seric if (dup(mpvect[0]) < 0) 715294Seric { 7162898Seric syserr("Cannot dup to zero!"); 7172898Seric _exit(EX_OSERR); 718294Seric } 7194709Seric (void) close(mpvect[0]); 7202968Seric if (!bitset(M_RESTR, m->m_flags)) 7214215Seric { 7224417Seric if (ctladdr->q_uid == 0) 7234417Seric { 7244417Seric (void) setgid(DefGid); 7254417Seric (void) setuid(DefUid); 7264417Seric } 7274417Seric else 7284415Seric { 7294417Seric (void) setgid(ctladdr->q_gid); 7304417Seric (void) setuid(ctladdr->q_uid); 7314415Seric } 7324215Seric } 7332774Seric # ifndef VFORK 7342774Seric /* 7352774Seric ** We have to be careful with vfork - we can't mung up the 7362774Seric ** memory but we don't want the mailer to inherit any extra 7372774Seric ** open files. Chances are the mailer won't 7382774Seric ** care about an extra file, but then again you never know. 7392774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7402774Seric ** declared static so we can't. But if we fclose(pwf), which 7412774Seric ** is what endpwent does, it closes it in the parent too and 7422774Seric ** the next getpwnam will be slower. If you have a weird 7432774Seric ** mailer that chokes on the extra file you should do the 7442774Seric ** endpwent(). 7452774Seric ** 7462774Seric ** Similar comments apply to log. However, openlog is 7472774Seric ** clever enough to set the FIOCLEX mode on the file, 7482774Seric ** so it will be closed automatically on the exec. 7492774Seric */ 7502774Seric 7512774Seric endpwent(); 752294Seric # ifdef LOG 7532089Seric closelog(); 754294Seric # endif LOG 7552774Seric # endif VFORK 7566038Seric 7576038Seric /* try to execute the mailer */ 758294Seric execv(m->m_mailer, pvp); 7596038Seric 760294Seric /* syserr fails because log is closed */ 761294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 7624214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 7634082Seric (void) fflush(stdout); 7641619Seric _exit(EX_UNAVAILABLE); 765294Seric } 766294Seric 7674709Seric /* 7684863Seric ** Set up return value. 7694709Seric */ 7704709Seric 7714709Seric (void) close(mpvect[0]); 7724709Seric mfile = fdopen(mpvect[1], "w"); 7734863Seric if (clever) 7744863Seric { 7754863Seric (void) close(rpvect[1]); 7764863Seric rfile = fdopen(rpvect[0], "r"); 7774863Seric } 778294Seric 7794863Seric *pmfile = mfile; 7804863Seric *prfile = rfile; 781294Seric 7824863Seric return (pid); 783294Seric } 784294Seric /* 785294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 786294Seric ** 787294Seric ** Parameters: 788294Seric ** stat -- the status code from the mailer (high byte 789294Seric ** only; core dumps must have been taken care of 790294Seric ** already). 791294Seric ** force -- if set, force an error message output, even 792294Seric ** if the mailer seems to like to print its own 793294Seric ** messages. 794294Seric ** m -- the mailer descriptor for this mailer. 795294Seric ** 796294Seric ** Returns: 7974082Seric ** none. 798294Seric ** 799294Seric ** Side Effects: 8001518Seric ** Errors may be incremented. 801294Seric ** ExitStat may be set. 802294Seric */ 803294Seric 804294Seric giveresponse(stat, force, m) 805294Seric int stat; 806294Seric int force; 807294Seric register struct mailer *m; 808294Seric { 809294Seric register char *statmsg; 810294Seric extern char *SysExMsg[]; 811294Seric register int i; 812294Seric extern int N_SysEx; 8131624Seric char buf[30]; 814294Seric 8154315Seric /* 8164315Seric ** Compute status message from code. 8174315Seric */ 8184315Seric 819294Seric i = stat - EX__BASE; 820294Seric if (i < 0 || i > N_SysEx) 821294Seric statmsg = NULL; 822294Seric else 823294Seric statmsg = SysExMsg[i]; 824294Seric if (stat == 0) 8254065Seric { 8264194Seric if (bitset(M_LOCAL, m->m_flags)) 8274161Seric statmsg = "delivered"; 8284161Seric else 8294161Seric statmsg = "queued"; 8304065Seric if (Verbose) 8314166Seric message(Arpa_Info, statmsg); 8324065Seric } 8335179Seric # ifdef QUEUE 8344621Seric else if (stat == EX_TEMPFAIL) 8354621Seric { 8364621Seric if (Verbose) 8374621Seric message(Arpa_Info, "transmission deferred"); 8384621Seric } 8395179Seric # endif QUEUE 840294Seric else 841294Seric { 8421518Seric Errors++; 8436047Seric FatalErrors = TRUE; 844294Seric if (statmsg == NULL && m->m_badstat != 0) 845294Seric { 846294Seric stat = m->m_badstat; 847294Seric i = stat - EX__BASE; 848294Seric # ifdef DEBUG 849294Seric if (i < 0 || i >= N_SysEx) 850294Seric syserr("Bad m_badstat %d", stat); 851294Seric else 852294Seric # endif DEBUG 853294Seric statmsg = SysExMsg[i]; 854294Seric } 855294Seric if (statmsg == NULL) 856294Seric usrerr("unknown mailer response %d", stat); 8574065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 858294Seric usrerr("%s", statmsg); 859294Seric } 860294Seric 861294Seric /* 862294Seric ** Final cleanup. 863294Seric ** Log a record of the transaction. Compute the new 864294Seric ** ExitStat -- if we already had an error, stick with 865294Seric ** that. 866294Seric */ 867294Seric 8681624Seric if (statmsg == NULL) 8691624Seric { 8704082Seric (void) sprintf(buf, "error %d", stat); 8711624Seric statmsg = buf; 8721624Seric } 8731624Seric 874294Seric # ifdef LOG 8756900Seric syslog(LOG_INFO, "%s->%s: %ld: %s", CurEnv->e_from.q_paddr, CurEnv->e_to, CurEnv->e_msgsize, statmsg); 876294Seric # endif LOG 8775179Seric # ifdef QUEUE 8784621Seric if (stat != EX_TEMPFAIL) 8795179Seric # endif QUEUE 8804621Seric setstat(stat); 881294Seric } 882294Seric /* 8836974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 884294Seric ** 8856974Seric ** This can be made an arbitrary message separator by changing $l 886294Seric ** 8876974Seric ** One of the ugliest hacks seen by human eyes is 8886974Seric ** contained herein: UUCP wants those stupid 8896974Seric ** "remote from <host>" lines. Why oh why does a 8906974Seric ** well-meaning programmer such as myself have to 8916974Seric ** deal with this kind of antique garbage???? 8926974Seric ** 893294Seric ** Parameters: 8946974Seric ** fp -- the file to output to. 8956974Seric ** m -- the mailer describing this entry. 896294Seric ** 897294Seric ** Returns: 8986974Seric ** none 899294Seric ** 900294Seric ** Side Effects: 9016974Seric ** outputs some text to fp. 902294Seric */ 903294Seric 9046974Seric putfromline(fp, m) 9056974Seric register FILE *fp; 9066974Seric register MAILER *m; 907294Seric { 9086974Seric char buf[MAXLINE]; 909294Seric 9106974Seric if (bitset(M_NHDR, m->m_flags)) 9116974Seric return; 9124315Seric 9136974Seric # ifdef UGLYUUCP 9146974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9154205Seric { 9166974Seric extern char *macvalue(); 9176974Seric char *sys = macvalue('g'); 9186974Seric char *bang = index(sys, '!'); 9196041Seric 9206974Seric if (bang == NULL) 9216974Seric syserr("No ! in UUCP! (%s)", sys); 9225099Seric else 9236974Seric *bang = '\0'; 9246974Seric expand("From $f $d remote from $g", buf, 9256974Seric &buf[sizeof buf - 1], CurEnv); 9266974Seric *bang = '!'; 9276974Seric } 9286974Seric else 9295179Seric # endif UGLYUUCP 9306974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 9316974Seric fputs(buf, fp); 9325981Seric } 9335981Seric /* 9346974Seric ** PUTHEADER -- put the header part of a message from the in-core copy 9355981Seric ** 9365981Seric ** Parameters: 9375981Seric ** fp -- file to put it on. 9385981Seric ** m -- mailer to use. 9396974Seric ** e -- envelope to use. 9405981Seric ** 9415981Seric ** Returns: 9425981Seric ** none. 9435981Seric ** 9445981Seric ** Side Effects: 9455981Seric ** none. 9465981Seric */ 9475981Seric 9486974Seric putheader(fp, m, e) 9495981Seric register FILE *fp; 9505981Seric register struct mailer *m; 9516974Seric register ENVELOPE *e; 9525981Seric { 9535981Seric char buf[BUFSIZ]; 9545981Seric register HDR *h; 9555981Seric extern char *arpadate(); 9565981Seric extern char *capitalize(); 9575981Seric extern char *hvalue(); 9585981Seric extern bool samefrom(); 9595981Seric char *of_line; 9605981Seric 9614447Seric of_line = hvalue("original-from"); 9626974Seric for (h = e->e_header; h != NULL; h = h->h_link) 9631828Seric { 9644315Seric register char *p; 9656974Seric char *origfrom = e->e_origfrom; 9664447Seric bool nooutput; 9674315Seric 9684447Seric nooutput = FALSE; 9693389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 9704447Seric nooutput = TRUE; 9714447Seric 9724447Seric /* use From: line from message if generated is the same */ 9734370Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 9744447Seric strcmp(m->m_from, "$f") == 0 && of_line == NULL) 9753385Seric { 9764370Seric p = origfrom; 9774370Seric origfrom = NULL; 9784370Seric } 9794370Seric else if (bitset(H_DEFAULT, h->h_flags)) 9804370Seric { 9816974Seric expand(h->h_value, buf, &buf[sizeof buf], e); 9823385Seric p = buf; 9833385Seric } 9845913Seric else if (bitset(H_ADDR, h->h_flags)) 9855913Seric { 9865913Seric register int opos; 9875913Seric bool firstone = TRUE; 9885913Seric 9895913Seric /* 9905913Seric ** Output the address list translated by the 9915913Seric ** mailer and with commas. 9925913Seric */ 9935913Seric 9945913Seric p = h->h_value; 9955913Seric if (p == NULL || *p == '\0' || nooutput) 9965913Seric continue; 9975913Seric fprintf(fp, "%s: ", capitalize(h->h_field)); 9985913Seric opos = strlen(h->h_field) + 2; 9995913Seric while (*p != '\0') 10005913Seric { 10015913Seric register char *name = p; 10025913Seric extern char *remotename(); 10035913Seric char savechar; 10045913Seric 10055913Seric /* find the end of the name */ 10065936Seric while (*p != '\0' && *p != ',') 10075936Seric { 10085936Seric extern bool isatword(); 10095936Seric char *oldp; 10105936Seric 10116974Seric if (!e->e_oldstyle || !isspace(*p)) 10125936Seric { 10135936Seric p++; 10145936Seric continue; 10155936Seric } 10165936Seric oldp = p; 10175936Seric while (*p != '\0' && isspace(*p)) 10185936Seric p++; 10195936Seric if (*p != '@' && !isatword(p)) 10205936Seric { 10215936Seric p = oldp; 10225936Seric break; 10235936Seric } 10245936Seric p += *p == '@' ? 1 : 2; 10255936Seric while (*p != '\0' && isspace(*p)) 10265936Seric p++; 10275936Seric } 10285913Seric savechar = *p; 10295913Seric *p = '\0'; 10305913Seric 10315913Seric /* translate the name to be relative */ 10326820Seric name = remotename(name, m, FALSE); 10335913Seric if (*name == '\0') 10345913Seric continue; 10355913Seric 10365913Seric /* output the name with nice formatting */ 10375913Seric opos += strlen(name); 10385913Seric if (!firstone) 10395913Seric opos += 2; 10405913Seric if (opos > 78 && !firstone) 10415913Seric { 10425913Seric fprintf(fp, ",\n "); 10435916Seric opos = 8 + strlen(name); 10445913Seric } 10455913Seric else if (!firstone) 10465913Seric fprintf(fp, ", "); 10475913Seric fprintf(fp, "%s", name); 10485913Seric firstone = FALSE; 10495913Seric 10505913Seric /* clean up the source string */ 10515913Seric *p = savechar; 10525913Seric while (*p != '\0' && (isspace(*p) || *p == ',')) 10535913Seric p++; 10545913Seric } 10555913Seric fprintf(fp, "\n"); 10565913Seric nooutput = TRUE; 10575913Seric } 10582898Seric else 10593385Seric p = h->h_value; 10604447Seric if (p == NULL || *p == '\0') 10613389Seric continue; 10624209Seric 10634209Seric /* hack, hack -- output Original-From field if different */ 10644447Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL) 10654209Seric { 10664447Seric /* output new Original-From line if needed */ 10674447Seric if (of_line == NULL && !samefrom(p, origfrom)) 10684447Seric fprintf(fp, "Original-From: %s\n", origfrom); 10694447Seric if (of_line != NULL && !nooutput && samefrom(p, of_line)) 10704447Seric { 10714447Seric /* delete Original-From: line if redundant */ 10724447Seric p = of_line; 10734447Seric of_line = NULL; 10744447Seric } 10754447Seric } 10764447Seric else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL) 10774447Seric nooutput = TRUE; 10784447Seric 10794447Seric /* finally, output the header line */ 10804447Seric if (!nooutput) 10814447Seric { 10824447Seric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 10834447Seric h->h_flags |= H_USED; 10844209Seric } 10852898Seric } 1086294Seric } 1087294Seric /* 10886974Seric ** PUTBODY -- put the body of a message. 10896974Seric ** 10906974Seric ** Parameters: 10916974Seric ** fp -- file to output onto. 10926974Seric ** m -- a mailer descriptor. 10936974Seric ** xdot -- if set, use SMTP hidden dot algorithm. 10946974Seric ** 10956974Seric ** Returns: 10966974Seric ** none. 10976974Seric ** 10986974Seric ** Side Effects: 10996974Seric ** The message is written onto fp. 11006974Seric */ 11016974Seric 11026974Seric putbody(fp, m, xdot) 11036974Seric FILE *fp; 11046974Seric struct mailer *m; 11056974Seric bool xdot; 11066974Seric { 11076974Seric char buf[MAXLINE + 1]; 11086974Seric 11096974Seric /* 11106974Seric ** Output the body of the message 11116974Seric */ 11126974Seric 11137003Seric #ifdef lint 11147003Seric /* m will be needed later for complete smtp emulation */ 11157003Seric if (m == NULL) 11167003Seric return; 11177003Seric #endif lint 11187003Seric 11196974Seric if (TempFile != NULL) 11206974Seric { 11216974Seric rewind(TempFile); 11226974Seric buf[0] = '.'; 11236974Seric while (!ferror(fp) && fgets(&buf[1], sizeof buf - 1, TempFile) != NULL) 11246974Seric fputs((xdot && buf[1] == '.') ? buf : &buf[1], fp); 11256974Seric 11266974Seric if (ferror(TempFile)) 11276974Seric { 11286974Seric syserr("putbody: read error"); 11296974Seric ExitStat = EX_IOERR; 11306974Seric } 11316974Seric } 11326974Seric 11336974Seric (void) fflush(fp); 11346974Seric if (ferror(fp) && errno != EPIPE) 11356974Seric { 11366974Seric syserr("putbody: write error"); 11376974Seric ExitStat = EX_IOERR; 11386974Seric } 11396974Seric errno = 0; 11406974Seric } 11416974Seric /* 11425936Seric ** ISATWORD -- tell if the word we are pointing to is "at". 11435936Seric ** 11445936Seric ** Parameters: 11455936Seric ** p -- word to check. 11465936Seric ** 11475936Seric ** Returns: 11485936Seric ** TRUE -- if p is the word at. 11495936Seric ** FALSE -- otherwise. 11505936Seric ** 11515936Seric ** Side Effects: 11525936Seric ** none. 11535936Seric */ 11545936Seric 11555936Seric bool 11565936Seric isatword(p) 11575936Seric register char *p; 11585936Seric { 11595936Seric extern char lower(); 11605936Seric 11615936Seric if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 11625936Seric p[2] != '\0' && isspace(p[2])) 11635936Seric return (TRUE); 11645936Seric return (FALSE); 11655936Seric } 11665936Seric /* 11675913Seric ** REMOTENAME -- return the name relative to the current mailer 11685913Seric ** 11695913Seric ** Parameters: 11705913Seric ** name -- the name to translate. 11716820Seric ** force -- if set, forces rewriting even if the mailer 11726820Seric ** does not request it. Used for rewriting 11736820Seric ** sender addresses. 11745913Seric ** 11755913Seric ** Returns: 11765913Seric ** the text string representing this address relative to 11775913Seric ** the receiving mailer. 11785913Seric ** 11795913Seric ** Side Effects: 11805913Seric ** none. 11815913Seric ** 11825913Seric ** Warnings: 11835913Seric ** The text string returned is tucked away locally; 11845913Seric ** copy it if you intend to save it. 11855913Seric */ 11865913Seric 11875913Seric char * 11886820Seric remotename(name, m, force) 11895913Seric char *name; 11905916Seric struct mailer *m; 11916820Seric bool force; 11925913Seric { 11935913Seric static char buf[MAXNAME]; 11945913Seric char lbuf[MAXNAME]; 11955913Seric extern char *macvalue(); 11965913Seric char *oldf = macvalue('f'); 11975916Seric char *oldx = macvalue('x'); 11985916Seric char *oldg = macvalue('g'); 11995913Seric extern char **prescan(); 12005913Seric register char **pvp; 12015916Seric extern char *getxpart(); 12027003Seric extern ADDRESS *buildaddr(); 12035913Seric 12045913Seric /* 12056820Seric ** See if this mailer wants the name to be rewritten. There are 12066820Seric ** many problems here, owing to the standards for doing replies. 12076820Seric ** In general, these names should only be rewritten if we are 12086820Seric ** sending to another host that runs sendmail. 12096820Seric */ 12106820Seric 12116820Seric if (!bitset(M_RELRCPT, m->m_flags) && !force) 12127003Seric return (name); 12136820Seric 12146820Seric /* 12155913Seric ** Do general rewriting of name. 12165913Seric ** This will also take care of doing global name translation. 12175913Seric */ 12185913Seric 12195916Seric define('x', getxpart(name)); 12205913Seric pvp = prescan(name, '\0'); 1221*7048Seric rewrite(pvp, 1); 1222*7048Seric rewrite(pvp, 3); 1223*7048Seric if (**pvp == CANONNET) 12245913Seric { 1225*7048Seric /* oops... resolved to something */ 1226*7048Seric return (name); 12275913Seric } 1228*7048Seric cataddr(pvp, lbuf, sizeof lbuf); 12295913Seric 12305913Seric /* make the name relative to the receiving mailer */ 12315913Seric define('f', lbuf); 12326974Seric expand(m->m_from, buf, &buf[sizeof buf - 1], CurEnv); 12335913Seric 12345913Seric /* rewrite to get rid of garbage we added in the expand above */ 12355913Seric pvp = prescan(buf, '\0'); 12365913Seric rewrite(pvp, 2); 12375916Seric cataddr(pvp, lbuf, sizeof lbuf); 12385913Seric 12395916Seric /* now add any comment info we had before back */ 12405916Seric define('g', lbuf); 12416974Seric expand("$q", buf, &buf[sizeof buf - 1], CurEnv); 12425916Seric 12435913Seric define('f', oldf); 12445916Seric define('g', oldg); 12455916Seric define('x', oldx); 12465913Seric 12475913Seric # ifdef DEBUG 12485913Seric if (Debug > 0) 12495913Seric printf("remotename(%s) => `%s'\n", name, buf); 12505913Seric # endif DEBUG 12515913Seric return (buf); 12525913Seric } 12535913Seric /* 12544370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 12554370Seric ** 12564370Seric ** Parameters: 12574370Seric ** ifrom -- internally generated form of from address. 12584370Seric ** efrom -- external form of from address. 12594370Seric ** 12604370Seric ** Returns: 12614370Seric ** TRUE -- if they convey the same info. 12624370Seric ** FALSE -- if any information has been lost. 12634370Seric ** 12644370Seric ** Side Effects: 12654370Seric ** none. 12664370Seric */ 12674370Seric 12684370Seric bool 12694370Seric samefrom(ifrom, efrom) 12704370Seric char *ifrom; 12714370Seric char *efrom; 12724370Seric { 12734447Seric register char *p; 12744447Seric char buf[MAXNAME + 4]; 12754447Seric 12764447Seric # ifdef DEBUG 12774447Seric if (Debug > 7) 12784447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 12794447Seric # endif DEBUG 12804447Seric if (strcmp(ifrom, efrom) == 0) 12814447Seric goto success; 12824447Seric p = index(ifrom, '@'); 12834447Seric if (p == NULL) 12844447Seric goto failure; 12854447Seric *p = '\0'; 12867003Seric (void) strcpy(buf, ifrom); 12877003Seric (void) strcat(buf, " at "); 12884447Seric *p++ = '@'; 12897003Seric (void) strcat(buf, p); 12904447Seric if (strcmp(buf, efrom) == 0) 12914447Seric goto success; 12924447Seric 12934447Seric failure: 12944447Seric # ifdef DEBUG 12954447Seric if (Debug > 7) 12964447Seric printf("FALSE\n"); 12974447Seric # endif DEBUG 12984447Seric return (FALSE); 12994447Seric 13004447Seric success: 13014447Seric # ifdef DEBUG 13024447Seric if (Debug > 7) 13034447Seric printf("TRUE\n"); 13044447Seric # endif DEBUG 13054447Seric return (TRUE); 13064370Seric } 13074370Seric /* 1308294Seric ** MAILFILE -- Send a message to a file. 1309294Seric ** 13104327Seric ** If the file has the setuid/setgid bits set, but NO execute 13114327Seric ** bits, sendmail will try to become the owner of that file 13124327Seric ** rather than the real user. Obviously, this only works if 13134327Seric ** sendmail runs as root. 13144327Seric ** 1315294Seric ** Parameters: 1316294Seric ** filename -- the name of the file to send to. 13174397Seric ** ctladdr -- the controlling address header -- includes 13184397Seric ** the userid/groupid to be when sending. 1319294Seric ** 1320294Seric ** Returns: 1321294Seric ** The exit code associated with the operation. 1322294Seric ** 1323294Seric ** Side Effects: 1324294Seric ** none. 1325294Seric */ 1326294Seric 13274397Seric mailfile(filename, ctladdr) 1328294Seric char *filename; 13294397Seric ADDRESS *ctladdr; 1330294Seric { 1331294Seric register FILE *f; 13324214Seric register int pid; 1333294Seric 13344214Seric /* 13354214Seric ** Fork so we can change permissions here. 13364214Seric ** Note that we MUST use fork, not vfork, because of 13374214Seric ** the complications of calling subroutines, etc. 13384214Seric */ 13394067Seric 13404214Seric DOFORK(fork); 13414214Seric 13424214Seric if (pid < 0) 13434214Seric return (EX_OSERR); 13444214Seric else if (pid == 0) 13454214Seric { 13464214Seric /* child -- actually write to file */ 13474327Seric struct stat stb; 13484327Seric 13494215Seric (void) signal(SIGINT, SIG_DFL); 13504215Seric (void) signal(SIGHUP, SIG_DFL); 13514215Seric (void) signal(SIGTERM, SIG_DFL); 13524327Seric umask(OldUmask); 13534327Seric if (stat(filename, &stb) < 0) 13544431Seric stb.st_mode = 0666; 13554327Seric if (bitset(0111, stb.st_mode)) 13564327Seric exit(EX_CANTCREAT); 13574401Seric if (ctladdr == NULL) 13586900Seric ctladdr = &CurEnv->e_from; 13594327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 13604417Seric { 13614417Seric if (ctladdr->q_uid == 0) 13624417Seric (void) setgid(DefGid); 13634417Seric else 13644417Seric (void) setgid(ctladdr->q_gid); 13654417Seric } 13664327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 13674417Seric { 13684417Seric if (ctladdr->q_uid == 0) 13694417Seric (void) setuid(DefUid); 13704417Seric else 13714417Seric (void) setuid(ctladdr->q_uid); 13724417Seric } 13736887Seric f = dfopen(filename, "a"); 13744214Seric if (f == NULL) 13754214Seric exit(EX_CANTCREAT); 13764214Seric 13776974Seric putfromline(f, Mailer[1]); 13786974Seric (*CurEnv->e_puthdr)(f, Mailer[1], CurEnv); 13796974Seric fprintf(f, "\n"); 13806974Seric (*CurEnv->e_putbody)(f, Mailer[1], FALSE); 13814214Seric fputs("\n", f); 13824214Seric (void) fclose(f); 13834214Seric (void) fflush(stdout); 13844417Seric 13856887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13864621Seric (void) chmod(filename, (int) stb.st_mode); 13874214Seric exit(EX_OK); 13884315Seric /*NOTREACHED*/ 13894214Seric } 13904214Seric else 13914214Seric { 13924214Seric /* parent -- wait for exit status */ 13934214Seric register int i; 13944214Seric auto int stat; 13954214Seric 13964214Seric while ((i = wait(&stat)) != pid) 13974214Seric { 13984214Seric if (i < 0) 13994214Seric { 14004214Seric stat = EX_OSERR << 8; 14014214Seric break; 14024214Seric } 14034214Seric } 14044215Seric if ((stat & 0377) != 0) 14054215Seric stat = EX_UNAVAILABLE << 8; 14064214Seric return ((stat >> 8) & 0377); 14074214Seric } 1408294Seric } 14094550Seric /* 14104550Seric ** SENDALL -- actually send all the messages. 14114550Seric ** 14124550Seric ** Parameters: 14137043Seric ** e -- the envelope to send. 14144550Seric ** verifyonly -- if set, only give verification messages. 14154550Seric ** 14164550Seric ** Returns: 14174550Seric ** none. 14184550Seric ** 14194550Seric ** Side Effects: 14204550Seric ** Scans the send lists and sends everything it finds. 14217043Seric ** Delivers any appropriate error messages. 14224550Seric */ 14234550Seric 14247043Seric sendall(e, verifyonly) 14257043Seric ENVELOPE *e; 14264550Seric bool verifyonly; 14274550Seric { 14285008Seric register ADDRESS *q; 14294550Seric 14305032Seric # ifdef DEBUG 14315032Seric if (Debug > 1) 14325032Seric { 14336900Seric printf("\nSend Queue:\n"); 14347043Seric printaddr(e->e_sendqueue, TRUE); 14355032Seric } 14365032Seric # endif DEBUG 14375008Seric 14387043Seric /* 14397043Seric ** Run through the list and send everything. 14407043Seric */ 14417043Seric 14427043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14434550Seric { 14445008Seric if (verifyonly) 14454550Seric { 14466900Seric CurEnv->e_to = q->q_paddr; 14475008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14484550Seric { 14495008Seric if (bitset(M_LOCAL, q->q_mailer->m_flags)) 14505008Seric message(Arpa_Info, "deliverable"); 14515008Seric else 14525008Seric message(Arpa_Info, "queueable"); 14534550Seric } 14544550Seric } 14555008Seric else 14566974Seric (void) deliver(q); 14574550Seric } 14587043Seric 14597043Seric /* 14607043Seric ** Now run through and check for errors. 14617043Seric */ 14627043Seric 14637043Seric if (verifyonly) 14647043Seric return; 14657043Seric 14667043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14677043Seric { 14687043Seric register ADDRESS *qq; 14697043Seric 14707043Seric if (bitset(QQUEUEUP, q->q_flags)) 14717043Seric e->e_queueup = TRUE; 14727043Seric if (!bitset(QBADADDR, q->q_flags)) 14737043Seric continue; 14747043Seric 14757043Seric /* we have an address that failed -- find the parent */ 14767043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14777043Seric { 14787043Seric char obuf[MAXNAME + 6]; 14797043Seric extern char *aliaslookup(); 14807043Seric 14817043Seric /* we can only have owners for local addresses */ 14827043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 14837043Seric continue; 14847043Seric 14857043Seric /* see if the owner list exists */ 14867043Seric (void) strcpy(obuf, "owner-"); 14877047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14887047Seric (void) strcat(obuf, "owner"); 14897047Seric else 14907047Seric (void) strcat(obuf, qq->q_user); 14917043Seric if (aliaslookup(obuf) == NULL) 14927043Seric continue; 14937043Seric 14947043Seric /* owner list exists -- add it to the error queue */ 14957043Seric qq->q_flags &= ~QPRIMARY; 14967043Seric sendto(obuf, 1, qq, &e->e_errorqueue); 14977043Seric MailBack = TRUE; 14987043Seric break; 14997043Seric } 15007043Seric 15017043Seric /* if we did not find an owner, send to the sender */ 15027043Seric if (qq == NULL) 15037043Seric sendto(e->e_from.q_paddr, 1, qq, &e->e_errorqueue); 15047043Seric } 15054550Seric } 15067043Seric /* 15077043Seric ** CHECKERRORS -- check a queue of addresses and process errors. 15087043Seric ** 15097043Seric ** Parameters: 15107043Seric ** e -- the envelope to check. 15117043Seric ** 15127043Seric ** Returns: 15137043Seric ** none. 15147043Seric ** 15157043Seric ** Side Effects: 15167043Seric ** Arranges to queue all tempfailed messages in q 15177043Seric ** or deliver error responses. 15187043Seric */ 15197043Seric 15207043Seric checkerrors(e) 15217043Seric register ENVELOPE *e; 15227043Seric { 15237043Seric # ifdef DEBUG 15247043Seric if (Debug > 0) 15257043Seric { 15267043Seric printf("\ncheckerrors: errorqueue:\n"); 15277043Seric printaddr(e->e_errorqueue, TRUE); 15287043Seric } 15297043Seric # endif DEBUG 15307043Seric 15317043Seric /* mail back the transcript on errors */ 15327043Seric if (FatalErrors) 15337043Seric savemail(); 15347043Seric 15357043Seric /* queue up anything laying around */ 15367043Seric if (e->e_queueup) 15377043Seric { 15387043Seric # ifdef QUEUE 15397043Seric queueup(e, FALSE); 15407043Seric # else QUEUE 15417043Seric syserr("finis: trying to queue %s", e->e_df); 15427043Seric # endif QUEUE 15437043Seric } 15447043Seric } 1545