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*5330Seric SCCSID(@(#)deliver.c 3.61 01/05/82); 10405Seric 11294Seric /* 124315Seric ** DELIVER -- Deliver a message to a list of addresses. 13294Seric ** 144315Seric ** This routine delivers to everyone on the same host as the 154315Seric ** user on the head of the list. It is clever about mailers 164315Seric ** that don't handle multiple users. It is NOT guaranteed 174315Seric ** that it will deliver to all these addresses however -- so 184315Seric ** deliver should be called once for each address on the 194315Seric ** list. 204315Seric ** 21294Seric ** Parameters: 224621Seric ** firstto -- head of the address list to deliver to. 23294Seric ** editfcn -- if non-NULL, we want to call this function 24294Seric ** to output the letter (instead of just out- 25294Seric ** putting it raw). 26294Seric ** 27294Seric ** Returns: 28294Seric ** zero -- successfully delivered. 29294Seric ** else -- some failure, see ExitStat for more info. 30294Seric ** 31294Seric ** Side Effects: 32294Seric ** The standard input is passed off to someone. 33294Seric */ 34294Seric 354621Seric deliver(firstto, editfcn) 364621Seric ADDRESS *firstto; 37294Seric int (*editfcn)(); 38294Seric { 394452Seric char *host; /* host being sent to */ 404452Seric char *user; /* user being sent to */ 41294Seric char **pvp; 423233Seric register char **mvp; 433233Seric register char *p; 444452Seric register struct mailer *m; /* mailer for this recipient */ 45294Seric register int i; 462898Seric extern putmessage(); 472968Seric extern bool checkcompat(); 483233Seric char *pv[MAXPV+1]; 494452Seric char tobuf[MAXLINE]; /* text line of to people */ 503233Seric char buf[MAXNAME]; 514397Seric ADDRESS *ctladdr; 524397Seric extern ADDRESS *getctladdr(); 534452Seric char tfrombuf[MAXNAME]; /* translated from person */ 544452Seric extern char **prescan(); 554621Seric register ADDRESS *to = firstto; 564863Seric bool clever = FALSE; /* running user smtp to this mailer */ 574863Seric bool tempfail = FALSE; 585032Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 59294Seric 604488Seric errno = 0; 615008Seric if (!ForceMail && bitset(QDONTSEND, to->q_flags)) 623233Seric return (0); 63294Seric 64294Seric # ifdef DEBUG 65294Seric if (Debug) 663233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 674596Seric to->q_mailer->m_mno, to->q_host, to->q_user); 68294Seric # endif DEBUG 69294Seric 70294Seric /* 713233Seric ** Do initial argv setup. 723233Seric ** Insert the mailer name. Notice that $x expansion is 733233Seric ** NOT done on the mailer name. Then, if the mailer has 743233Seric ** a picky -f flag, we insert it as appropriate. This 753233Seric ** code does not check for 'pv' overflow; this places a 763233Seric ** manifest lower limit of 4 for MAXPV. 772968Seric */ 782968Seric 794596Seric m = to->q_mailer; 803233Seric host = to->q_host; 814452Seric 824452Seric /* rewrite from address, using rewriting rules */ 834452Seric (void) expand(m->m_from, buf, &buf[sizeof buf - 1]); 844452Seric mvp = prescan(buf, '\0'); 854452Seric if (mvp == NULL) 864452Seric { 874452Seric syserr("bad mailer from translate \"%s\"", buf); 884452Seric return (EX_SOFTWARE); 894452Seric } 904452Seric rewrite(mvp, 2); 914452Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 924452Seric 934452Seric define('g', tfrombuf); /* translated sender address */ 943233Seric define('h', host); /* to host */ 953233Seric Errors = 0; 963233Seric pvp = pv; 973233Seric *pvp++ = m->m_argv[0]; 982968Seric 993233Seric /* insert -f or -r flag as appropriate */ 1003233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1013233Seric { 1023233Seric if (bitset(M_FOPT, m->m_flags)) 1033233Seric *pvp++ = "-f"; 1043233Seric else 1053233Seric *pvp++ = "-r"; 1064082Seric (void) expand("$g", buf, &buf[sizeof buf - 1]); 1073233Seric *pvp++ = newstr(buf); 1083233Seric } 109294Seric 110294Seric /* 1113233Seric ** Append the other fixed parts of the argv. These run 1123233Seric ** up to the first entry containing "$u". There can only 1133233Seric ** be one of these, and there are only a few more slots 1143233Seric ** in the pv after it. 115294Seric */ 116294Seric 1173233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 118294Seric { 1193233Seric while ((p = index(p, '$')) != NULL) 1203233Seric if (*++p == 'u') 1213233Seric break; 1223233Seric if (p != NULL) 1233233Seric break; 1243233Seric 1253233Seric /* this entry is safe -- go ahead and process it */ 1264082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 1273233Seric *pvp++ = newstr(buf); 1283233Seric if (pvp >= &pv[MAXPV - 3]) 1293233Seric { 1303233Seric syserr("Too many parameters to %s before $u", pv[0]); 1313233Seric return (-1); 1323233Seric } 133294Seric } 1344863Seric 1353233Seric if (*mvp == NULL) 1364863Seric { 1374863Seric /* running SMTP */ 1385179Seric # ifdef SMTP 1394863Seric clever = TRUE; 1404863Seric *pvp = NULL; 1414863Seric i = smtpinit(m, pv, (ADDRESS *) NULL); 1424863Seric giveresponse(i, TRUE, m); 1435179Seric # ifdef QUEUE 1444863Seric if (i == EX_TEMPFAIL) 1454863Seric { 1464863Seric QueueUp = TRUE; 1474863Seric tempfail = TRUE; 1484863Seric } 1495179Seric # endif QUEUE 1505179Seric # else SMTP 1515179Seric syserr("SMTP style mailer"); 1525179Seric return (EX_SOFTWARE); 1535179Seric # endif SMTP 1544863Seric } 155294Seric 156294Seric /* 1573233Seric ** At this point *mvp points to the argument with $u. We 1583233Seric ** run through our address list and append all the addresses 1593233Seric ** we can. If we run out of space, do not fret! We can 1603233Seric ** always send another copy later. 161294Seric */ 162294Seric 1633233Seric tobuf[0] = '\0'; 1643233Seric To = tobuf; 1654397Seric ctladdr = NULL; 1663233Seric for (; to != NULL; to = to->q_next) 167294Seric { 1683233Seric /* avoid sending multiple recipients to dumb mailers */ 1694382Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1703233Seric break; 1713233Seric 1723233Seric /* if already sent or not for this host, don't send */ 1735008Seric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 1745008Seric strcmp(to->q_host, host) != 0 || to->q_mailer != firstto->q_mailer) 1753233Seric continue; 1764397Seric 1775032Seric # ifdef DEBUG 1785032Seric if (Debug) 1795032Seric { 1805032Seric printf("\nsend to "); 1815032Seric printaddr(to, FALSE); 1825032Seric } 1835032Seric # endif DEBUG 1845032Seric 1855032Seric /* link together the chain of recipients */ 1865032Seric if (!bitset(QDONTSEND, to->q_flags)) 1875032Seric { 1885032Seric to->q_tchain = tochain; 1895032Seric tochain = to; 1905032Seric } 1915032Seric 1924397Seric /* compute effective uid/gid when sending */ 1934596Seric if (to->q_mailer == ProgMailer) 1944397Seric ctladdr = getctladdr(to); 1954397Seric 1963233Seric user = to->q_user; 1973233Seric To = to->q_paddr; 1983233Seric to->q_flags |= QDONTSEND; 1994863Seric if (tempfail) 2005032Seric { 2014863Seric to->q_flags |= QQUEUEUP; 2025032Seric continue; 2035032Seric } 2043233Seric 2053233Seric /* 2063233Seric ** Check to see that these people are allowed to 2073233Seric ** talk to each other. 2083233Seric */ 2093233Seric 2103233Seric if (!checkcompat(to)) 211294Seric { 2123233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 2133233Seric continue; 214294Seric } 2153233Seric 2163233Seric /* 2174099Seric ** Strip quote bits from names if the mailer is dumb 2184099Seric ** about them. 2193233Seric */ 2203233Seric 2213233Seric if (bitset(M_STRIPQ, m->m_flags)) 222294Seric { 2234099Seric stripquotes(user, TRUE); 2244099Seric stripquotes(host, TRUE); 2253233Seric } 2264099Seric else 2274099Seric { 2284099Seric stripquotes(user, FALSE); 2294099Seric stripquotes(host, FALSE); 2304099Seric } 2313233Seric 2323233Seric /* 2334161Seric ** If an error message has already been given, don't 2344161Seric ** bother to send to this address. 2354161Seric ** 2364161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2374161Seric ** >> NOTE >> cannot do any further aliasing; that 2384161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2394161Seric */ 2404161Seric 2414161Seric if (bitset(QBADADDR, to->q_flags)) 2424161Seric continue; 2434161Seric 2444283Seric /* save statistics.... */ 2454596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2464596Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(MsgSize); 2474283Seric 2484161Seric /* 2493233Seric ** See if this user name is "special". 2503233Seric ** If the user name has a slash in it, assume that this 2513233Seric ** is a file -- send it off without further ado. 2523233Seric ** Note that this means that editfcn's will not 2533233Seric ** be applied to the message. Also note that 2543233Seric ** this type of addresses is not processed along 2553233Seric ** with the others, so we fudge on the To person. 2563233Seric */ 2573233Seric 2584596Seric if (m == LocalMailer) 2593233Seric { 260294Seric if (index(user, '/') != NULL) 261294Seric { 2624397Seric i = mailfile(user, getctladdr(to)); 263294Seric giveresponse(i, TRUE, m); 2643233Seric continue; 265294Seric } 266294Seric } 2673233Seric 2684315Seric /* 2694315Seric ** Address is verified -- add this user to mailer 2704315Seric ** argv, and add it to the print list of recipients. 2714315Seric */ 2724315Seric 2733233Seric /* create list of users for error messages */ 2743233Seric if (tobuf[0] != '\0') 2754082Seric (void) strcat(tobuf, ","); 2764082Seric (void) strcat(tobuf, to->q_paddr); 2773233Seric define('u', user); /* to user */ 2784078Seric define('z', to->q_home); /* user's home */ 2793233Seric 2804863Seric /* 2814863Seric ** Expand out this user into argument list or 2824863Seric ** send it to our SMTP server. 2834863Seric */ 2844863Seric 2854863Seric if (clever) 2863233Seric { 2875179Seric # ifdef SMTP 2884975Seric i = smtprcpt(to); 2895179Seric if (i != EX_OK) 2904863Seric { 2915179Seric # ifdef QUEUE 2925179Seric if (i == EX_TEMPFAIL) 2935179Seric { 2945179Seric QueueUp = TRUE; 2955179Seric to->q_flags |= QQUEUEUP; 2965179Seric } 2975179Seric else 2985179Seric # endif QUEUE 2995179Seric { 3005179Seric to->q_flags |= QBADADDR; 3015179Seric giveresponse(i, TRUE, m); 3025179Seric } 3034863Seric } 3045179Seric # else SMTP 3055179Seric syserr("trying to be clever"); 3065179Seric # endif SMTP 3073233Seric } 3084863Seric else 3094863Seric { 3104863Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3114863Seric *pvp++ = newstr(buf); 3124863Seric if (pvp >= &pv[MAXPV - 2]) 3134863Seric { 3144863Seric /* allow some space for trailing parms */ 3154863Seric break; 3164863Seric } 3174863Seric } 318294Seric } 319294Seric 3204067Seric /* see if any addresses still exist */ 3214067Seric if (tobuf[0] == '\0') 3224863Seric { 3235179Seric # ifdef SMTP 3244863Seric if (clever) 3254863Seric smtpquit(pv[0]); 3265179Seric # endif SMTP 3274067Seric return (0); 3284863Seric } 3294067Seric 3303233Seric /* print out messages as full list */ 3313233Seric To = tobuf; 3323233Seric 333294Seric /* 3343233Seric ** Fill out any parameters after the $u parameter. 335294Seric */ 336294Seric 3374863Seric while (!clever && *++mvp != NULL) 338294Seric { 3394082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 3403233Seric *pvp++ = newstr(buf); 3413233Seric if (pvp >= &pv[MAXPV]) 3423233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 343294Seric } 3443233Seric *pvp++ = NULL; 345294Seric 346294Seric /* 347294Seric ** Call the mailer. 3482898Seric ** The argument vector gets built, pipes 349294Seric ** are created as necessary, and we fork & exec as 3502898Seric ** appropriate. 3514863Seric ** If we are running SMTP, we just need to clean up. 352294Seric */ 353294Seric 3543233Seric if (editfcn == NULL) 3553233Seric editfcn = putmessage; 3564397Seric if (ctladdr == NULL) 3574397Seric ctladdr = &From; 3585179Seric # ifdef SMTP 3594863Seric if (clever) 3604863Seric { 3614863Seric i = smtpfinish(m, editfcn); 3624863Seric smtpquit(pv[0]); 3634863Seric } 3644863Seric else 3655179Seric # endif SMTP 3664863Seric i = sendoff(m, pv, editfcn, ctladdr); 3673233Seric 3684621Seric /* 3694621Seric ** If we got a temporary failure, arrange to queue the 3704621Seric ** addressees. 3714621Seric */ 3724621Seric 3735179Seric # ifdef QUEUE 3744621Seric if (i == EX_TEMPFAIL) 3754621Seric { 3764621Seric QueueUp = TRUE; 3775032Seric for (to = tochain; to != NULL; to = to->q_tchain) 3784621Seric to->q_flags |= QQUEUEUP; 3794621Seric } 3805179Seric # endif QUEUE 3814621Seric 3824488Seric errno = 0; 3833233Seric return (i); 3843233Seric } 3853233Seric /* 3864214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 3874214Seric ** 3884214Seric ** This MUST be a macro, since after a vfork we are running 3894214Seric ** two processes on the same stack!!! 3904214Seric ** 3914214Seric ** Parameters: 3924214Seric ** none. 3934214Seric ** 3944214Seric ** Returns: 3954214Seric ** From a macro??? You've got to be kidding! 3964214Seric ** 3974214Seric ** Side Effects: 3984214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 3994214Seric ** pid of child in parent, zero in child. 4004214Seric ** -1 on unrecoverable error. 4014214Seric ** 4024214Seric ** Notes: 4034214Seric ** I'm awfully sorry this looks so awful. That's 4044214Seric ** vfork for you..... 4054214Seric */ 4064214Seric 4074214Seric # define NFORKTRIES 5 4084214Seric # ifdef VFORK 4094214Seric # define XFORK vfork 4104214Seric # else VFORK 4114214Seric # define XFORK fork 4124214Seric # endif VFORK 4134214Seric 4144214Seric # define DOFORK(fORKfN) \ 4154214Seric {\ 4164214Seric register int i;\ 4174214Seric \ 4184214Seric for (i = NFORKTRIES; i-- > 0; )\ 4194214Seric {\ 4204214Seric pid = fORKfN();\ 4214214Seric if (pid >= 0)\ 4224214Seric break;\ 4234214Seric sleep((unsigned) NFORKTRIES - i);\ 4244214Seric }\ 4254214Seric } 4264214Seric /* 4274637Seric ** DOFORK -- simple fork interface to DOFORK. 4284637Seric ** 4294637Seric ** Parameters: 4304637Seric ** none. 4314637Seric ** 4324637Seric ** Returns: 4334637Seric ** pid of child in parent. 4344637Seric ** zero in child. 4354637Seric ** -1 on error. 4364637Seric ** 4374637Seric ** Side Effects: 4384637Seric ** returns twice, once in parent and once in child. 4394637Seric */ 4404637Seric 4414637Seric dofork() 4424637Seric { 4434637Seric register int pid; 4444637Seric 4454637Seric DOFORK(fork); 4464637Seric return (pid); 4474637Seric } 4484637Seric /* 4493233Seric ** SENDOFF -- send off call to mailer & collect response. 4503233Seric ** 4513233Seric ** Parameters: 4523233Seric ** m -- mailer descriptor. 4533233Seric ** pvp -- parameter vector to send to it. 4543233Seric ** editfcn -- function to pipe it through. 4554397Seric ** ctladdr -- an address pointer controlling the 4564397Seric ** user/groupid etc. of the mailer. 4573233Seric ** 4583233Seric ** Returns: 4593233Seric ** exit status of mailer. 4603233Seric ** 4613233Seric ** Side Effects: 4623233Seric ** none. 4633233Seric */ 4643233Seric 4654397Seric sendoff(m, pvp, editfcn, ctladdr) 4663233Seric struct mailer *m; 4673233Seric char **pvp; 4683233Seric int (*editfcn)(); 4694397Seric ADDRESS *ctladdr; 4703233Seric { 4714863Seric auto FILE *mfile; 4724863Seric auto FILE *rfile; 4733233Seric register int i; 4744863Seric extern putmessage(); 4753233Seric int pid; 4764863Seric 4774863Seric /* 4784863Seric ** Create connection to mailer. 4794863Seric */ 4804863Seric 4814863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 4824863Seric if (pid < 0) 4834863Seric return (-1); 4844863Seric 4854863Seric /* 4864863Seric ** Format and send message. 4874863Seric */ 4884863Seric 4894863Seric (void) signal(SIGPIPE, SIG_IGN); 4904863Seric if (editfcn == NULL) 4914863Seric editfcn = putmessage; 4924863Seric 4934863Seric (*editfcn)(mfile, m, FALSE); 4944863Seric (void) fclose(mfile); 4954863Seric 4964863Seric i = endmailer(pid, pvp[0]); 4974863Seric giveresponse(i, TRUE, m); 4984863Seric return (i); 4994863Seric } 5004863Seric /* 5014863Seric ** ENDMAILER -- Wait for mailer to terminate. 5024863Seric ** 5034863Seric ** We should never get fatal errors (e.g., segmentation 5044863Seric ** violation), so we report those specially. For other 5054863Seric ** errors, we choose a status message (into statmsg), 5064863Seric ** and if it represents an error, we print it. 5074863Seric ** 5084863Seric ** Parameters: 5094863Seric ** pid -- pid of mailer. 5104863Seric ** name -- name of mailer (for error messages). 5114863Seric ** 5124863Seric ** Returns: 5134863Seric ** exit code of mailer. 5144863Seric ** 5154863Seric ** Side Effects: 5164863Seric ** none. 5174863Seric */ 5184863Seric 5194863Seric endmailer(pid, name) 5204863Seric int pid; 5214863Seric char *name; 5224863Seric { 5234863Seric register int i; 5244863Seric auto int st; 5254863Seric 5264863Seric while ((i = wait(&st)) > 0 && i != pid) 5274863Seric continue; 5284863Seric if (i < 0) 5294863Seric { 5304863Seric syserr("wait"); 5314863Seric return (-1); 5324863Seric } 5334863Seric if ((st & 0377) != 0) 5344863Seric { 5354863Seric syserr("%s: stat %o", name, st); 5364863Seric ExitStat = EX_UNAVAILABLE; 5374863Seric return (-1); 5384863Seric } 5394863Seric i = (st >> 8) & 0377; 5404863Seric return (i); 5414863Seric } 5424863Seric /* 5434863Seric ** OPENMAILER -- open connection to mailer. 5444863Seric ** 5454863Seric ** Parameters: 5464863Seric ** m -- mailer descriptor. 5474863Seric ** pvp -- parameter vector to pass to mailer. 5484863Seric ** ctladdr -- controlling address for user. 5494863Seric ** clever -- create a full duplex connection. 5504863Seric ** pmfile -- pointer to mfile (to mailer) connection. 5514863Seric ** prfile -- pointer to rfile (from mailer) connection. 5524863Seric ** 5534863Seric ** Returns: 5544863Seric ** pid of mailer. 5554863Seric ** -1 on error. 5564863Seric ** 5574863Seric ** Side Effects: 5584863Seric ** creates a mailer in a subprocess. 5594863Seric */ 5604863Seric 5614863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 5624863Seric struct mailer *m; 5634863Seric char **pvp; 5644863Seric ADDRESS *ctladdr; 5654863Seric bool clever; 5664863Seric FILE **pmfile; 5674863Seric FILE **prfile; 5684863Seric { 5694863Seric int pid; 5704709Seric int mpvect[2]; 5714863Seric int rpvect[2]; 5723233Seric FILE *mfile; 5734863Seric FILE *rfile; 5743233Seric extern FILE *fdopen(); 5753233Seric 5763233Seric # ifdef DEBUG 5773233Seric if (Debug) 578294Seric { 5794863Seric printf("openmailer:\n"); 5803233Seric printav(pvp); 581294Seric } 5823233Seric # endif DEBUG 5834488Seric errno = 0; 5843233Seric 5852898Seric /* create a pipe to shove the mail through */ 5864709Seric if (pipe(mpvect) < 0) 587294Seric { 5884863Seric syserr("pipe (to mailer)"); 589294Seric return (-1); 590294Seric } 5914863Seric 5925179Seric # ifdef SMTP 5934863Seric /* if this mailer speaks smtp, create a return pipe */ 5944863Seric if (clever && pipe(rpvect) < 0) 5954863Seric { 5964863Seric syserr("pipe (from mailer)"); 5974863Seric (void) close(mpvect[0]); 5984863Seric (void) close(mpvect[1]); 5994863Seric return (-1); 6004863Seric } 6015179Seric # endif SMTP 6024863Seric 6034214Seric DOFORK(XFORK); 6044327Seric /* pid is set by DOFORK */ 605294Seric if (pid < 0) 606294Seric { 607294Seric syserr("Cannot fork"); 6084709Seric (void) close(mpvect[0]); 6094709Seric (void) close(mpvect[1]); 6104863Seric if (clever) 6114863Seric { 6124863Seric (void) close(rpvect[0]); 6134863Seric (void) close(rpvect[1]); 6144863Seric } 615294Seric return (-1); 616294Seric } 617294Seric else if (pid == 0) 618294Seric { 619294Seric /* child -- set up input & exec mailer */ 6201621Seric /* make diagnostic output be standard output */ 6214477Seric (void) signal(SIGINT, SIG_IGN); 6224477Seric (void) signal(SIGHUP, SIG_IGN); 6234215Seric (void) signal(SIGTERM, SIG_DFL); 6244709Seric 6254709Seric /* arrange to filter standard & diag output of command */ 6264863Seric if (clever) 6274709Seric { 6284863Seric (void) close(rpvect[0]); 6294709Seric (void) close(1); 6304863Seric (void) dup(rpvect[1]); 6314863Seric (void) close(rpvect[1]); 6324863Seric } 6334863Seric else if (OutChannel != stdout) 6344863Seric { 6354863Seric (void) close(1); 6364709Seric (void) dup(fileno(OutChannel)); 6374709Seric } 6384082Seric (void) close(2); 6394082Seric (void) dup(1); 6404709Seric 6414709Seric /* arrange to get standard input */ 6424709Seric (void) close(mpvect[1]); 6434082Seric (void) close(0); 6444709Seric if (dup(mpvect[0]) < 0) 645294Seric { 6462898Seric syserr("Cannot dup to zero!"); 6472898Seric _exit(EX_OSERR); 648294Seric } 6494709Seric (void) close(mpvect[0]); 6502968Seric if (!bitset(M_RESTR, m->m_flags)) 6514215Seric { 6524417Seric if (ctladdr->q_uid == 0) 6534417Seric { 6544417Seric extern int DefUid, DefGid; 6554415Seric 6564417Seric (void) setgid(DefGid); 6574417Seric (void) setuid(DefUid); 6584417Seric } 6594417Seric else 6604415Seric { 6614417Seric (void) setgid(ctladdr->q_gid); 6624417Seric (void) setuid(ctladdr->q_uid); 6634415Seric } 6644215Seric } 6652774Seric # ifndef VFORK 6662774Seric /* 6672774Seric ** We have to be careful with vfork - we can't mung up the 6682774Seric ** memory but we don't want the mailer to inherit any extra 6692774Seric ** open files. Chances are the mailer won't 6702774Seric ** care about an extra file, but then again you never know. 6712774Seric ** Actually, we would like to close(fileno(pwf)), but it's 6722774Seric ** declared static so we can't. But if we fclose(pwf), which 6732774Seric ** is what endpwent does, it closes it in the parent too and 6742774Seric ** the next getpwnam will be slower. If you have a weird 6752774Seric ** mailer that chokes on the extra file you should do the 6762774Seric ** endpwent(). 6772774Seric ** 6782774Seric ** Similar comments apply to log. However, openlog is 6792774Seric ** clever enough to set the FIOCLEX mode on the file, 6802774Seric ** so it will be closed automatically on the exec. 6812774Seric */ 6822774Seric 6832774Seric endpwent(); 684294Seric # ifdef LOG 6852089Seric closelog(); 686294Seric # endif LOG 6872774Seric # endif VFORK 688294Seric execv(m->m_mailer, pvp); 689294Seric /* syserr fails because log is closed */ 690294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 6914214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 6924082Seric (void) fflush(stdout); 6931619Seric _exit(EX_UNAVAILABLE); 694294Seric } 695294Seric 6964709Seric /* 6974863Seric ** Set up return value. 6984709Seric */ 6994709Seric 7004709Seric (void) close(mpvect[0]); 7014709Seric mfile = fdopen(mpvect[1], "w"); 7024863Seric if (clever) 7034863Seric { 7044863Seric (void) close(rpvect[1]); 7054863Seric rfile = fdopen(rpvect[0], "r"); 7064863Seric } 707294Seric 7084863Seric *pmfile = mfile; 7094863Seric *prfile = rfile; 710294Seric 7114863Seric return (pid); 712294Seric } 713294Seric /* 714294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 715294Seric ** 716294Seric ** Parameters: 717294Seric ** stat -- the status code from the mailer (high byte 718294Seric ** only; core dumps must have been taken care of 719294Seric ** already). 720294Seric ** force -- if set, force an error message output, even 721294Seric ** if the mailer seems to like to print its own 722294Seric ** messages. 723294Seric ** m -- the mailer descriptor for this mailer. 724294Seric ** 725294Seric ** Returns: 7264082Seric ** none. 727294Seric ** 728294Seric ** Side Effects: 7291518Seric ** Errors may be incremented. 730294Seric ** ExitStat may be set. 731294Seric */ 732294Seric 733294Seric giveresponse(stat, force, m) 734294Seric int stat; 735294Seric int force; 736294Seric register struct mailer *m; 737294Seric { 738294Seric register char *statmsg; 739294Seric extern char *SysExMsg[]; 740294Seric register int i; 741294Seric extern int N_SysEx; 7421624Seric char buf[30]; 743294Seric 7444315Seric /* 7454315Seric ** Compute status message from code. 7464315Seric */ 7474315Seric 748294Seric i = stat - EX__BASE; 749294Seric if (i < 0 || i > N_SysEx) 750294Seric statmsg = NULL; 751294Seric else 752294Seric statmsg = SysExMsg[i]; 753294Seric if (stat == 0) 7544065Seric { 7554194Seric if (bitset(M_LOCAL, m->m_flags)) 7564161Seric statmsg = "delivered"; 7574161Seric else 7584161Seric statmsg = "queued"; 7594065Seric if (Verbose) 7604166Seric message(Arpa_Info, statmsg); 7614065Seric } 7625179Seric # ifdef QUEUE 7634621Seric else if (stat == EX_TEMPFAIL) 7644621Seric { 7654621Seric if (Verbose) 7664621Seric message(Arpa_Info, "transmission deferred"); 7674621Seric } 7685179Seric # endif QUEUE 769294Seric else 770294Seric { 7711518Seric Errors++; 772294Seric if (statmsg == NULL && m->m_badstat != 0) 773294Seric { 774294Seric stat = m->m_badstat; 775294Seric i = stat - EX__BASE; 776294Seric # ifdef DEBUG 777294Seric if (i < 0 || i >= N_SysEx) 778294Seric syserr("Bad m_badstat %d", stat); 779294Seric else 780294Seric # endif DEBUG 781294Seric statmsg = SysExMsg[i]; 782294Seric } 783294Seric if (statmsg == NULL) 784294Seric usrerr("unknown mailer response %d", stat); 7854065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 786294Seric usrerr("%s", statmsg); 787294Seric } 788294Seric 789294Seric /* 790294Seric ** Final cleanup. 791294Seric ** Log a record of the transaction. Compute the new 792294Seric ** ExitStat -- if we already had an error, stick with 793294Seric ** that. 794294Seric */ 795294Seric 7961624Seric if (statmsg == NULL) 7971624Seric { 7984082Seric (void) sprintf(buf, "error %d", stat); 7991624Seric statmsg = buf; 8001624Seric } 8011624Seric 802294Seric # ifdef LOG 8032774Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 804294Seric # endif LOG 8055179Seric # ifdef QUEUE 8064621Seric if (stat != EX_TEMPFAIL) 8075179Seric # endif QUEUE 8084621Seric setstat(stat); 809294Seric } 810294Seric /* 8112898Seric ** PUTMESSAGE -- output a message to the final mailer. 812294Seric ** 8132898Seric ** This routine takes care of recreating the header from the 8142898Seric ** in-core copy, etc. 815294Seric ** 816294Seric ** Parameters: 8172898Seric ** fp -- file to output onto. 8182898Seric ** m -- a mailer descriptor. 8194863Seric ** xdot -- if set, hide lines beginning with dot. 820294Seric ** 821294Seric ** Returns: 8222898Seric ** none. 823294Seric ** 824294Seric ** Side Effects: 8252898Seric ** The message is written onto fp. 826294Seric */ 827294Seric 8284863Seric putmessage(fp, m, xdot) 8292898Seric FILE *fp; 8302898Seric struct mailer *m; 8314863Seric bool xdot; 832294Seric { 8332898Seric char buf[BUFSIZ]; 8344315Seric register HDR *h; 8352898Seric extern char *arpadate(); 8362898Seric bool anyheader = FALSE; 8373044Seric extern char *capitalize(); 8384370Seric extern char *hvalue(); 8394370Seric extern bool samefrom(); 8404447Seric char *of_line; 841294Seric 8424315Seric /* 8434315Seric ** Output "From" line unless supressed 8445099Seric ** 8455099Seric ** >>>>>>>>>> One of the ugliest hacks seen by human eyes is 8465099Seric ** >>>>>>>>>> contained herein: UUCP wants those stupid 847*5330Seric ** >>>>>>>>>> "remote from <host>" lines. Why oh why does a 848*5330Seric ** >> NOTE >> well-meaning programmer such as myself have to 8495099Seric ** >>>>>>>>>> deal with this kind of antique garbage???? 850*5330Seric ** >>>>>>>>>> This even depends on the local UUCP host name 851*5330Seric ** >>>>>>>>>> being in the $U macro!!!! 8524315Seric */ 8534315Seric 8543186Seric if (!bitset(M_NHDR, m->m_flags)) 8554205Seric { 8565179Seric # ifdef UGLYUUCP 8575179Seric char *p = rindex(m->m_mailer, '/'); 8585101Seric 8595101Seric if (p != NULL && strcmp(p, "/uux") == 0 && 8605101Seric strcmp(m->m_name, "uucp") == 0) 861*5330Seric (void) expand("From $f $d remote from $U", buf, 8625099Seric &buf[sizeof buf - 1]); 8635099Seric else 8645179Seric # endif UGLYUUCP 8655099Seric (void) expand("$l", buf, &buf[sizeof buf - 1]); 8664205Seric fprintf(fp, "%s\n", buf); 8674205Seric } 8683186Seric 8694315Seric /* 8704315Seric ** Output all header lines 8714315Seric */ 8724315Seric 8734447Seric of_line = hvalue("original-from"); 8742898Seric for (h = Header; h != NULL; h = h->h_link) 8751828Seric { 8764315Seric register char *p; 8774370Seric char *origfrom = OrigFrom; 8784447Seric bool nooutput; 8794315Seric 8804447Seric nooutput = FALSE; 8813389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 8824209Seric { 8834209Seric p = ")><("; /* can't happen (I hope) */ 8844447Seric nooutput = TRUE; 8854209Seric } 8864447Seric 8874447Seric /* use From: line from message if generated is the same */ 8884370Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 8894447Seric strcmp(m->m_from, "$f") == 0 && of_line == NULL) 8903385Seric { 8914370Seric p = origfrom; 8924370Seric origfrom = NULL; 8934370Seric } 8944370Seric else if (bitset(H_DEFAULT, h->h_flags)) 8954370Seric { 8964082Seric (void) expand(h->h_value, buf, &buf[sizeof buf]); 8973385Seric p = buf; 8983385Seric } 8992898Seric else 9003385Seric p = h->h_value; 9014447Seric if (p == NULL || *p == '\0') 9023389Seric continue; 9034209Seric 9044209Seric /* hack, hack -- output Original-From field if different */ 9054447Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL) 9064209Seric { 9074447Seric /* output new Original-From line if needed */ 9084447Seric if (of_line == NULL && !samefrom(p, origfrom)) 9094447Seric { 9104447Seric fprintf(fp, "Original-From: %s\n", origfrom); 9114447Seric anyheader = TRUE; 9124447Seric } 9134447Seric if (of_line != NULL && !nooutput && samefrom(p, of_line)) 9144447Seric { 9154447Seric /* delete Original-From: line if redundant */ 9164447Seric p = of_line; 9174447Seric of_line = NULL; 9184447Seric } 9194447Seric } 9204447Seric else if (strcmp(h->h_field, "original-from") == 0 && of_line == NULL) 9214447Seric nooutput = TRUE; 9224447Seric 9234447Seric /* finally, output the header line */ 9244447Seric if (!nooutput) 9254447Seric { 9264447Seric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 9274447Seric h->h_flags |= H_USED; 9284370Seric anyheader = TRUE; 9294209Seric } 9302898Seric } 9312898Seric if (anyheader) 9322898Seric fprintf(fp, "\n"); 9332898Seric 9344315Seric /* 9354315Seric ** Output the body of the message 9364315Seric */ 9374315Seric 9384452Seric if (TempFile != NULL) 9394452Seric { 9404452Seric rewind(TempFile); 9414863Seric while (!ferror(fp) && fgets(buf, sizeof buf, TempFile) != NULL) 9424863Seric fprintf(fp, "%s%s", xdot && buf[0] == '.' ? "." : "", buf); 9432898Seric 9444452Seric if (ferror(TempFile)) 9454452Seric { 9464452Seric syserr("putmessage: read error"); 9474452Seric setstat(EX_IOERR); 9484452Seric } 9494452Seric } 9504452Seric 9514621Seric (void) fflush(fp); 9524123Seric if (ferror(fp) && errno != EPIPE) 953294Seric { 9542898Seric syserr("putmessage: write error"); 955294Seric setstat(EX_IOERR); 956294Seric } 9574123Seric errno = 0; 958294Seric } 959294Seric /* 9604370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 9614370Seric ** 9624370Seric ** Parameters: 9634370Seric ** ifrom -- internally generated form of from address. 9644370Seric ** efrom -- external form of from address. 9654370Seric ** 9664370Seric ** Returns: 9674370Seric ** TRUE -- if they convey the same info. 9684370Seric ** FALSE -- if any information has been lost. 9694370Seric ** 9704370Seric ** Side Effects: 9714370Seric ** none. 9724370Seric */ 9734370Seric 9744370Seric bool 9754370Seric samefrom(ifrom, efrom) 9764370Seric char *ifrom; 9774370Seric char *efrom; 9784370Seric { 9794447Seric register char *p; 9804447Seric char buf[MAXNAME + 4]; 9814447Seric 9824447Seric # ifdef DEBUG 9834447Seric if (Debug > 7) 9844447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 9854447Seric # endif DEBUG 9864447Seric if (strcmp(ifrom, efrom) == 0) 9874447Seric goto success; 9884447Seric p = index(ifrom, '@'); 9894447Seric if (p == NULL) 9904447Seric goto failure; 9914447Seric *p = '\0'; 9924447Seric strcpy(buf, ifrom); 9934447Seric strcat(buf, " at "); 9944447Seric *p++ = '@'; 9954447Seric strcat(buf, p); 9964447Seric if (strcmp(buf, efrom) == 0) 9974447Seric goto success; 9984447Seric 9994447Seric failure: 10004447Seric # ifdef DEBUG 10014447Seric if (Debug > 7) 10024447Seric printf("FALSE\n"); 10034447Seric # endif DEBUG 10044447Seric return (FALSE); 10054447Seric 10064447Seric success: 10074447Seric # ifdef DEBUG 10084447Seric if (Debug > 7) 10094447Seric printf("TRUE\n"); 10104447Seric # endif DEBUG 10114447Seric return (TRUE); 10124370Seric } 10134370Seric /* 1014294Seric ** MAILFILE -- Send a message to a file. 1015294Seric ** 10164327Seric ** If the file has the setuid/setgid bits set, but NO execute 10174327Seric ** bits, sendmail will try to become the owner of that file 10184327Seric ** rather than the real user. Obviously, this only works if 10194327Seric ** sendmail runs as root. 10204327Seric ** 1021294Seric ** Parameters: 1022294Seric ** filename -- the name of the file to send to. 10234397Seric ** ctladdr -- the controlling address header -- includes 10244397Seric ** the userid/groupid to be when sending. 1025294Seric ** 1026294Seric ** Returns: 1027294Seric ** The exit code associated with the operation. 1028294Seric ** 1029294Seric ** Side Effects: 1030294Seric ** none. 1031294Seric */ 1032294Seric 10334397Seric mailfile(filename, ctladdr) 1034294Seric char *filename; 10354397Seric ADDRESS *ctladdr; 1036294Seric { 1037294Seric register FILE *f; 10384214Seric register int pid; 1039294Seric 10404214Seric /* 10414214Seric ** Fork so we can change permissions here. 10424214Seric ** Note that we MUST use fork, not vfork, because of 10434214Seric ** the complications of calling subroutines, etc. 10444214Seric */ 10454067Seric 10464214Seric DOFORK(fork); 10474214Seric 10484214Seric if (pid < 0) 10494214Seric return (EX_OSERR); 10504214Seric else if (pid == 0) 10514214Seric { 10524214Seric /* child -- actually write to file */ 10534327Seric struct stat stb; 10544417Seric extern int DefUid, DefGid; 10554327Seric 10564215Seric (void) signal(SIGINT, SIG_DFL); 10574215Seric (void) signal(SIGHUP, SIG_DFL); 10584215Seric (void) signal(SIGTERM, SIG_DFL); 10594327Seric umask(OldUmask); 10604327Seric if (stat(filename, &stb) < 0) 10614431Seric stb.st_mode = 0666; 10624327Seric if (bitset(0111, stb.st_mode)) 10634327Seric exit(EX_CANTCREAT); 10644401Seric if (ctladdr == NULL) 10654401Seric ctladdr = &From; 10664327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 10674417Seric { 10684417Seric if (ctladdr->q_uid == 0) 10694417Seric (void) setgid(DefGid); 10704417Seric else 10714417Seric (void) setgid(ctladdr->q_gid); 10724417Seric } 10734327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 10744417Seric { 10754417Seric if (ctladdr->q_uid == 0) 10764417Seric (void) setuid(DefUid); 10774417Seric else 10784417Seric (void) setuid(ctladdr->q_uid); 10794417Seric } 10804214Seric f = fopen(filename, "a"); 10814214Seric if (f == NULL) 10824214Seric exit(EX_CANTCREAT); 10834214Seric 10844863Seric putmessage(f, Mailer[1], FALSE); 10854214Seric fputs("\n", f); 10864214Seric (void) fclose(f); 10874214Seric (void) fflush(stdout); 10884417Seric 10894417Seric /* reset ISUID & ISGID bits */ 10904621Seric (void) chmod(filename, (int) stb.st_mode); 10914214Seric exit(EX_OK); 10924315Seric /*NOTREACHED*/ 10934214Seric } 10944214Seric else 10954214Seric { 10964214Seric /* parent -- wait for exit status */ 10974214Seric register int i; 10984214Seric auto int stat; 10994214Seric 11004214Seric while ((i = wait(&stat)) != pid) 11014214Seric { 11024214Seric if (i < 0) 11034214Seric { 11044214Seric stat = EX_OSERR << 8; 11054214Seric break; 11064214Seric } 11074214Seric } 11084215Seric if ((stat & 0377) != 0) 11094215Seric stat = EX_UNAVAILABLE << 8; 11104214Seric return ((stat >> 8) & 0377); 11114214Seric } 1112294Seric } 11134550Seric /* 11144550Seric ** SENDALL -- actually send all the messages. 11154550Seric ** 11164550Seric ** Parameters: 11174550Seric ** verifyonly -- if set, only give verification messages. 11184550Seric ** 11194550Seric ** Returns: 11204550Seric ** none. 11214550Seric ** 11224550Seric ** Side Effects: 11234550Seric ** Scans the send lists and sends everything it finds. 11244550Seric */ 11254550Seric 11264550Seric sendall(verifyonly) 11274550Seric bool verifyonly; 11284550Seric { 11295008Seric register ADDRESS *q; 11304550Seric typedef int (*fnptr)(); 11314550Seric 11325032Seric # ifdef DEBUG 11335032Seric if (Debug > 1) 11345032Seric { 11355032Seric printf("\nSendQueue:\n"); 11365032Seric printaddr(SendQueue, TRUE); 11375032Seric } 11385032Seric # endif DEBUG 11395008Seric 11405008Seric for (q = SendQueue; q != NULL; q = q->q_next) 11414550Seric { 11425008Seric if (verifyonly) 11434550Seric { 11445008Seric To = q->q_paddr; 11455008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 11464550Seric { 11475008Seric if (bitset(M_LOCAL, q->q_mailer->m_flags)) 11485008Seric message(Arpa_Info, "deliverable"); 11495008Seric else 11505008Seric message(Arpa_Info, "queueable"); 11514550Seric } 11524550Seric } 11535008Seric else 11545008Seric (void) deliver(q, (fnptr) NULL); 11554550Seric } 11564550Seric } 1157