1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*9148Seric SCCSID(@(#)deliver.c 3.127 11/13/82); 7405Seric 8294Seric /* 94315Seric ** DELIVER -- Deliver a message to a list of addresses. 10294Seric ** 114315Seric ** This routine delivers to everyone on the same host as the 124315Seric ** user on the head of the list. It is clever about mailers 134315Seric ** that don't handle multiple users. It is NOT guaranteed 144315Seric ** that it will deliver to all these addresses however -- so 154315Seric ** deliver should be called once for each address on the 164315Seric ** list. 174315Seric ** 18294Seric ** Parameters: 194621Seric ** firstto -- head of the address list to deliver to. 20294Seric ** 21294Seric ** Returns: 22294Seric ** zero -- successfully delivered. 23294Seric ** else -- some failure, see ExitStat for more info. 24294Seric ** 25294Seric ** Side Effects: 26294Seric ** The standard input is passed off to someone. 27294Seric */ 28294Seric 296974Seric deliver(firstto) 304621Seric ADDRESS *firstto; 31294Seric { 324452Seric char *host; /* host being sent to */ 334452Seric char *user; /* user being sent to */ 34294Seric char **pvp; 353233Seric register char **mvp; 363233Seric register char *p; 374452Seric register struct mailer *m; /* mailer for this recipient */ 382968Seric extern bool checkcompat(); 393233Seric char *pv[MAXPV+1]; 408225Seric char tobuf[MAXLINE-50]; /* text line of to people */ 413233Seric char buf[MAXNAME]; 424397Seric ADDRESS *ctladdr; 434397Seric extern ADDRESS *getctladdr(); 444452Seric char tfrombuf[MAXNAME]; /* translated from person */ 454452Seric extern char **prescan(); 464621Seric register ADDRESS *to = firstto; 474863Seric bool clever = FALSE; /* running user smtp to this mailer */ 485032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 497052Seric bool notopen = TRUE; /* set if connection not quite open */ 508003Seric register int rcode; /* response code */ 51294Seric 524488Seric errno = 0; 537052Seric if (bitset(QDONTSEND, to->q_flags)) 543233Seric return (0); 55294Seric 566974Seric m = to->q_mailer; 576974Seric host = to->q_host; 586974Seric 59294Seric # ifdef DEBUG 607672Seric if (tTd(10, 1)) 613233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 626974Seric m->m_mno, host, to->q_user); 63294Seric # endif DEBUG 64294Seric 65294Seric /* 665903Seric ** If this mailer is expensive, and if we don't want to make 675903Seric ** connections now, just mark these addresses and return. 685903Seric ** This is useful if we want to batch connections to 695903Seric ** reduce load. This will cause the messages to be 705903Seric ** queued up, and a daemon will come along to send the 715903Seric ** messages later. 725903Seric ** This should be on a per-mailer basis. 735903Seric */ 745903Seric 758428Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags) && 768428Seric !Verbose) 775903Seric { 785903Seric for (; to != NULL; to = to->q_next) 798431Seric { 808431Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 818431Seric continue; 828431Seric to->q_flags |= QQUEUEUP|QDONTSEND; 838431Seric CurEnv->e_to = to->q_paddr; 848496Seric message(Arpa_Info, "queued"); 858496Seric if (LogLevel > 4) 868496Seric logdelivery("queued"); 878431Seric } 888431Seric CurEnv->e_to = NULL; 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. 998062Seric ** The from address rewrite is expected to make 1008062Seric ** the address relative to the other end. 1012968Seric */ 1022968Seric 1034452Seric /* rewrite from address, using rewriting rules */ 1048062Seric expand("$f", buf, &buf[sizeof buf - 1], CurEnv); 1054452Seric mvp = prescan(buf, '\0'); 1068062Seric rewrite(mvp, m->m_s_rwset); 1074452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 1084452Seric 1094452Seric define('g', tfrombuf); /* translated sender address */ 1103233Seric define('h', host); /* to host */ 1113233Seric Errors = 0; 1123233Seric pvp = pv; 1133233Seric *pvp++ = m->m_argv[0]; 1142968Seric 1153233Seric /* insert -f or -r flag as appropriate */ 1163233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1173233Seric { 1183233Seric if (bitset(M_FOPT, m->m_flags)) 1193233Seric *pvp++ = "-f"; 1203233Seric else 1213233Seric *pvp++ = "-r"; 1226974Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1233233Seric *pvp++ = newstr(buf); 1243233Seric } 125294Seric 126294Seric /* 1273233Seric ** Append the other fixed parts of the argv. These run 1283233Seric ** up to the first entry containing "$u". There can only 1293233Seric ** be one of these, and there are only a few more slots 1303233Seric ** in the pv after it. 131294Seric */ 132294Seric 1333233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 134294Seric { 1353233Seric while ((p = index(p, '$')) != NULL) 1363233Seric if (*++p == 'u') 1373233Seric break; 1383233Seric if (p != NULL) 1393233Seric break; 1403233Seric 1413233Seric /* this entry is safe -- go ahead and process it */ 1426974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 1433233Seric *pvp++ = newstr(buf); 1443233Seric if (pvp >= &pv[MAXPV - 3]) 1453233Seric { 1463233Seric syserr("Too many parameters to %s before $u", pv[0]); 1473233Seric return (-1); 1483233Seric } 149294Seric } 1504863Seric 1516038Seric /* 1526038Seric ** If we have no substitution for the user name in the argument 1536038Seric ** list, we know that we must supply the names otherwise -- and 1546038Seric ** SMTP is the answer!! 1556038Seric */ 1566038Seric 1573233Seric if (*mvp == NULL) 1584863Seric { 1594863Seric /* running SMTP */ 1605179Seric # ifdef SMTP 1614863Seric clever = TRUE; 1624863Seric *pvp = NULL; 1635179Seric # else SMTP 1646038Seric /* oops! we don't implement SMTP */ 1655179Seric syserr("SMTP style mailer"); 1665179Seric return (EX_SOFTWARE); 1675179Seric # endif SMTP 1684863Seric } 169294Seric 170294Seric /* 1713233Seric ** At this point *mvp points to the argument with $u. We 1723233Seric ** run through our address list and append all the addresses 1733233Seric ** we can. If we run out of space, do not fret! We can 1743233Seric ** always send another copy later. 175294Seric */ 176294Seric 1773233Seric tobuf[0] = '\0'; 1786900Seric CurEnv->e_to = tobuf; 1794397Seric ctladdr = NULL; 1803233Seric for (; to != NULL; to = to->q_next) 181294Seric { 1823233Seric /* avoid sending multiple recipients to dumb mailers */ 1834382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1843233Seric break; 1853233Seric 1863233Seric /* if already sent or not for this host, don't send */ 1877052Seric if (bitset(QDONTSEND, to->q_flags) || 1887052Seric strcmp(to->q_host, host) != 0 || 1897052Seric to->q_mailer != firstto->q_mailer) 1903233Seric continue; 1914397Seric 1928225Seric /* avoid overflowing tobuf */ 1938225Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 1) < 0) 1948225Seric break; 1958225Seric 1965032Seric # ifdef DEBUG 1977672Seric if (tTd(10, 1)) 1985032Seric { 1995032Seric printf("\nsend to "); 2005032Seric printaddr(to, FALSE); 2015032Seric } 2025032Seric # endif DEBUG 2035032Seric 2044397Seric /* compute effective uid/gid when sending */ 2054596Seric if (to->q_mailer == ProgMailer) 2064397Seric ctladdr = getctladdr(to); 2074397Seric 2083233Seric user = to->q_user; 2096900Seric CurEnv->e_to = to->q_paddr; 2103233Seric to->q_flags |= QDONTSEND; 2113233Seric 2123233Seric /* 2133233Seric ** Check to see that these people are allowed to 2143233Seric ** talk to each other. 2153233Seric */ 2163233Seric 2173233Seric if (!checkcompat(to)) 218294Seric { 2193233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 2203233Seric continue; 221294Seric } 2223233Seric 2233233Seric /* 2244099Seric ** Strip quote bits from names if the mailer is dumb 2254099Seric ** about them. 2263233Seric */ 2273233Seric 2283233Seric if (bitset(M_STRIPQ, m->m_flags)) 229294Seric { 2304099Seric stripquotes(user, TRUE); 2314099Seric stripquotes(host, TRUE); 2323233Seric } 2334099Seric else 2344099Seric { 2354099Seric stripquotes(user, FALSE); 2364099Seric stripquotes(host, FALSE); 2374099Seric } 2383233Seric 2393233Seric /* 2407052Seric ** Do initial connection setup if needed. 2417052Seric */ 2427052Seric 2437052Seric if (notopen) 2447052Seric { 2457052Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 2467052Seric # ifdef SMTP 2477052Seric if (clever) 2487052Seric { 2497052Seric /* send the initial SMTP protocol */ 2508003Seric rcode = smtpinit(m, pv, (ADDRESS *) NULL); 2517052Seric } 2527052Seric # ifdef SMTP 2537052Seric notopen = FALSE; 2547052Seric } 2557052Seric 2567052Seric /* 2576059Seric ** Pass it to the other host if we are running SMTP. 2586059Seric */ 2596059Seric 2606059Seric if (clever) 2616059Seric { 2626059Seric # ifdef SMTP 2638003Seric if (rcode == EX_OK) 2648003Seric rcode = smtprcpt(to); 2658003Seric if (rcode != EX_OK) 2666059Seric { 2678003Seric if (rcode == EX_TEMPFAIL) 2686059Seric to->q_flags |= QQUEUEUP; 2696059Seric else 2706059Seric to->q_flags |= QBADADDR; 2718003Seric giveresponse(rcode, TRUE, m); 2726059Seric } 2736059Seric # else SMTP 2746059Seric syserr("trying to be clever"); 2756059Seric # endif SMTP 2766059Seric } 2776059Seric 2786059Seric /* 2794161Seric ** If an error message has already been given, don't 2804161Seric ** bother to send to this address. 2814161Seric ** 2824161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2834161Seric ** >> NOTE >> cannot do any further aliasing; that 2844161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2854161Seric */ 2864161Seric 2877293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2884161Seric continue; 2894161Seric 2904283Seric /* save statistics.... */ 2914596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2926900Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(CurEnv->e_msgsize); 2934283Seric 2944161Seric /* 2953233Seric ** See if this user name is "special". 2963233Seric ** If the user name has a slash in it, assume that this 2976974Seric ** is a file -- send it off without further ado. Note 2986974Seric ** that this type of addresses is not processed along 2996974Seric ** with the others, so we fudge on the To person. 3003233Seric */ 3013233Seric 3024596Seric if (m == LocalMailer) 3033233Seric { 3045599Seric if (user[0] == '/') 305294Seric { 3068003Seric rcode = mailfile(user, getctladdr(to)); 3078003Seric giveresponse(rcode, TRUE, m); 3083233Seric continue; 309294Seric } 310294Seric } 3113233Seric 3124315Seric /* 3134315Seric ** Address is verified -- add this user to mailer 3144315Seric ** argv, and add it to the print list of recipients. 3154315Seric */ 3164315Seric 3176059Seric /* link together the chain of recipients */ 3186272Seric to->q_tchain = tochain; 3196272Seric tochain = to; 3206059Seric 3213233Seric /* create list of users for error messages */ 3223233Seric if (tobuf[0] != '\0') 3234082Seric (void) strcat(tobuf, ","); 3244082Seric (void) strcat(tobuf, to->q_paddr); 3253233Seric define('u', user); /* to user */ 3264078Seric define('z', to->q_home); /* user's home */ 3273233Seric 3284863Seric /* 3296059Seric ** Expand out this user into argument list. 3304863Seric */ 3314863Seric 3326059Seric if (!clever) 3333233Seric { 3346974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3354863Seric *pvp++ = newstr(buf); 3364863Seric if (pvp >= &pv[MAXPV - 2]) 3374863Seric { 3384863Seric /* allow some space for trailing parms */ 3394863Seric break; 3404863Seric } 3414863Seric } 342294Seric } 343294Seric 3444067Seric /* see if any addresses still exist */ 3454067Seric if (tobuf[0] == '\0') 3464863Seric { 3475179Seric # ifdef SMTP 3488906Seric if (clever && !notopen) 3497228Seric smtpquit(pv[0], FALSE); 3505179Seric # endif SMTP 3517003Seric define('g', (char *) NULL); 3524067Seric return (0); 3534863Seric } 3544067Seric 3553233Seric /* print out messages as full list */ 3566900Seric CurEnv->e_to = tobuf; 3573233Seric 358294Seric /* 3593233Seric ** Fill out any parameters after the $u parameter. 360294Seric */ 361294Seric 3624863Seric while (!clever && *++mvp != NULL) 363294Seric { 3646974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3653233Seric *pvp++ = newstr(buf); 3663233Seric if (pvp >= &pv[MAXPV]) 3673233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 368294Seric } 3693233Seric *pvp++ = NULL; 370294Seric 371294Seric /* 372294Seric ** Call the mailer. 3732898Seric ** The argument vector gets built, pipes 374294Seric ** are created as necessary, and we fork & exec as 3752898Seric ** appropriate. 3764863Seric ** If we are running SMTP, we just need to clean up. 377294Seric */ 378294Seric 3794397Seric if (ctladdr == NULL) 3806900Seric ctladdr = &CurEnv->e_from; 3815179Seric # ifdef SMTP 3824863Seric if (clever) 3834863Seric { 3848003Seric rcode = smtpfinish(m, CurEnv); 3858003Seric if (rcode != EX_OK) 3868003Seric giveresponse(rcode, TRUE, m); 3878003Seric smtpquit(pv[0], rcode == EX_OK); 3884863Seric } 3894863Seric else 3905179Seric # endif SMTP 3918003Seric rcode = sendoff(m, pv, ctladdr); 3923233Seric 3934621Seric /* 3944621Seric ** If we got a temporary failure, arrange to queue the 3954621Seric ** addressees. 3964621Seric */ 3974621Seric 3988003Seric if (rcode == EX_TEMPFAIL) 3994621Seric { 4005032Seric for (to = tochain; to != NULL; to = to->q_tchain) 4014621Seric to->q_flags |= QQUEUEUP; 4024621Seric } 4034621Seric 4044488Seric errno = 0; 4057003Seric define('g', (char *) NULL); 4068003Seric return (rcode); 4073233Seric } 4083233Seric /* 4094214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4104214Seric ** 4114214Seric ** This MUST be a macro, since after a vfork we are running 4124214Seric ** two processes on the same stack!!! 4134214Seric ** 4144214Seric ** Parameters: 4154214Seric ** none. 4164214Seric ** 4174214Seric ** Returns: 4184214Seric ** From a macro??? You've got to be kidding! 4194214Seric ** 4204214Seric ** Side Effects: 4214214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4224214Seric ** pid of child in parent, zero in child. 4234214Seric ** -1 on unrecoverable error. 4244214Seric ** 4254214Seric ** Notes: 4264214Seric ** I'm awfully sorry this looks so awful. That's 4274214Seric ** vfork for you..... 4284214Seric */ 4294214Seric 4304214Seric # define NFORKTRIES 5 431*9148Seric # ifdef VMUNIX 4324214Seric # define XFORK vfork 433*9148Seric # else VMUNIX 4344214Seric # define XFORK fork 435*9148Seric # endif VMUNIX 4364214Seric 4374214Seric # define DOFORK(fORKfN) \ 4384214Seric {\ 4394214Seric register int i;\ 4404214Seric \ 4414214Seric for (i = NFORKTRIES; i-- > 0; )\ 4424214Seric {\ 4434214Seric pid = fORKfN();\ 4444214Seric if (pid >= 0)\ 4454214Seric break;\ 4467003Seric sleep(NFORKTRIES - i);\ 4474214Seric }\ 4484214Seric } 4494214Seric /* 4504637Seric ** DOFORK -- simple fork interface to DOFORK. 4514637Seric ** 4524637Seric ** Parameters: 4534637Seric ** none. 4544637Seric ** 4554637Seric ** Returns: 4564637Seric ** pid of child in parent. 4574637Seric ** zero in child. 4584637Seric ** -1 on error. 4594637Seric ** 4604637Seric ** Side Effects: 4614637Seric ** returns twice, once in parent and once in child. 4624637Seric */ 4634637Seric 4644637Seric dofork() 4654637Seric { 4664637Seric register int pid; 4674637Seric 4684637Seric DOFORK(fork); 4694637Seric return (pid); 4704637Seric } 4714637Seric /* 4723233Seric ** SENDOFF -- send off call to mailer & collect response. 4733233Seric ** 4743233Seric ** Parameters: 4753233Seric ** m -- mailer descriptor. 4763233Seric ** pvp -- parameter vector to send to it. 4774397Seric ** ctladdr -- an address pointer controlling the 4784397Seric ** user/groupid etc. of the mailer. 4793233Seric ** 4803233Seric ** Returns: 4813233Seric ** exit status of mailer. 4823233Seric ** 4833233Seric ** Side Effects: 4843233Seric ** none. 4853233Seric */ 4863233Seric 4876974Seric sendoff(m, pvp, ctladdr) 4883233Seric struct mailer *m; 4893233Seric char **pvp; 4904397Seric ADDRESS *ctladdr; 4913233Seric { 4924863Seric auto FILE *mfile; 4934863Seric auto FILE *rfile; 4943233Seric register int i; 4953233Seric int pid; 4964863Seric 4974863Seric /* 4984863Seric ** Create connection to mailer. 4994863Seric */ 5004863Seric 5014863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5024863Seric if (pid < 0) 5034863Seric return (-1); 5044863Seric 5054863Seric /* 5064863Seric ** Format and send message. 5074863Seric */ 5084863Seric 5094863Seric (void) signal(SIGPIPE, SIG_IGN); 5106974Seric putfromline(mfile, m); 5116974Seric (*CurEnv->e_puthdr)(mfile, m, CurEnv); 5126974Seric fprintf(mfile, "\n"); 5136974Seric (*CurEnv->e_putbody)(mfile, m, FALSE); 5144863Seric (void) fclose(mfile); 5154863Seric 5164863Seric i = endmailer(pid, pvp[0]); 5174863Seric giveresponse(i, TRUE, m); 5185981Seric 5195981Seric /* arrange a return receipt if requested */ 5208062Seric if (CurEnv->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 5215981Seric { 5226900Seric CurEnv->e_sendreceipt = TRUE; 5238062Seric if (ExitStat == EX_OK) 5248062Seric fprintf(Xscript, "%s... successfully delivered\n", 5258062Seric CurEnv->e_to); 5265981Seric /* do we want to send back more info? */ 5275981Seric } 5285981Seric 5294863Seric return (i); 5304863Seric } 5314863Seric /* 5324863Seric ** ENDMAILER -- Wait for mailer to terminate. 5334863Seric ** 5344863Seric ** We should never get fatal errors (e.g., segmentation 5354863Seric ** violation), so we report those specially. For other 5364863Seric ** errors, we choose a status message (into statmsg), 5374863Seric ** and if it represents an error, we print it. 5384863Seric ** 5394863Seric ** Parameters: 5404863Seric ** pid -- pid of mailer. 5414863Seric ** name -- name of mailer (for error messages). 5424863Seric ** 5434863Seric ** Returns: 5444863Seric ** exit code of mailer. 5454863Seric ** 5464863Seric ** Side Effects: 5474863Seric ** none. 5484863Seric */ 5494863Seric 5504863Seric endmailer(pid, name) 5514863Seric int pid; 5524863Seric char *name; 5534863Seric { 5544863Seric register int i; 5554863Seric auto int st; 5564863Seric 5576038Seric /* in the IPC case there is nothing to wait for */ 5586038Seric if (pid == 0) 5596038Seric return (EX_OK); 5606038Seric 5616038Seric /* wait for the mailer process to die and collect status */ 5628127Seric do 5638127Seric { 5648127Seric errno = 0; 5658127Seric i = wait(&st); 5668133Seric } while ((i >= 0 && i != pid) || errno == EINTR); 5674863Seric if (i < 0) 5684863Seric { 5694863Seric syserr("wait"); 5704863Seric return (-1); 5714863Seric } 5726038Seric 5736038Seric /* see if it died a horrid death */ 5744863Seric if ((st & 0377) != 0) 5754863Seric { 5764863Seric syserr("%s: stat %o", name, st); 5774863Seric ExitStat = EX_UNAVAILABLE; 5784863Seric return (-1); 5794863Seric } 5806038Seric 5816038Seric /* normal death -- return status */ 5824863Seric i = (st >> 8) & 0377; 5834863Seric return (i); 5844863Seric } 5854863Seric /* 5864863Seric ** OPENMAILER -- open connection to mailer. 5874863Seric ** 5884863Seric ** Parameters: 5894863Seric ** m -- mailer descriptor. 5904863Seric ** pvp -- parameter vector to pass to mailer. 5914863Seric ** ctladdr -- controlling address for user. 5924863Seric ** clever -- create a full duplex connection. 5934863Seric ** pmfile -- pointer to mfile (to mailer) connection. 5944863Seric ** prfile -- pointer to rfile (from mailer) connection. 5954863Seric ** 5964863Seric ** Returns: 5976038Seric ** pid of mailer ( > 0 ). 5984863Seric ** -1 on error. 5996038Seric ** zero on an IPC connection. 6004863Seric ** 6014863Seric ** Side Effects: 6024863Seric ** creates a mailer in a subprocess. 6034863Seric */ 6044863Seric 6054863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6064863Seric struct mailer *m; 6074863Seric char **pvp; 6084863Seric ADDRESS *ctladdr; 6094863Seric bool clever; 6104863Seric FILE **pmfile; 6114863Seric FILE **prfile; 6124863Seric { 6134863Seric int pid; 6144709Seric int mpvect[2]; 6154863Seric int rpvect[2]; 6163233Seric FILE *mfile; 6174863Seric FILE *rfile; 6183233Seric extern FILE *fdopen(); 6193233Seric 6203233Seric # ifdef DEBUG 6217672Seric if (tTd(11, 1)) 622294Seric { 6238178Seric printf("openmailer:"); 6243233Seric printav(pvp); 625294Seric } 6263233Seric # endif DEBUG 6274488Seric errno = 0; 6283233Seric 6296038Seric # ifdef DAEMON 6306038Seric /* 6316038Seric ** Deal with the special case of mail handled through an IPC 6326038Seric ** connection. 6336038Seric ** In this case we don't actually fork. We must be 6346038Seric ** running SMTP for this to work. We will return a 6356038Seric ** zero pid to indicate that we are running IPC. 6366038Seric */ 6376038Seric 6386038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6396038Seric { 6406038Seric register int i; 6417285Seric register u_short port; 6426038Seric 6436038Seric if (!clever) 6446038Seric syserr("non-clever IPC"); 6456632Seric if (pvp[2] != NULL) 6467285Seric port = atoi(pvp[2]); 6476632Seric else 6487285Seric port = 0; 6497285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 6506038Seric if (i != EX_OK) 6516047Seric { 6526047Seric ExitStat = i; 6536038Seric return (-1); 6546047Seric } 6556038Seric else 6566038Seric return (0); 6576038Seric } 6586038Seric # endif DAEMON 6596038Seric 6602898Seric /* create a pipe to shove the mail through */ 6614709Seric if (pipe(mpvect) < 0) 662294Seric { 6634863Seric syserr("pipe (to mailer)"); 664294Seric return (-1); 665294Seric } 6664863Seric 6675179Seric # ifdef SMTP 6684863Seric /* if this mailer speaks smtp, create a return pipe */ 6694863Seric if (clever && pipe(rpvect) < 0) 6704863Seric { 6714863Seric syserr("pipe (from mailer)"); 6724863Seric (void) close(mpvect[0]); 6734863Seric (void) close(mpvect[1]); 6744863Seric return (-1); 6754863Seric } 6765179Seric # endif SMTP 6774863Seric 6786038Seric /* 6796038Seric ** Actually fork the mailer process. 6806038Seric ** DOFORK is clever about retrying. 6816038Seric */ 6826038Seric 6837672Seric (void) fflush(Xscript); /* for debugging */ 6844214Seric DOFORK(XFORK); 6854327Seric /* pid is set by DOFORK */ 686294Seric if (pid < 0) 687294Seric { 6886038Seric /* failure */ 689294Seric syserr("Cannot fork"); 6904709Seric (void) close(mpvect[0]); 6914709Seric (void) close(mpvect[1]); 6924863Seric if (clever) 6934863Seric { 6944863Seric (void) close(rpvect[0]); 6954863Seric (void) close(rpvect[1]); 6964863Seric } 697294Seric return (-1); 698294Seric } 699294Seric else if (pid == 0) 700294Seric { 701294Seric /* child -- set up input & exec mailer */ 7021621Seric /* make diagnostic output be standard output */ 7034477Seric (void) signal(SIGINT, SIG_IGN); 7044477Seric (void) signal(SIGHUP, SIG_IGN); 7054215Seric (void) signal(SIGTERM, SIG_DFL); 7064709Seric 7074709Seric /* arrange to filter standard & diag output of command */ 7084863Seric if (clever) 7094709Seric { 7104863Seric (void) close(rpvect[0]); 7114709Seric (void) close(1); 7124863Seric (void) dup(rpvect[1]); 7134863Seric (void) close(rpvect[1]); 7144863Seric } 7159107Seric else if (Smtp || HoldErrs) 7164863Seric { 7174863Seric (void) close(1); 7189107Seric (void) dup(fileno(Xscript)); 7194709Seric } 7204082Seric (void) close(2); 7214082Seric (void) dup(1); 7224709Seric 7234709Seric /* arrange to get standard input */ 7244709Seric (void) close(mpvect[1]); 7254082Seric (void) close(0); 7264709Seric if (dup(mpvect[0]) < 0) 727294Seric { 7282898Seric syserr("Cannot dup to zero!"); 7292898Seric _exit(EX_OSERR); 730294Seric } 7314709Seric (void) close(mpvect[0]); 7322968Seric if (!bitset(M_RESTR, m->m_flags)) 7334215Seric { 7344417Seric if (ctladdr->q_uid == 0) 7354417Seric { 7364417Seric (void) setgid(DefGid); 7374417Seric (void) setuid(DefUid); 7384417Seric } 7394417Seric else 7404415Seric { 7414417Seric (void) setgid(ctladdr->q_gid); 7424417Seric (void) setuid(ctladdr->q_uid); 7434415Seric } 7444215Seric } 745*9148Seric # ifndef VMUNIX 7462774Seric /* 7472774Seric ** We have to be careful with vfork - we can't mung up the 7482774Seric ** memory but we don't want the mailer to inherit any extra 7492774Seric ** open files. Chances are the mailer won't 7502774Seric ** care about an extra file, but then again you never know. 7512774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7522774Seric ** declared static so we can't. But if we fclose(pwf), which 7532774Seric ** is what endpwent does, it closes it in the parent too and 7542774Seric ** the next getpwnam will be slower. If you have a weird 7552774Seric ** mailer that chokes on the extra file you should do the 756*9148Seric ** endpwent(). -MRH 7572774Seric ** 7582774Seric ** Similar comments apply to log. However, openlog is 7592774Seric ** clever enough to set the FIOCLEX mode on the file, 7602774Seric ** so it will be closed automatically on the exec. 7612774Seric */ 7622774Seric 7632774Seric endpwent(); 764294Seric # ifdef LOG 7652089Seric closelog(); 766294Seric # endif LOG 767*9148Seric # endif VMUNIX 7686038Seric 7696038Seric /* try to execute the mailer */ 770294Seric execv(m->m_mailer, pvp); 7716038Seric 772294Seric /* syserr fails because log is closed */ 773294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 7744214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 7754082Seric (void) fflush(stdout); 7761619Seric _exit(EX_UNAVAILABLE); 777294Seric } 778294Seric 7794709Seric /* 7804863Seric ** Set up return value. 7814709Seric */ 7824709Seric 7834709Seric (void) close(mpvect[0]); 7844709Seric mfile = fdopen(mpvect[1], "w"); 7854863Seric if (clever) 7864863Seric { 7874863Seric (void) close(rpvect[1]); 7884863Seric rfile = fdopen(rpvect[0], "r"); 7894863Seric } 790294Seric 7914863Seric *pmfile = mfile; 7924863Seric *prfile = rfile; 793294Seric 7944863Seric return (pid); 795294Seric } 796294Seric /* 797294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 798294Seric ** 799294Seric ** Parameters: 800294Seric ** stat -- the status code from the mailer (high byte 801294Seric ** only; core dumps must have been taken care of 802294Seric ** already). 803294Seric ** force -- if set, force an error message output, even 804294Seric ** if the mailer seems to like to print its own 805294Seric ** messages. 806294Seric ** m -- the mailer descriptor for this mailer. 807294Seric ** 808294Seric ** Returns: 8094082Seric ** none. 810294Seric ** 811294Seric ** Side Effects: 8121518Seric ** Errors may be incremented. 813294Seric ** ExitStat may be set. 814294Seric */ 815294Seric 816294Seric giveresponse(stat, force, m) 817294Seric int stat; 8187228Seric bool force; 819294Seric register struct mailer *m; 820294Seric { 821294Seric register char *statmsg; 822294Seric extern char *SysExMsg[]; 823294Seric register int i; 824294Seric extern int N_SysEx; 8251624Seric char buf[30]; 826294Seric 8274315Seric /* 8284315Seric ** Compute status message from code. 8294315Seric */ 8304315Seric 831294Seric i = stat - EX__BASE; 832294Seric if (i < 0 || i > N_SysEx) 833294Seric statmsg = NULL; 834294Seric else 835294Seric statmsg = SysExMsg[i]; 836294Seric if (stat == 0) 8374065Seric { 8388003Seric statmsg = "250 sent"; 8398003Seric message(Arpa_Info, &statmsg[4]); 8404065Seric } 8414621Seric else if (stat == EX_TEMPFAIL) 8424621Seric { 8438496Seric message(Arpa_Info, "deferred"); 8444621Seric } 845294Seric else 846294Seric { 8471518Seric Errors++; 8486047Seric FatalErrors = TRUE; 849294Seric if (statmsg == NULL && m->m_badstat != 0) 850294Seric { 851294Seric stat = m->m_badstat; 852294Seric i = stat - EX__BASE; 853294Seric # ifdef DEBUG 854294Seric if (i < 0 || i >= N_SysEx) 855294Seric syserr("Bad m_badstat %d", stat); 856294Seric else 857294Seric # endif DEBUG 8587344Seric statmsg = SysExMsg[i]; 859294Seric } 860294Seric if (statmsg == NULL) 861294Seric usrerr("unknown mailer response %d", stat); 8624065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 8638003Seric usrerr(statmsg); 8647344Seric else 8658003Seric fprintf(Xscript, "%s\n", &statmsg[4]); 866294Seric } 867294Seric 868294Seric /* 869294Seric ** Final cleanup. 870294Seric ** Log a record of the transaction. Compute the new 871294Seric ** ExitStat -- if we already had an error, stick with 872294Seric ** that. 873294Seric */ 874294Seric 8751624Seric if (statmsg == NULL) 8761624Seric { 8778003Seric (void) sprintf(buf, "554 error %d", stat); 8781624Seric statmsg = buf; 8791624Seric } 8801624Seric 8818496Seric /* log it in the system log */ 8827680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 8838496Seric logdelivery(&statmsg[4]); 8847858Seric 8858496Seric /* set the exit status appropriately */ 8864621Seric if (stat != EX_TEMPFAIL) 8874621Seric setstat(stat); 888294Seric } 889294Seric /* 8908496Seric ** LOGDELIVERY -- log the delivery in the system log 8918496Seric ** 8928496Seric ** Parameters: 8938496Seric ** stat -- the message to print for the status 8948496Seric ** 8958496Seric ** Returns: 8968496Seric ** none 8978496Seric ** 8988496Seric ** Side Effects: 8998496Seric ** none 9008496Seric */ 9018496Seric 9028496Seric logdelivery(stat) 9038496Seric char *stat; 9048496Seric { 9058496Seric extern char *pintvl(); 9068496Seric 9078496Seric # ifdef LOG 9088496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 9098496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 9108496Seric # endif LOG 9118496Seric } 9128496Seric /* 9136974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 914294Seric ** 9156974Seric ** This can be made an arbitrary message separator by changing $l 916294Seric ** 9176974Seric ** One of the ugliest hacks seen by human eyes is 9186974Seric ** contained herein: UUCP wants those stupid 9196974Seric ** "remote from <host>" lines. Why oh why does a 9206974Seric ** well-meaning programmer such as myself have to 9216974Seric ** deal with this kind of antique garbage???? 9226974Seric ** 923294Seric ** Parameters: 9246974Seric ** fp -- the file to output to. 9256974Seric ** m -- the mailer describing this entry. 926294Seric ** 927294Seric ** Returns: 9286974Seric ** none 929294Seric ** 930294Seric ** Side Effects: 9316974Seric ** outputs some text to fp. 932294Seric */ 933294Seric 9346974Seric putfromline(fp, m) 9356974Seric register FILE *fp; 9366974Seric register MAILER *m; 937294Seric { 9386974Seric char buf[MAXLINE]; 939294Seric 9406974Seric if (bitset(M_NHDR, m->m_flags)) 9416974Seric return; 9424315Seric 9436974Seric # ifdef UGLYUUCP 9446974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9454205Seric { 9466974Seric extern char *macvalue(); 9478178Seric char *sys = macvalue('g', CurEnv); 9486974Seric char *bang = index(sys, '!'); 9496041Seric 9506974Seric if (bang == NULL) 9516974Seric syserr("No ! in UUCP! (%s)", sys); 9525099Seric else 9536974Seric *bang = '\0'; 9547232Seric expand("From $f $d remote from $g\n", buf, 9556974Seric &buf[sizeof buf - 1], CurEnv); 9566974Seric *bang = '!'; 9576974Seric } 9586974Seric else 9595179Seric # endif UGLYUUCP 9606974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 9617123Seric putline(buf, fp, bitset(M_FULLSMTP, m->m_flags)); 9625981Seric } 9635981Seric /* 9646974Seric ** PUTHEADER -- put the header part of a message from the in-core copy 9655981Seric ** 9665981Seric ** Parameters: 9675981Seric ** fp -- file to put it on. 9685981Seric ** m -- mailer to use. 9696974Seric ** e -- envelope to use. 9705981Seric ** 9715981Seric ** Returns: 9725981Seric ** none. 9735981Seric ** 9745981Seric ** Side Effects: 9755981Seric ** none. 9765981Seric */ 9775981Seric 9786974Seric putheader(fp, m, e) 9795981Seric register FILE *fp; 9805981Seric register struct mailer *m; 9816974Seric register ENVELOPE *e; 9825981Seric { 9835981Seric char buf[BUFSIZ]; 9845981Seric register HDR *h; 9855981Seric extern char *arpadate(); 9865981Seric extern char *capitalize(); 9875981Seric extern bool samefrom(); 9887123Seric char obuf[MAXLINE]; 9897123Seric register char *obp; 9907123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 9915981Seric 9928434Seric if (bitset(M_LOCAL, m->m_flags) && fullsmtp) 9938434Seric fprintf(fp, "Return-Path: <%s>\n", e->e_from); 9946974Seric for (h = e->e_header; h != NULL; h = h->h_link) 9951828Seric { 9964315Seric register char *p; 9974315Seric 9983389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 9998062Seric continue; 10004447Seric 10017756Seric p = h->h_value; 10028062Seric if (bitset(H_DEFAULT, h->h_flags)) 10033385Seric { 10047666Seric /* macro expand value if generated internally */ 10058062Seric expand(p, buf, &buf[sizeof buf], e); 10063385Seric p = buf; 10073385Seric } 10084447Seric if (p == NULL || *p == '\0') 10093389Seric continue; 10104209Seric 10118062Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 10124209Seric { 10138062Seric /* address field */ 10148093Seric bool oldstyle = e->e_oldstyle; 10158093Seric 10168093Seric if (bitset(H_FROM, h->h_flags)) 10178093Seric oldstyle = FALSE; 10188093Seric commaize(h, p, fp, oldstyle, m); 10194447Seric } 10208062Seric else 10214447Seric { 10228062Seric /* vanilla header line */ 10237123Seric (void) sprintf(obuf, "%s: %s\n", capitalize(h->h_field), p); 10247123Seric putline(obuf, fp, fullsmtp); 10254209Seric } 10268062Seric h->h_flags |= H_USED; 10272898Seric } 1028294Seric } 1029294Seric /* 10307756Seric ** COMMAIZE -- output a header field, making a comma-translated list. 10317756Seric ** 10327756Seric ** Parameters: 10338062Seric ** h -- the header field to output. 10348062Seric ** p -- the value to put in it. 10357756Seric ** fp -- file to put it to. 10367756Seric ** oldstyle -- TRUE if this is an old style header. 10378235Seric ** m -- a pointer to the mailer descriptor. If NULL, 10388235Seric ** don't transform the name at all. 10397756Seric ** 10407756Seric ** Returns: 10417756Seric ** none. 10427756Seric ** 10437756Seric ** Side Effects: 10447756Seric ** outputs "p" to file "fp". 10457756Seric */ 10467756Seric 10478062Seric commaize(h, p, fp, oldstyle, m) 10488062Seric register HDR *h; 10497756Seric register char *p; 10507756Seric FILE *fp; 10517756Seric bool oldstyle; 10528062Seric register MAILER *m; 10537756Seric { 10548062Seric register char *obp; 10558062Seric int opos; 10568235Seric bool fullsmtp = FALSE; 10577756Seric bool firstone = TRUE; 10587756Seric char obuf[MAXLINE]; 10597756Seric 10607756Seric /* 10617756Seric ** Output the address list translated by the 10627756Seric ** mailer and with commas. 10637756Seric */ 10647756Seric 10657756Seric # ifdef DEBUG 10667756Seric if (tTd(14, 2)) 10678062Seric printf("commaize(%s: %s)\n", h->h_field, p); 10687756Seric # endif DEBUG 10697756Seric 10708235Seric if (m != NULL && bitset(M_FULLSMTP, m->m_flags)) 10718235Seric fullsmtp = TRUE; 10728235Seric 10737756Seric obp = obuf; 10748062Seric (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 10758062Seric opos = strlen(h->h_field) + 2; 10767756Seric obp += opos; 10777756Seric 10787756Seric /* 10797756Seric ** Run through the list of values. 10807756Seric */ 10817756Seric 10827756Seric while (*p != '\0') 10837756Seric { 10847756Seric register char *name; 10857756Seric char savechar; 10868062Seric extern char *remotename(); 10878077Seric extern char *DelimChar; /* defined in prescan */ 10887756Seric 10897756Seric /* 10907756Seric ** Find the end of the name. New style names 10917756Seric ** end with a comma, old style names end with 10927756Seric ** a space character. However, spaces do not 10937756Seric ** necessarily delimit an old-style name -- at 10947756Seric ** signs mean keep going. 10957756Seric */ 10967756Seric 10978077Seric /* find end of name */ 10988077Seric while (isspace(*p) || *p == ',') 10997756Seric p++; 11007756Seric name = p; 11018077Seric for (;;) 11027756Seric { 11038077Seric char *oldp; 11047756Seric extern bool isatword(); 11057756Seric 11068091Seric (void) prescan(p, oldstyle ? ' ' : ','); 11078077Seric p = DelimChar; 11087756Seric 11097756Seric /* look to see if we have an at sign */ 11107756Seric oldp = p; 11117756Seric while (*p != '\0' && isspace(*p)) 11127756Seric p++; 11137756Seric 11147756Seric if (*p != '@' && !isatword(p)) 11157756Seric { 11167756Seric p = oldp; 11177756Seric break; 11187756Seric } 11197756Seric p += *p == '@' ? 1 : 2; 11207756Seric while (*p != '\0' && isspace(*p)) 11217756Seric p++; 11227756Seric } 11237756Seric /* at the end of one complete name */ 11247756Seric 11257756Seric /* strip off trailing white space */ 11267756Seric while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) 11277756Seric p--; 11287756Seric if (++p == name) 11297756Seric continue; 11307756Seric savechar = *p; 11317756Seric *p = '\0'; 11327756Seric 11337756Seric /* translate the name to be relative */ 11348235Seric if (m != NULL) 11358235Seric name = remotename(name, m, bitset(H_FROM, h->h_flags)); 11367756Seric if (*name == '\0') 11377756Seric { 11387756Seric *p = savechar; 11397756Seric continue; 11407756Seric } 11417756Seric 11427756Seric /* output the name with nice formatting */ 11439040Seric opos += qstrlen(name); 11447756Seric if (!firstone) 11457756Seric opos += 2; 11467756Seric if (opos > 78 && !firstone) 11477756Seric { 11487756Seric (void) sprintf(obp, ",\n"); 11497756Seric putline(obuf, fp, fullsmtp); 11507756Seric obp = obuf; 11517756Seric (void) sprintf(obp, " "); 11527756Seric obp += strlen(obp); 11537756Seric opos = 8 + strlen(name); 11547756Seric } 11557756Seric else if (!firstone) 11567756Seric { 11577756Seric (void) sprintf(obp, ", "); 11587756Seric obp += 2; 11597756Seric } 11609040Seric 11619040Seric /* strip off quote bits as we output */ 11629040Seric while (*name != '\0') 11639040Seric { 11649040Seric if (bitset(0200, *name)) 11659040Seric *obp++ = '\\'; 11669040Seric *obp++ = *name++ & ~0200; 11679040Seric } 11687756Seric firstone = FALSE; 11697756Seric *p = savechar; 11707756Seric } 11717756Seric (void) strcpy(obp, "\n"); 11727756Seric putline(obuf, fp, fullsmtp); 11737756Seric } 11747756Seric /* 11756974Seric ** PUTBODY -- put the body of a message. 11766974Seric ** 11776974Seric ** Parameters: 11786974Seric ** fp -- file to output onto. 11796974Seric ** m -- a mailer descriptor. 11806974Seric ** xdot -- if set, use SMTP hidden dot algorithm. 11816974Seric ** 11826974Seric ** Returns: 11836974Seric ** none. 11846974Seric ** 11856974Seric ** Side Effects: 11866974Seric ** The message is written onto fp. 11876974Seric */ 11886974Seric 11896974Seric putbody(fp, m, xdot) 11906974Seric FILE *fp; 11916974Seric struct mailer *m; 11926974Seric bool xdot; 11936974Seric { 11946974Seric char buf[MAXLINE + 1]; 11957123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 11966974Seric 11976974Seric /* 11986974Seric ** Output the body of the message 11996974Seric */ 12006974Seric 12017003Seric #ifdef lint 12027003Seric /* m will be needed later for complete smtp emulation */ 12037003Seric if (m == NULL) 12047003Seric return; 12057003Seric #endif lint 12067003Seric 12076974Seric if (TempFile != NULL) 12086974Seric { 12096974Seric rewind(TempFile); 12106974Seric buf[0] = '.'; 12116974Seric while (!ferror(fp) && fgets(&buf[1], sizeof buf - 1, TempFile) != NULL) 12127123Seric putline((xdot && buf[1] == '.') ? buf : &buf[1], fp, fullsmtp); 12136974Seric 12146974Seric if (ferror(TempFile)) 12156974Seric { 12166974Seric syserr("putbody: read error"); 12176974Seric ExitStat = EX_IOERR; 12186974Seric } 12196974Seric } 12206974Seric 12216974Seric (void) fflush(fp); 12226974Seric if (ferror(fp) && errno != EPIPE) 12236974Seric { 12246974Seric syserr("putbody: write error"); 12256974Seric ExitStat = EX_IOERR; 12266974Seric } 12276974Seric errno = 0; 12286974Seric } 12296974Seric /* 12305936Seric ** ISATWORD -- tell if the word we are pointing to is "at". 12315936Seric ** 12325936Seric ** Parameters: 12335936Seric ** p -- word to check. 12345936Seric ** 12355936Seric ** Returns: 12365936Seric ** TRUE -- if p is the word at. 12375936Seric ** FALSE -- otherwise. 12385936Seric ** 12395936Seric ** Side Effects: 12405936Seric ** none. 12415936Seric */ 12425936Seric 12435936Seric bool 12445936Seric isatword(p) 12455936Seric register char *p; 12465936Seric { 12475936Seric extern char lower(); 12485936Seric 12495936Seric if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 12505936Seric p[2] != '\0' && isspace(p[2])) 12515936Seric return (TRUE); 12525936Seric return (FALSE); 12535936Seric } 12545936Seric /* 12554370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 12564370Seric ** 12574370Seric ** Parameters: 12584370Seric ** ifrom -- internally generated form of from address. 12594370Seric ** efrom -- external form of from address. 12604370Seric ** 12614370Seric ** Returns: 12624370Seric ** TRUE -- if they convey the same info. 12634370Seric ** FALSE -- if any information has been lost. 12644370Seric ** 12654370Seric ** Side Effects: 12664370Seric ** none. 12674370Seric */ 12684370Seric 12694370Seric bool 12704370Seric samefrom(ifrom, efrom) 12714370Seric char *ifrom; 12724370Seric char *efrom; 12734370Seric { 12744447Seric register char *p; 12754447Seric char buf[MAXNAME + 4]; 12764447Seric 12774447Seric # ifdef DEBUG 12787672Seric if (tTd(3, 8)) 12794447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 12804447Seric # endif DEBUG 12814447Seric if (strcmp(ifrom, efrom) == 0) 12824447Seric goto success; 12834447Seric p = index(ifrom, '@'); 12844447Seric if (p == NULL) 12854447Seric goto failure; 12864447Seric *p = '\0'; 12877003Seric (void) strcpy(buf, ifrom); 12887003Seric (void) strcat(buf, " at "); 12894447Seric *p++ = '@'; 12907003Seric (void) strcat(buf, p); 12914447Seric if (strcmp(buf, efrom) == 0) 12924447Seric goto success; 12934447Seric 12944447Seric failure: 12954447Seric # ifdef DEBUG 12967672Seric if (tTd(3, 8)) 12974447Seric printf("FALSE\n"); 12984447Seric # endif DEBUG 12994447Seric return (FALSE); 13004447Seric 13014447Seric success: 13024447Seric # ifdef DEBUG 13037672Seric if (tTd(3, 8)) 13044447Seric printf("TRUE\n"); 13054447Seric # endif DEBUG 13064447Seric return (TRUE); 13074370Seric } 13084370Seric /* 1309294Seric ** MAILFILE -- Send a message to a file. 1310294Seric ** 13114327Seric ** If the file has the setuid/setgid bits set, but NO execute 13124327Seric ** bits, sendmail will try to become the owner of that file 13134327Seric ** rather than the real user. Obviously, this only works if 13144327Seric ** sendmail runs as root. 13154327Seric ** 1316294Seric ** Parameters: 1317294Seric ** filename -- the name of the file to send to. 13184397Seric ** ctladdr -- the controlling address header -- includes 13194397Seric ** the userid/groupid to be when sending. 1320294Seric ** 1321294Seric ** Returns: 1322294Seric ** The exit code associated with the operation. 1323294Seric ** 1324294Seric ** Side Effects: 1325294Seric ** none. 1326294Seric */ 1327294Seric 13284397Seric mailfile(filename, ctladdr) 1329294Seric char *filename; 13304397Seric ADDRESS *ctladdr; 1331294Seric { 1332294Seric register FILE *f; 13334214Seric register int pid; 1334294Seric 13354214Seric /* 13364214Seric ** Fork so we can change permissions here. 13374214Seric ** Note that we MUST use fork, not vfork, because of 13384214Seric ** the complications of calling subroutines, etc. 13394214Seric */ 13404067Seric 13414214Seric DOFORK(fork); 13424214Seric 13434214Seric if (pid < 0) 13444214Seric return (EX_OSERR); 13454214Seric else if (pid == 0) 13464214Seric { 13474214Seric /* child -- actually write to file */ 13484327Seric struct stat stb; 13494327Seric 13504215Seric (void) signal(SIGINT, SIG_DFL); 13514215Seric (void) signal(SIGHUP, SIG_DFL); 13524215Seric (void) signal(SIGTERM, SIG_DFL); 13534327Seric umask(OldUmask); 13544327Seric if (stat(filename, &stb) < 0) 13554431Seric stb.st_mode = 0666; 13564327Seric if (bitset(0111, stb.st_mode)) 13574327Seric exit(EX_CANTCREAT); 13584401Seric if (ctladdr == NULL) 13596900Seric ctladdr = &CurEnv->e_from; 13604327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 13614417Seric { 13624417Seric if (ctladdr->q_uid == 0) 13634417Seric (void) setgid(DefGid); 13644417Seric else 13654417Seric (void) setgid(ctladdr->q_gid); 13664417Seric } 13674327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 13684417Seric { 13694417Seric if (ctladdr->q_uid == 0) 13704417Seric (void) setuid(DefUid); 13714417Seric else 13724417Seric (void) setuid(ctladdr->q_uid); 13734417Seric } 13746887Seric f = dfopen(filename, "a"); 13754214Seric if (f == NULL) 13764214Seric exit(EX_CANTCREAT); 13774214Seric 13786974Seric putfromline(f, Mailer[1]); 13796974Seric (*CurEnv->e_puthdr)(f, Mailer[1], CurEnv); 13807123Seric fputs("\n", f); 13816974Seric (*CurEnv->e_putbody)(f, Mailer[1], FALSE); 13824214Seric fputs("\n", f); 13834214Seric (void) fclose(f); 13844214Seric (void) fflush(stdout); 13854417Seric 13866887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13874621Seric (void) chmod(filename, (int) stb.st_mode); 13884214Seric exit(EX_OK); 13894315Seric /*NOTREACHED*/ 13904214Seric } 13914214Seric else 13924214Seric { 13934214Seric /* parent -- wait for exit status */ 13944214Seric register int i; 13954214Seric auto int stat; 13964214Seric 13974214Seric while ((i = wait(&stat)) != pid) 13984214Seric { 13994214Seric if (i < 0) 14004214Seric { 14014214Seric stat = EX_OSERR << 8; 14024214Seric break; 14034214Seric } 14044214Seric } 14054215Seric if ((stat & 0377) != 0) 14064215Seric stat = EX_UNAVAILABLE << 8; 14074214Seric return ((stat >> 8) & 0377); 14084214Seric } 1409294Seric } 14104550Seric /* 14114550Seric ** SENDALL -- actually send all the messages. 14124550Seric ** 14134550Seric ** Parameters: 14147043Seric ** e -- the envelope to send. 14154550Seric ** verifyonly -- if set, only give verification messages. 14164550Seric ** 14174550Seric ** Returns: 14184550Seric ** none. 14194550Seric ** 14204550Seric ** Side Effects: 14214550Seric ** Scans the send lists and sends everything it finds. 14227043Seric ** Delivers any appropriate error messages. 14234550Seric */ 14244550Seric 14257043Seric sendall(e, verifyonly) 14267043Seric ENVELOPE *e; 14274550Seric bool verifyonly; 14284550Seric { 14295008Seric register ADDRESS *q; 14307779Seric bool oldverbose; 14314550Seric 14325032Seric # ifdef DEBUG 14338248Seric if (tTd(13, 1)) 14345032Seric { 14358542Seric printf("\nSENDALL: verify %d, sendqueue:\n", verifyonly); 14367043Seric printaddr(e->e_sendqueue, TRUE); 14375032Seric } 14385032Seric # endif DEBUG 14395008Seric 14407043Seric /* 14417043Seric ** Run through the list and send everything. 14427043Seric */ 14437043Seric 14447779Seric oldverbose = Verbose; 14457779Seric if (verifyonly) 14467779Seric Verbose = TRUE; 14477043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14484550Seric { 14495008Seric if (verifyonly) 14504550Seric { 14516900Seric CurEnv->e_to = q->q_paddr; 14525008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14537052Seric message(Arpa_Info, "deliverable"); 14544550Seric } 14555008Seric else 14566974Seric (void) deliver(q); 14574550Seric } 14587779Seric Verbose = oldverbose; 14597043Seric 14607043Seric /* 14617043Seric ** Now run through and check for errors. 14627043Seric */ 14637043Seric 14647043Seric if (verifyonly) 14657043Seric return; 14667043Seric 14677043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14687043Seric { 14697043Seric register ADDRESS *qq; 14707043Seric 14718248Seric # ifdef DEBUG 14728248Seric if (tTd(13, 3)) 14738248Seric { 14748248Seric printf("Checking "); 14758248Seric printaddr(q, FALSE); 14768248Seric } 14778248Seric # endif DEBUG 14788248Seric 14797043Seric if (bitset(QQUEUEUP, q->q_flags)) 14807043Seric e->e_queueup = TRUE; 14817043Seric 14827043Seric /* we have an address that failed -- find the parent */ 14837043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14847043Seric { 14857043Seric char obuf[MAXNAME + 6]; 14867043Seric extern char *aliaslookup(); 14877043Seric 14887043Seric /* we can only have owners for local addresses */ 14897043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 14907043Seric continue; 14917043Seric 14927043Seric /* see if the owner list exists */ 14937043Seric (void) strcpy(obuf, "owner-"); 14947047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14957047Seric (void) strcat(obuf, "owner"); 14967047Seric else 14977047Seric (void) strcat(obuf, qq->q_user); 14987043Seric if (aliaslookup(obuf) == NULL) 14997043Seric continue; 15007043Seric 15018248Seric # ifdef DEBUG 15028248Seric if (tTd(13, 4)) 15038248Seric printf("Errors to %s\n", obuf); 15048248Seric # endif DEBUG 15058248Seric 15068248Seric /* add in an errors-to field */ 15078248Seric /* ugh... must happen before delivery..... 15088248Seric addheader("errors-to", newstr(obuf), e); 15098248Seric .... i guess this should go in sendto */ 15108248Seric 15118248Seric /* only send errors if the message failed */ 15128248Seric if (!bitset(QBADADDR, q->q_flags)) 15138248Seric break; 15148248Seric 15157043Seric /* owner list exists -- add it to the error queue */ 15167043Seric qq->q_flags &= ~QPRIMARY; 15178077Seric sendto(obuf, qq, &e->e_errorqueue); 15187043Seric MailBack = TRUE; 15197043Seric break; 15207043Seric } 15217043Seric 15227043Seric /* if we did not find an owner, send to the sender */ 15238426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 15248077Seric sendto(e->e_from.q_paddr, qq, &e->e_errorqueue); 15257043Seric } 15264550Seric } 15277043Seric /* 15287043Seric ** CHECKERRORS -- check a queue of addresses and process errors. 15297043Seric ** 15307043Seric ** Parameters: 15317043Seric ** e -- the envelope to check. 15327043Seric ** 15337043Seric ** Returns: 15347043Seric ** none. 15357043Seric ** 15367043Seric ** Side Effects: 15377043Seric ** Arranges to queue all tempfailed messages in q 15387043Seric ** or deliver error responses. 15397043Seric */ 15407043Seric 15417043Seric checkerrors(e) 15427043Seric register ENVELOPE *e; 15437043Seric { 15447808Seric register ADDRESS *q; 15457808Seric 15467043Seric # ifdef DEBUG 15477672Seric if (tTd(4, 1)) 15487043Seric { 15497371Seric printf("\ncheckerrors: FatalErrors %d, errorqueue:\n"); 15507043Seric printaddr(e->e_errorqueue, TRUE); 15517043Seric } 15527043Seric # endif DEBUG 15537043Seric 15547043Seric /* mail back the transcript on errors */ 15557043Seric if (FatalErrors) 15567043Seric savemail(); 15577043Seric 15587043Seric /* queue up anything laying around */ 15597858Seric if (e->e_dontqueue) 15607858Seric return; 15617808Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15627043Seric { 15637808Seric if (bitset(QQUEUEUP, q->q_flags)) 15647808Seric { 15657043Seric # ifdef QUEUE 15667808Seric queueup(e, FALSE); 15678262Seric e->e_df = e->e_qf = NULL; 15688262Seric e->e_dontqueue = TRUE; 15697043Seric # else QUEUE 15707808Seric syserr("checkerrors: trying to queue %s", e->e_df); 15717043Seric # endif QUEUE 15727808Seric break; 15737808Seric } 15747043Seric } 15757043Seric } 1576