125a99e2eSeric # include <signal.h> 254aa2b0fSeric # include <errno.h> 3b20b3270Seric # include "sendmail.h" 4c77d1c25Seric # include <sys/stat.h> 525a99e2eSeric 6*588cad61Seric SCCSID(@(#)deliver.c 3.133 11/28/82); 7259cace7Seric 825a99e2eSeric /* 913bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 1013bbc08cSeric ** 1113bbc08cSeric ** This routine delivers to everyone on the same host as the 1213bbc08cSeric ** user on the head of the list. It is clever about mailers 1313bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 1413bbc08cSeric ** that it will deliver to all these addresses however -- so 1513bbc08cSeric ** deliver should be called once for each address on the 1613bbc08cSeric ** list. 1725a99e2eSeric ** 1825a99e2eSeric ** Parameters: 19*588cad61Seric ** e -- the envelope to deliver. 20c77d1c25Seric ** firstto -- head of the address list to deliver to. 2125a99e2eSeric ** 2225a99e2eSeric ** Returns: 2325a99e2eSeric ** zero -- successfully delivered. 2425a99e2eSeric ** else -- some failure, see ExitStat for more info. 2525a99e2eSeric ** 2625a99e2eSeric ** Side Effects: 2725a99e2eSeric ** The standard input is passed off to someone. 2825a99e2eSeric */ 2925a99e2eSeric 30*588cad61Seric deliver(e, firstto) 31*588cad61Seric register ENVELOPE *e; 32c77d1c25Seric ADDRESS *firstto; 3325a99e2eSeric { 3478442df3Seric char *host; /* host being sent to */ 3578442df3Seric char *user; /* user being sent to */ 3625a99e2eSeric char **pvp; 375dfc646bSeric register char **mvp; 3825a99e2eSeric register char *p; 39*588cad61Seric register MAILER *m; /* mailer for this recipient */ 402a6e0786Seric extern bool checkcompat(); 415dfc646bSeric char *pv[MAXPV+1]; 424b22ea87Seric char tobuf[MAXLINE-50]; /* text line of to people */ 435dfc646bSeric char buf[MAXNAME]; 446259796dSeric ADDRESS *ctladdr; 456259796dSeric extern ADDRESS *getctladdr(); 4678442df3Seric char tfrombuf[MAXNAME]; /* translated from person */ 4778442df3Seric extern char **prescan(); 48c77d1c25Seric register ADDRESS *to = firstto; 49c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 50772e6e50Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 515826d9d3Seric register int rcode; /* response code */ 5225a99e2eSeric 5335490626Seric errno = 0; 54da2935e1Seric if (bitset(QDONTSEND, to->q_flags)) 555dfc646bSeric return (0); 5625a99e2eSeric 5751552439Seric m = to->q_mailer; 5851552439Seric host = to->q_host; 5951552439Seric 6025a99e2eSeric # ifdef DEBUG 616ef48975Seric if (tTd(10, 1)) 625dfc646bSeric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 6351552439Seric m->m_mno, host, to->q_user); 6425a99e2eSeric # endif DEBUG 65f3dbc832Seric 66f3dbc832Seric /* 67f3dbc832Seric ** If this mailer is expensive, and if we don't want to make 68f3dbc832Seric ** connections now, just mark these addresses and return. 69f3dbc832Seric ** This is useful if we want to batch connections to 70f3dbc832Seric ** reduce load. This will cause the messages to be 71f3dbc832Seric ** queued up, and a daemon will come along to send the 72f3dbc832Seric ** messages later. 73f3dbc832Seric ** This should be on a per-mailer basis. 74f3dbc832Seric */ 75f3dbc832Seric 76317680d6Seric if (NoConnect && !QueueRun && bitset(M_EXPENSIVE, m->m_flags) && 77317680d6Seric !Verbose) 78f3dbc832Seric { 79f3dbc832Seric for (; to != NULL; to = to->q_next) 80f4560e80Seric { 81f4560e80Seric if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m) 82f4560e80Seric continue; 83f3dbc832Seric to->q_flags |= QQUEUEUP|QDONTSEND; 84*588cad61Seric e->e_to = to->q_paddr; 85eb238f8cSeric message(Arpa_Info, "queued"); 86eb238f8cSeric if (LogLevel > 4) 87eb238f8cSeric logdelivery("queued"); 88f4560e80Seric } 89*588cad61Seric e->e_to = NULL; 90f3dbc832Seric return (0); 91f3dbc832Seric } 92f3dbc832Seric 9325a99e2eSeric /* 945dfc646bSeric ** Do initial argv setup. 955dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 965dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 975dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 985dfc646bSeric ** code does not check for 'pv' overflow; this places a 995dfc646bSeric ** manifest lower limit of 4 for MAXPV. 1003bea8136Seric ** The from address rewrite is expected to make 1013bea8136Seric ** the address relative to the other end. 1025dfc646bSeric */ 1035dfc646bSeric 10478442df3Seric /* rewrite from address, using rewriting rules */ 105*588cad61Seric expand("$f", buf, &buf[sizeof buf - 1], e); 10678442df3Seric mvp = prescan(buf, '\0'); 107*588cad61Seric rewrite(mvp, 3); 108*588cad61Seric rewrite(mvp, 1); 1093bea8136Seric rewrite(mvp, m->m_s_rwset); 11078442df3Seric cataddr(mvp, tfrombuf, sizeof tfrombuf); 11178442df3Seric 112*588cad61Seric define('g', tfrombuf, e); /* translated sender address */ 113*588cad61Seric define('h', host, e); /* to host */ 1145dfc646bSeric Errors = 0; 1155dfc646bSeric pvp = pv; 1165dfc646bSeric *pvp++ = m->m_argv[0]; 1175dfc646bSeric 1185dfc646bSeric /* insert -f or -r flag as appropriate */ 1195dfc646bSeric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 1205dfc646bSeric { 1215dfc646bSeric if (bitset(M_FOPT, m->m_flags)) 1225dfc646bSeric *pvp++ = "-f"; 1235dfc646bSeric else 1245dfc646bSeric *pvp++ = "-r"; 125*588cad61Seric expand("$g", buf, &buf[sizeof buf - 1], e); 1265dfc646bSeric *pvp++ = newstr(buf); 1275dfc646bSeric } 1285dfc646bSeric 1295dfc646bSeric /* 1305dfc646bSeric ** Append the other fixed parts of the argv. These run 1315dfc646bSeric ** up to the first entry containing "$u". There can only 1325dfc646bSeric ** be one of these, and there are only a few more slots 1335dfc646bSeric ** in the pv after it. 1345dfc646bSeric */ 1355dfc646bSeric 1365dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 1375dfc646bSeric { 1385dfc646bSeric while ((p = index(p, '$')) != NULL) 1395dfc646bSeric if (*++p == 'u') 1405dfc646bSeric break; 1415dfc646bSeric if (p != NULL) 1425dfc646bSeric break; 1435dfc646bSeric 1445dfc646bSeric /* this entry is safe -- go ahead and process it */ 145*588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 1465dfc646bSeric *pvp++ = newstr(buf); 1475dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 1485dfc646bSeric { 1495dfc646bSeric syserr("Too many parameters to %s before $u", pv[0]); 1505dfc646bSeric return (-1); 1515dfc646bSeric } 1525dfc646bSeric } 153c579ef51Seric 15433db8731Seric /* 15533db8731Seric ** If we have no substitution for the user name in the argument 15633db8731Seric ** list, we know that we must supply the names otherwise -- and 15733db8731Seric ** SMTP is the answer!! 15833db8731Seric */ 15933db8731Seric 1605dfc646bSeric if (*mvp == NULL) 161c579ef51Seric { 162c579ef51Seric /* running SMTP */ 1632c7e1b8dSeric # ifdef SMTP 164c579ef51Seric clever = TRUE; 165c579ef51Seric *pvp = NULL; 1662c7e1b8dSeric # else SMTP 16733db8731Seric /* oops! we don't implement SMTP */ 1682c7e1b8dSeric syserr("SMTP style mailer"); 1692c7e1b8dSeric return (EX_SOFTWARE); 1702c7e1b8dSeric # endif SMTP 171c579ef51Seric } 1725dfc646bSeric 1735dfc646bSeric /* 1745dfc646bSeric ** At this point *mvp points to the argument with $u. We 1755dfc646bSeric ** run through our address list and append all the addresses 1765dfc646bSeric ** we can. If we run out of space, do not fret! We can 1775dfc646bSeric ** always send another copy later. 1785dfc646bSeric */ 1795dfc646bSeric 1805dfc646bSeric tobuf[0] = '\0'; 181*588cad61Seric e->e_to = tobuf; 1826259796dSeric ctladdr = NULL; 1835dfc646bSeric for (; to != NULL; to = to->q_next) 1845dfc646bSeric { 1855dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 186bea22b26Seric if (tobuf[0] != '\0' && !bitset(M_MUSER, m->m_flags)) 1875dfc646bSeric break; 1885dfc646bSeric 1895dfc646bSeric /* if already sent or not for this host, don't send */ 190da2935e1Seric if (bitset(QDONTSEND, to->q_flags) || 191da2935e1Seric strcmp(to->q_host, host) != 0 || 192da2935e1Seric to->q_mailer != firstto->q_mailer) 1935dfc646bSeric continue; 1946259796dSeric 1954b22ea87Seric /* avoid overflowing tobuf */ 196*588cad61Seric if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0) 1974b22ea87Seric break; 1984b22ea87Seric 199772e6e50Seric # ifdef DEBUG 2006ef48975Seric if (tTd(10, 1)) 201772e6e50Seric { 202772e6e50Seric printf("\nsend to "); 203772e6e50Seric printaddr(to, FALSE); 204772e6e50Seric } 205772e6e50Seric # endif DEBUG 206772e6e50Seric 2076259796dSeric /* compute effective uid/gid when sending */ 2087da1035fSeric if (to->q_mailer == ProgMailer) 2096259796dSeric ctladdr = getctladdr(to); 2106259796dSeric 2115dfc646bSeric user = to->q_user; 212*588cad61Seric e->e_to = to->q_paddr; 2135dfc646bSeric to->q_flags |= QDONTSEND; 2145dfc646bSeric 2155dfc646bSeric /* 2165dfc646bSeric ** Check to see that these people are allowed to 2175dfc646bSeric ** talk to each other. 2182a6e0786Seric */ 2192a6e0786Seric 2202a6e0786Seric if (!checkcompat(to)) 2215dfc646bSeric { 222*588cad61Seric giveresponse(EX_UNAVAILABLE, m); 2235dfc646bSeric continue; 2245dfc646bSeric } 2252a6e0786Seric 2262a6e0786Seric /* 2279ec9501bSeric ** Strip quote bits from names if the mailer is dumb 2289ec9501bSeric ** about them. 22925a99e2eSeric */ 23025a99e2eSeric 2312a6e0786Seric if (bitset(M_STRIPQ, m->m_flags)) 23225a99e2eSeric { 2339ec9501bSeric stripquotes(user, TRUE); 2349ec9501bSeric stripquotes(host, TRUE); 2359ec9501bSeric } 2369ec9501bSeric else 2379ec9501bSeric { 2389ec9501bSeric stripquotes(user, FALSE); 2399ec9501bSeric stripquotes(host, FALSE); 24025a99e2eSeric } 24125a99e2eSeric 242cdb828c5Seric /* hack attack -- delivermail compatibility */ 243cdb828c5Seric if (m == ProgMailer && *user == '|') 244cdb828c5Seric user++; 245cdb828c5Seric 24625a99e2eSeric /* 2473efaed6eSeric ** If an error message has already been given, don't 2483efaed6eSeric ** bother to send to this address. 2493efaed6eSeric ** 2503efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 2513efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 2523efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 2533efaed6eSeric */ 2543efaed6eSeric 2556cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2563efaed6eSeric continue; 2573efaed6eSeric 258f2fec898Seric /* save statistics.... */ 259*588cad61Seric markstats(e, to); 260f2fec898Seric 2613efaed6eSeric /* 26225a99e2eSeric ** See if this user name is "special". 26325a99e2eSeric ** If the user name has a slash in it, assume that this 26451552439Seric ** is a file -- send it off without further ado. Note 26551552439Seric ** that this type of addresses is not processed along 26651552439Seric ** with the others, so we fudge on the To person. 26725a99e2eSeric */ 26825a99e2eSeric 2697da1035fSeric if (m == LocalMailer) 27025a99e2eSeric { 271a49f24c0Seric if (user[0] == '/') 27225a99e2eSeric { 2735826d9d3Seric rcode = mailfile(user, getctladdr(to)); 274*588cad61Seric giveresponse(rcode, m); 2755dfc646bSeric continue; 27625a99e2eSeric } 27725a99e2eSeric } 27825a99e2eSeric 27913bbc08cSeric /* 28013bbc08cSeric ** Address is verified -- add this user to mailer 28113bbc08cSeric ** argv, and add it to the print list of recipients. 28213bbc08cSeric */ 28313bbc08cSeric 284508daeccSeric /* link together the chain of recipients */ 285508daeccSeric to->q_tchain = tochain; 286508daeccSeric tochain = to; 287508daeccSeric 2885dfc646bSeric /* create list of users for error messages */ 2895dfc646bSeric if (tobuf[0] != '\0') 290db8841e9Seric (void) strcat(tobuf, ","); 291db8841e9Seric (void) strcat(tobuf, to->q_paddr); 292*588cad61Seric define('u', user, e); /* to user */ 293*588cad61Seric define('z', to->q_home, e); /* user's home */ 2945dfc646bSeric 295c579ef51Seric /* 296508daeccSeric ** Expand out this user into argument list. 297c579ef51Seric */ 298c579ef51Seric 299508daeccSeric if (!clever) 300c579ef51Seric { 301*588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3025dfc646bSeric *pvp++ = newstr(buf); 3035dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 3045dfc646bSeric { 3055dfc646bSeric /* allow some space for trailing parms */ 3065dfc646bSeric break; 3075dfc646bSeric } 3085dfc646bSeric } 309c579ef51Seric } 3105dfc646bSeric 311145b49b1Seric /* see if any addresses still exist */ 312145b49b1Seric if (tobuf[0] == '\0') 313c579ef51Seric { 314*588cad61Seric define('g', (char *) NULL, e); 315145b49b1Seric return (0); 316c579ef51Seric } 317145b49b1Seric 3185dfc646bSeric /* print out messages as full list */ 319*588cad61Seric e->e_to = tobuf; 3205dfc646bSeric 3215dfc646bSeric /* 3225dfc646bSeric ** Fill out any parameters after the $u parameter. 3235dfc646bSeric */ 3245dfc646bSeric 325c579ef51Seric while (!clever && *++mvp != NULL) 3265dfc646bSeric { 327*588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 3285dfc646bSeric *pvp++ = newstr(buf); 3295dfc646bSeric if (pvp >= &pv[MAXPV]) 3305dfc646bSeric syserr("deliver: pv overflow after $u for %s", pv[0]); 3315dfc646bSeric } 3325dfc646bSeric *pvp++ = NULL; 3335dfc646bSeric 33425a99e2eSeric /* 33525a99e2eSeric ** Call the mailer. 3366328bdf7Seric ** The argument vector gets built, pipes 33725a99e2eSeric ** are created as necessary, and we fork & exec as 3386328bdf7Seric ** appropriate. 339c579ef51Seric ** If we are running SMTP, we just need to clean up. 34025a99e2eSeric */ 34125a99e2eSeric 342*588cad61Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 343*588cad61Seric 3446259796dSeric if (ctladdr == NULL) 345*588cad61Seric ctladdr = &e->e_from; 3462c7e1b8dSeric # ifdef SMTP 347c579ef51Seric if (clever) 348c579ef51Seric { 349*588cad61Seric /* send the initial SMTP protocol */ 350*588cad61Seric rcode = smtpinit(m, pv, (ADDRESS *) NULL); 351*588cad61Seric 352*588cad61Seric /* send the recipient list */ 353*588cad61Seric for (to = tochain; to != NULL; to = to->q_tchain) 354*588cad61Seric { 355*588cad61Seric int i; 356*588cad61Seric 357*588cad61Seric if (rcode == EX_OK) 358*588cad61Seric i = smtprcpt(to); 359*588cad61Seric else 360*588cad61Seric i = rcode; 361*588cad61Seric if (i != EX_OK) 362*588cad61Seric { 363*588cad61Seric if (i == EX_TEMPFAIL) 364*588cad61Seric to->q_flags |= QQUEUEUP; 365*588cad61Seric else 366*588cad61Seric to->q_flags |= QBADADDR; 367*588cad61Seric giveresponse(rcode, m); 368*588cad61Seric } 369*588cad61Seric } 370*588cad61Seric 371*588cad61Seric /* now send the closing protocol */ 372*588cad61Seric if (rcode == EX_OK) 373*588cad61Seric rcode = smtpfinish(m, e); 3745826d9d3Seric if (rcode != EX_OK) 375*588cad61Seric giveresponse(rcode, m); 3765826d9d3Seric smtpquit(pv[0], rcode == EX_OK); 377c579ef51Seric } 378c579ef51Seric else 3792c7e1b8dSeric # endif SMTP 380*588cad61Seric rcode = sendoff(e, m, pv, ctladdr); 3815dfc646bSeric 382c77d1c25Seric /* 383c77d1c25Seric ** If we got a temporary failure, arrange to queue the 384c77d1c25Seric ** addressees. 385c77d1c25Seric */ 386c77d1c25Seric 3875826d9d3Seric if (rcode == EX_TEMPFAIL) 388c77d1c25Seric { 389772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 390c77d1c25Seric to->q_flags |= QQUEUEUP; 391c77d1c25Seric } 392c77d1c25Seric 39335490626Seric errno = 0; 394*588cad61Seric define('g', (char *) NULL, e); 3955826d9d3Seric return (rcode); 39625a99e2eSeric } 3975dfc646bSeric /* 39832d19d43Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 39932d19d43Seric ** 40032d19d43Seric ** This MUST be a macro, since after a vfork we are running 40132d19d43Seric ** two processes on the same stack!!! 40232d19d43Seric ** 40332d19d43Seric ** Parameters: 40432d19d43Seric ** none. 40532d19d43Seric ** 40632d19d43Seric ** Returns: 40732d19d43Seric ** From a macro??? You've got to be kidding! 40832d19d43Seric ** 40932d19d43Seric ** Side Effects: 41032d19d43Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 41132d19d43Seric ** pid of child in parent, zero in child. 41232d19d43Seric ** -1 on unrecoverable error. 41332d19d43Seric ** 41432d19d43Seric ** Notes: 41532d19d43Seric ** I'm awfully sorry this looks so awful. That's 41632d19d43Seric ** vfork for you..... 41732d19d43Seric */ 41832d19d43Seric 41932d19d43Seric # define NFORKTRIES 5 4204300ddf0Seric # ifdef VMUNIX 42132d19d43Seric # define XFORK vfork 4224300ddf0Seric # else VMUNIX 42332d19d43Seric # define XFORK fork 4244300ddf0Seric # endif VMUNIX 42532d19d43Seric 42632d19d43Seric # define DOFORK(fORKfN) \ 42732d19d43Seric {\ 42832d19d43Seric register int i;\ 42932d19d43Seric \ 43032d19d43Seric for (i = NFORKTRIES; i-- > 0; )\ 43132d19d43Seric {\ 43232d19d43Seric pid = fORKfN();\ 43332d19d43Seric if (pid >= 0)\ 43432d19d43Seric break;\ 4355e663df1Seric sleep(NFORKTRIES - i);\ 43632d19d43Seric }\ 43732d19d43Seric } 43832d19d43Seric /* 4392ed72599Seric ** DOFORK -- simple fork interface to DOFORK. 4402ed72599Seric ** 4412ed72599Seric ** Parameters: 4422ed72599Seric ** none. 4432ed72599Seric ** 4442ed72599Seric ** Returns: 4452ed72599Seric ** pid of child in parent. 4462ed72599Seric ** zero in child. 4472ed72599Seric ** -1 on error. 4482ed72599Seric ** 4492ed72599Seric ** Side Effects: 4502ed72599Seric ** returns twice, once in parent and once in child. 4512ed72599Seric */ 4522ed72599Seric 4532ed72599Seric dofork() 4542ed72599Seric { 4552ed72599Seric register int pid; 4562ed72599Seric 4572ed72599Seric DOFORK(fork); 4582ed72599Seric return (pid); 4592ed72599Seric } 4602ed72599Seric /* 4615dfc646bSeric ** SENDOFF -- send off call to mailer & collect response. 4625dfc646bSeric ** 4635dfc646bSeric ** Parameters: 464*588cad61Seric ** e -- the envelope to mail. 4655dfc646bSeric ** m -- mailer descriptor. 4665dfc646bSeric ** pvp -- parameter vector to send to it. 4676259796dSeric ** ctladdr -- an address pointer controlling the 4686259796dSeric ** user/groupid etc. of the mailer. 4695dfc646bSeric ** 4705dfc646bSeric ** Returns: 4715dfc646bSeric ** exit status of mailer. 4725dfc646bSeric ** 4735dfc646bSeric ** Side Effects: 4745dfc646bSeric ** none. 4755dfc646bSeric */ 4765dfc646bSeric 477*588cad61Seric sendoff(e, m, pvp, ctladdr) 478*588cad61Seric register ENVELOPE *e; 479*588cad61Seric MAILER *m; 4805dfc646bSeric char **pvp; 4816259796dSeric ADDRESS *ctladdr; 4825dfc646bSeric { 483c579ef51Seric auto FILE *mfile; 484c579ef51Seric auto FILE *rfile; 4855dfc646bSeric register int i; 486c579ef51Seric int pid; 487c579ef51Seric 488c579ef51Seric /* 489c579ef51Seric ** Create connection to mailer. 490c579ef51Seric */ 491c579ef51Seric 492c579ef51Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 493c579ef51Seric if (pid < 0) 494c579ef51Seric return (-1); 495c579ef51Seric 496c579ef51Seric /* 497c579ef51Seric ** Format and send message. 498*588cad61Seric ** We ignore broken pipes so that the mailer need not read 499*588cad61Seric ** its input if it is not convenient to do so (e.g., on 500*588cad61Seric ** some error). 501c579ef51Seric */ 502c579ef51Seric 503c579ef51Seric (void) signal(SIGPIPE, SIG_IGN); 50451552439Seric putfromline(mfile, m); 505*588cad61Seric (*e->e_puthdr)(mfile, m, e); 50651552439Seric fprintf(mfile, "\n"); 507*588cad61Seric (*e->e_putbody)(mfile, m, FALSE); 508c579ef51Seric (void) fclose(mfile); 509c579ef51Seric 510c579ef51Seric i = endmailer(pid, pvp[0]); 511*588cad61Seric giveresponse(i, m); 512bc6e2962Seric 513bc6e2962Seric /* arrange a return receipt if requested */ 514*588cad61Seric if (e->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 515bc6e2962Seric { 516*588cad61Seric e->e_flags |= EF_SENDRECEIPT; 517b254bcb6Seric if (ExitStat == EX_OK && Xscript != NULL) 5183bea8136Seric fprintf(Xscript, "%s... successfully delivered\n", 519*588cad61Seric e->e_to); 520bc6e2962Seric /* do we want to send back more info? */ 521bc6e2962Seric } 522bc6e2962Seric 523c579ef51Seric return (i); 524c579ef51Seric } 525c579ef51Seric /* 526c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 527c579ef51Seric ** 528c579ef51Seric ** We should never get fatal errors (e.g., segmentation 529c579ef51Seric ** violation), so we report those specially. For other 530c579ef51Seric ** errors, we choose a status message (into statmsg), 531c579ef51Seric ** and if it represents an error, we print it. 532c579ef51Seric ** 533c579ef51Seric ** Parameters: 534c579ef51Seric ** pid -- pid of mailer. 535c579ef51Seric ** name -- name of mailer (for error messages). 536c579ef51Seric ** 537c579ef51Seric ** Returns: 538c579ef51Seric ** exit code of mailer. 539c579ef51Seric ** 540c579ef51Seric ** Side Effects: 541c579ef51Seric ** none. 542c579ef51Seric */ 543c579ef51Seric 544c579ef51Seric endmailer(pid, name) 545c579ef51Seric int pid; 546c579ef51Seric char *name; 547c579ef51Seric { 548*588cad61Seric int st; 549c579ef51Seric 55033db8731Seric /* in the IPC case there is nothing to wait for */ 55133db8731Seric if (pid == 0) 55233db8731Seric return (EX_OK); 55333db8731Seric 55433db8731Seric /* wait for the mailer process to die and collect status */ 555*588cad61Seric st = waitfor(pid); 556*588cad61Seric if (st == -1) 55778de67c1Seric { 558*588cad61Seric syserr("endmailer %s: wait", name); 559*588cad61Seric return (EX_SOFTWARE); 560c579ef51Seric } 56133db8731Seric 56233db8731Seric /* see if it died a horrid death */ 563c579ef51Seric if ((st & 0377) != 0) 564c579ef51Seric { 565*588cad61Seric syserr("endmailer %s: stat %o", name, st); 566c579ef51Seric ExitStat = EX_UNAVAILABLE; 567*588cad61Seric return (EX_UNAVAILABLE); 568c579ef51Seric } 56933db8731Seric 57033db8731Seric /* normal death -- return status */ 571*588cad61Seric st = (st >> 8) & 0377; 572*588cad61Seric return (st); 573c579ef51Seric } 574c579ef51Seric /* 575c579ef51Seric ** OPENMAILER -- open connection to mailer. 576c579ef51Seric ** 577c579ef51Seric ** Parameters: 578c579ef51Seric ** m -- mailer descriptor. 579c579ef51Seric ** pvp -- parameter vector to pass to mailer. 580c579ef51Seric ** ctladdr -- controlling address for user. 581c579ef51Seric ** clever -- create a full duplex connection. 582c579ef51Seric ** pmfile -- pointer to mfile (to mailer) connection. 583c579ef51Seric ** prfile -- pointer to rfile (from mailer) connection. 584c579ef51Seric ** 585c579ef51Seric ** Returns: 58633db8731Seric ** pid of mailer ( > 0 ). 587c579ef51Seric ** -1 on error. 58833db8731Seric ** zero on an IPC connection. 589c579ef51Seric ** 590c579ef51Seric ** Side Effects: 591c579ef51Seric ** creates a mailer in a subprocess. 592c579ef51Seric */ 593c579ef51Seric 594c579ef51Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 595*588cad61Seric MAILER *m; 596c579ef51Seric char **pvp; 597c579ef51Seric ADDRESS *ctladdr; 598c579ef51Seric bool clever; 599c579ef51Seric FILE **pmfile; 600c579ef51Seric FILE **prfile; 601c579ef51Seric { 6025dfc646bSeric int pid; 603f8952a83Seric int mpvect[2]; 604c579ef51Seric int rpvect[2]; 6055dfc646bSeric FILE *mfile; 606c579ef51Seric FILE *rfile; 6075dfc646bSeric extern FILE *fdopen(); 6085dfc646bSeric 6095dfc646bSeric # ifdef DEBUG 6106ef48975Seric if (tTd(11, 1)) 6115dfc646bSeric { 6128c57e552Seric printf("openmailer:"); 6135dfc646bSeric printav(pvp); 6145dfc646bSeric } 6155dfc646bSeric # endif DEBUG 61635490626Seric errno = 0; 6175dfc646bSeric 61833db8731Seric /* 61933db8731Seric ** Deal with the special case of mail handled through an IPC 62033db8731Seric ** connection. 62133db8731Seric ** In this case we don't actually fork. We must be 62233db8731Seric ** running SMTP for this to work. We will return a 62333db8731Seric ** zero pid to indicate that we are running IPC. 62433db8731Seric */ 62533db8731Seric 62633db8731Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 62733db8731Seric { 628*588cad61Seric #ifdef DAEMON 62933db8731Seric register int i; 6301277f9a8Seric register u_short port; 63133db8731Seric 63233db8731Seric if (!clever) 63333db8731Seric syserr("non-clever IPC"); 63493b6e3cfSeric if (pvp[2] != NULL) 6351277f9a8Seric port = atoi(pvp[2]); 63693b6e3cfSeric else 6371277f9a8Seric port = 0; 6381277f9a8Seric i = makeconnection(pvp[1], port, pmfile, prfile); 63933db8731Seric if (i != EX_OK) 640ed854c7bSeric { 641ed854c7bSeric ExitStat = i; 64233db8731Seric return (-1); 643ed854c7bSeric } 64433db8731Seric else 64533db8731Seric return (0); 646*588cad61Seric #else DAEMON 647*588cad61Seric syserr("openmailer: no IPC"); 648*588cad61Seric return (-1); 64933db8731Seric #endif DAEMON 650*588cad61Seric } 65133db8731Seric 6526328bdf7Seric /* create a pipe to shove the mail through */ 653f8952a83Seric if (pipe(mpvect) < 0) 65425a99e2eSeric { 655*588cad61Seric syserr("openmailer: pipe (to mailer)"); 65625a99e2eSeric return (-1); 65725a99e2eSeric } 658c579ef51Seric 6592c7e1b8dSeric #ifdef SMTP 660c579ef51Seric /* if this mailer speaks smtp, create a return pipe */ 661c579ef51Seric if (clever && pipe(rpvect) < 0) 662c579ef51Seric { 663*588cad61Seric syserr("openmailer: pipe (from mailer)"); 664c579ef51Seric (void) close(mpvect[0]); 665c579ef51Seric (void) close(mpvect[1]); 666c579ef51Seric return (-1); 667c579ef51Seric } 6682c7e1b8dSeric #endif SMTP 669c579ef51Seric 67033db8731Seric /* 67133db8731Seric ** Actually fork the mailer process. 67233db8731Seric ** DOFORK is clever about retrying. 67333db8731Seric */ 67433db8731Seric 675b254bcb6Seric if (Xscript != NULL) 6766ef48975Seric (void) fflush(Xscript); /* for debugging */ 677*588cad61Seric (void) fflush(stdout); 67832d19d43Seric DOFORK(XFORK); 679f129ec7dSeric /* pid is set by DOFORK */ 68025a99e2eSeric if (pid < 0) 68125a99e2eSeric { 68233db8731Seric /* failure */ 683*588cad61Seric syserr("openmailer: cannot fork"); 684f8952a83Seric (void) close(mpvect[0]); 685f8952a83Seric (void) close(mpvect[1]); 686*588cad61Seric #ifdef SMTP 687c579ef51Seric if (clever) 688c579ef51Seric { 689c579ef51Seric (void) close(rpvect[0]); 690c579ef51Seric (void) close(rpvect[1]); 691c579ef51Seric } 692*588cad61Seric #endif SMTP 69325a99e2eSeric return (-1); 69425a99e2eSeric } 69525a99e2eSeric else if (pid == 0) 69625a99e2eSeric { 69725a99e2eSeric /* child -- set up input & exec mailer */ 69803ab8e55Seric /* make diagnostic output be standard output */ 6998f0e7860Seric (void) signal(SIGINT, SIG_IGN); 7008f0e7860Seric (void) signal(SIGHUP, SIG_IGN); 7010984da9fSeric (void) signal(SIGTERM, SIG_DFL); 702f8952a83Seric 703f8952a83Seric /* arrange to filter standard & diag output of command */ 704c579ef51Seric if (clever) 705c579ef51Seric { 706c579ef51Seric (void) close(rpvect[0]); 707c579ef51Seric (void) close(1); 708c579ef51Seric (void) dup(rpvect[1]); 709c579ef51Seric (void) close(rpvect[1]); 710c579ef51Seric } 711276723a8Seric else if (OpMode == MD_SMTP || HoldErrs) 712f8952a83Seric { 713*588cad61Seric /* put mailer output in transcript */ 714f8952a83Seric (void) close(1); 7159df2a963Seric (void) dup(fileno(Xscript)); 716f8952a83Seric } 717db8841e9Seric (void) close(2); 718db8841e9Seric (void) dup(1); 719f8952a83Seric 720f8952a83Seric /* arrange to get standard input */ 721f8952a83Seric (void) close(mpvect[1]); 722db8841e9Seric (void) close(0); 723f8952a83Seric if (dup(mpvect[0]) < 0) 72425a99e2eSeric { 72525a99e2eSeric syserr("Cannot dup to zero!"); 726a590b978Seric _exit(EX_OSERR); 72725a99e2eSeric } 728f8952a83Seric (void) close(mpvect[0]); 7292a6e0786Seric if (!bitset(M_RESTR, m->m_flags)) 7300984da9fSeric { 731e36b99e2Seric if (ctladdr->q_uid == 0) 732e36b99e2Seric { 733e36b99e2Seric (void) setgid(DefGid); 734e36b99e2Seric (void) setuid(DefUid); 735e36b99e2Seric } 736e36b99e2Seric else 73769f29479Seric { 738e36b99e2Seric (void) setgid(ctladdr->q_gid); 739e36b99e2Seric (void) setuid(ctladdr->q_uid); 74069f29479Seric } 7410984da9fSeric } 742*588cad61Seric 743e374fd72Seric /* 744e374fd72Seric ** We have to be careful with vfork - we can't mung up the 745e374fd72Seric ** memory but we don't want the mailer to inherit any extra 746e374fd72Seric ** open files. Chances are the mailer won't 747e374fd72Seric ** care about an extra file, but then again you never know. 748e374fd72Seric ** Actually, we would like to close(fileno(pwf)), but it's 749e374fd72Seric ** declared static so we can't. But if we fclose(pwf), which 750e374fd72Seric ** is what endpwent does, it closes it in the parent too and 751e374fd72Seric ** the next getpwnam will be slower. If you have a weird 752e374fd72Seric ** mailer that chokes on the extra file you should do the 7534300ddf0Seric ** endpwent(). -MRH 754e374fd72Seric ** 755e374fd72Seric ** Similar comments apply to log. However, openlog is 756e374fd72Seric ** clever enough to set the FIOCLEX mode on the file, 757e374fd72Seric ** so it will be closed automatically on the exec. 758e374fd72Seric */ 759e374fd72Seric 760*588cad61Seric closeall(); 76133db8731Seric 76233db8731Seric /* try to execute the mailer */ 76325a99e2eSeric execv(m->m_mailer, pvp); 76433db8731Seric 76525a99e2eSeric /* syserr fails because log is closed */ 76625a99e2eSeric /* syserr("Cannot exec %s", m->m_mailer); */ 76732d19d43Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 768db8841e9Seric (void) fflush(stdout); 769a590b978Seric _exit(EX_UNAVAILABLE); 77025a99e2eSeric } 77125a99e2eSeric 772f8952a83Seric /* 773c579ef51Seric ** Set up return value. 774f8952a83Seric */ 775f8952a83Seric 776f8952a83Seric (void) close(mpvect[0]); 777f8952a83Seric mfile = fdopen(mpvect[1], "w"); 778c579ef51Seric if (clever) 77925a99e2eSeric { 780c579ef51Seric (void) close(rpvect[1]); 781c579ef51Seric rfile = fdopen(rpvect[0], "r"); 78225a99e2eSeric } 783c579ef51Seric 784c579ef51Seric *pmfile = mfile; 785c579ef51Seric *prfile = rfile; 786c579ef51Seric 787c579ef51Seric return (pid); 78825a99e2eSeric } 78925a99e2eSeric /* 79025a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 79125a99e2eSeric ** 79225a99e2eSeric ** Parameters: 79325a99e2eSeric ** stat -- the status code from the mailer (high byte 79425a99e2eSeric ** only; core dumps must have been taken care of 79525a99e2eSeric ** already). 79625a99e2eSeric ** m -- the mailer descriptor for this mailer. 79725a99e2eSeric ** 79825a99e2eSeric ** Returns: 799db8841e9Seric ** none. 80025a99e2eSeric ** 80125a99e2eSeric ** Side Effects: 802c1f9df2cSeric ** Errors may be incremented. 80325a99e2eSeric ** ExitStat may be set. 80425a99e2eSeric */ 80525a99e2eSeric 806*588cad61Seric /*ARGSUSED*/ 807*588cad61Seric giveresponse(stat, m) 80825a99e2eSeric int stat; 809*588cad61Seric register MAILER *m; 81025a99e2eSeric { 81125a99e2eSeric register char *statmsg; 81225a99e2eSeric extern char *SysExMsg[]; 81325a99e2eSeric register int i; 81425a99e2eSeric extern int N_SysEx; 81529dd97a3Seric char buf[30]; 81625a99e2eSeric 81713bbc08cSeric /* 81813bbc08cSeric ** Compute status message from code. 81913bbc08cSeric */ 82013bbc08cSeric 82125a99e2eSeric i = stat - EX__BASE; 822*588cad61Seric if (stat == 0) 823*588cad61Seric statmsg = "250 Sent"; 824*588cad61Seric else if (i < 0 || i > N_SysEx) 825*588cad61Seric { 826*588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 827*588cad61Seric stat = EX_UNAVAILABLE; 828*588cad61Seric statmsg = buf; 829*588cad61Seric } 83025a99e2eSeric else 83125a99e2eSeric statmsg = SysExMsg[i]; 832*588cad61Seric 833*588cad61Seric /* 834*588cad61Seric ** Print the message as appropriate 835*588cad61Seric */ 836*588cad61Seric 83725a99e2eSeric if (stat == 0) 8385826d9d3Seric message(Arpa_Info, &statmsg[4]); 839c77d1c25Seric else if (stat == EX_TEMPFAIL) 840eb238f8cSeric message(Arpa_Info, "deferred"); 84125a99e2eSeric else 84225a99e2eSeric { 843c1f9df2cSeric Errors++; 8445826d9d3Seric usrerr(statmsg); 845*588cad61Seric CurEnv->e_flags |= EF_FATALERRS; 84625a99e2eSeric } 84725a99e2eSeric 84825a99e2eSeric /* 84925a99e2eSeric ** Final cleanup. 85025a99e2eSeric ** Log a record of the transaction. Compute the new 85125a99e2eSeric ** ExitStat -- if we already had an error, stick with 85225a99e2eSeric ** that. 85325a99e2eSeric */ 85425a99e2eSeric 85561f5a1d4Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 856eb238f8cSeric logdelivery(&statmsg[4]); 857eb238f8cSeric 858eb238f8cSeric if (stat != EX_TEMPFAIL) 859eb238f8cSeric setstat(stat); 860eb238f8cSeric } 861eb238f8cSeric /* 862eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 863eb238f8cSeric ** 864eb238f8cSeric ** Parameters: 865eb238f8cSeric ** stat -- the message to print for the status 866eb238f8cSeric ** 867eb238f8cSeric ** Returns: 868eb238f8cSeric ** none 869eb238f8cSeric ** 870eb238f8cSeric ** Side Effects: 871eb238f8cSeric ** none 872eb238f8cSeric */ 873eb238f8cSeric 874eb238f8cSeric logdelivery(stat) 875eb238f8cSeric char *stat; 8765cf56be3Seric { 8775cf56be3Seric extern char *pintvl(); 8785cf56be3Seric 879eb238f8cSeric # ifdef LOG 8805cf56be3Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 881eb238f8cSeric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 88225a99e2eSeric # endif LOG 88325a99e2eSeric } 88425a99e2eSeric /* 88551552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 88625a99e2eSeric ** 88751552439Seric ** This can be made an arbitrary message separator by changing $l 88851552439Seric ** 88951552439Seric ** One of the ugliest hacks seen by human eyes is 89051552439Seric ** contained herein: UUCP wants those stupid 891*588cad61Seric ** "emote from <host>" lines. Why oh why does a 89251552439Seric ** well-meaning programmer such as myself have to 89351552439Seric ** deal with this kind of antique garbage???? 89425a99e2eSeric ** 89525a99e2eSeric ** Parameters: 89651552439Seric ** fp -- the file to output to. 89751552439Seric ** m -- the mailer describing this entry. 89825a99e2eSeric ** 89925a99e2eSeric ** Returns: 90051552439Seric ** none 90125a99e2eSeric ** 90225a99e2eSeric ** Side Effects: 90351552439Seric ** outputs some text to fp. 90425a99e2eSeric */ 90525a99e2eSeric 90651552439Seric putfromline(fp, m) 90751552439Seric register FILE *fp; 90851552439Seric register MAILER *m; 90925a99e2eSeric { 91051552439Seric char buf[MAXLINE]; 91125a99e2eSeric 91251552439Seric if (bitset(M_NHDR, m->m_flags)) 91351552439Seric return; 91413bbc08cSeric 9152c7e1b8dSeric # ifdef UGLYUUCP 916a49f24c0Seric if (bitset(M_UGLYUUCP, m->m_flags)) 91774b6e67bSeric { 91874b6e67bSeric extern char *macvalue(); 9198c57e552Seric char *sys = macvalue('g', CurEnv); 92074b6e67bSeric char *bang = index(sys, '!'); 92174b6e67bSeric 92274b6e67bSeric if (bang == NULL) 92374b6e67bSeric syserr("No ! in UUCP! (%s)", sys); 92474b6e67bSeric else 925*588cad61Seric { 92674b6e67bSeric *bang = '\0'; 927518ad6b6Seric expand("From $f $d remote from $g\n", buf, 92851552439Seric &buf[sizeof buf - 1], CurEnv); 92974b6e67bSeric *bang = '!'; 93074b6e67bSeric } 931*588cad61Seric } 932a36e30c9Seric else 9332c7e1b8dSeric # endif UGLYUUCP 93451552439Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 935d90b8d00Seric putline(buf, fp, bitset(M_FULLSMTP, m->m_flags)); 936bc6e2962Seric } 937bc6e2962Seric /* 93851552439Seric ** PUTBODY -- put the body of a message. 93951552439Seric ** 94051552439Seric ** Parameters: 94151552439Seric ** fp -- file to output onto. 94251552439Seric ** m -- a mailer descriptor. 94351552439Seric ** xdot -- if set, use SMTP hidden dot algorithm. 94451552439Seric ** 94551552439Seric ** Returns: 94651552439Seric ** none. 94751552439Seric ** 94851552439Seric ** Side Effects: 94951552439Seric ** The message is written onto fp. 95051552439Seric */ 95151552439Seric 95251552439Seric putbody(fp, m, xdot) 95351552439Seric FILE *fp; 954*588cad61Seric MAILER *m; 95551552439Seric bool xdot; 95651552439Seric { 95751552439Seric char buf[MAXLINE + 1]; 958d90b8d00Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 95951552439Seric 96051552439Seric /* 96151552439Seric ** Output the body of the message 96251552439Seric */ 96351552439Seric 96451552439Seric if (TempFile != NULL) 96551552439Seric { 96651552439Seric rewind(TempFile); 96751552439Seric buf[0] = '.'; 96851552439Seric while (!ferror(fp) && fgets(&buf[1], sizeof buf - 1, TempFile) != NULL) 969d90b8d00Seric putline((xdot && buf[1] == '.') ? buf : &buf[1], fp, fullsmtp); 97051552439Seric 97151552439Seric if (ferror(TempFile)) 97251552439Seric { 97351552439Seric syserr("putbody: read error"); 97451552439Seric ExitStat = EX_IOERR; 97551552439Seric } 97651552439Seric } 97751552439Seric 97851552439Seric (void) fflush(fp); 97951552439Seric if (ferror(fp) && errno != EPIPE) 98051552439Seric { 98151552439Seric syserr("putbody: write error"); 98251552439Seric ExitStat = EX_IOERR; 98351552439Seric } 98451552439Seric errno = 0; 98525a99e2eSeric } 98625a99e2eSeric /* 98725a99e2eSeric ** MAILFILE -- Send a message to a file. 98825a99e2eSeric ** 989f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 990f129ec7dSeric ** bits, sendmail will try to become the owner of that file 991f129ec7dSeric ** rather than the real user. Obviously, this only works if 992f129ec7dSeric ** sendmail runs as root. 993f129ec7dSeric ** 994*588cad61Seric ** This could be done as a subordinate mailer, except that it 995*588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 996*588cad61Seric ** view this as being sufficiently important as to include it 997*588cad61Seric ** here. For example, if the system is dying, we shouldn't have 998*588cad61Seric ** to create another process plus some pipes to save the message. 999*588cad61Seric ** 100025a99e2eSeric ** Parameters: 100125a99e2eSeric ** filename -- the name of the file to send to. 10026259796dSeric ** ctladdr -- the controlling address header -- includes 10036259796dSeric ** the userid/groupid to be when sending. 100425a99e2eSeric ** 100525a99e2eSeric ** Returns: 100625a99e2eSeric ** The exit code associated with the operation. 100725a99e2eSeric ** 100825a99e2eSeric ** Side Effects: 100925a99e2eSeric ** none. 101025a99e2eSeric */ 101125a99e2eSeric 10126259796dSeric mailfile(filename, ctladdr) 101325a99e2eSeric char *filename; 10146259796dSeric ADDRESS *ctladdr; 101525a99e2eSeric { 101625a99e2eSeric register FILE *f; 101732d19d43Seric register int pid; 101825a99e2eSeric 101932d19d43Seric /* 102032d19d43Seric ** Fork so we can change permissions here. 102132d19d43Seric ** Note that we MUST use fork, not vfork, because of 102232d19d43Seric ** the complications of calling subroutines, etc. 102332d19d43Seric */ 102432d19d43Seric 102532d19d43Seric DOFORK(fork); 102632d19d43Seric 102732d19d43Seric if (pid < 0) 102832d19d43Seric return (EX_OSERR); 102932d19d43Seric else if (pid == 0) 103032d19d43Seric { 103132d19d43Seric /* child -- actually write to file */ 1032f129ec7dSeric struct stat stb; 1033f129ec7dSeric 10340984da9fSeric (void) signal(SIGINT, SIG_DFL); 10350984da9fSeric (void) signal(SIGHUP, SIG_DFL); 10360984da9fSeric (void) signal(SIGTERM, SIG_DFL); 1037f129ec7dSeric umask(OldUmask); 1038f129ec7dSeric if (stat(filename, &stb) < 0) 1039e6e1265fSeric stb.st_mode = 0666; 1040f129ec7dSeric if (bitset(0111, stb.st_mode)) 1041f129ec7dSeric exit(EX_CANTCREAT); 104203827b5fSeric if (ctladdr == NULL) 10437a941e7aSeric ctladdr = &CurEnv->e_from; 1044f129ec7dSeric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 1045e36b99e2Seric { 1046e36b99e2Seric if (ctladdr->q_uid == 0) 1047e36b99e2Seric (void) setgid(DefGid); 1048e36b99e2Seric else 10496259796dSeric (void) setgid(ctladdr->q_gid); 1050e36b99e2Seric } 1051f129ec7dSeric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 1052e36b99e2Seric { 1053e36b99e2Seric if (ctladdr->q_uid == 0) 1054e36b99e2Seric (void) setuid(DefUid); 1055e36b99e2Seric else 10566259796dSeric (void) setuid(ctladdr->q_uid); 1057e36b99e2Seric } 105827628d59Seric f = dfopen(filename, "a"); 105925a99e2eSeric if (f == NULL) 106032d19d43Seric exit(EX_CANTCREAT); 106125a99e2eSeric 1062*588cad61Seric putfromline(f, ProgMailer); 1063*588cad61Seric (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); 1064d90b8d00Seric fputs("\n", f); 1065*588cad61Seric (*CurEnv->e_putbody)(f, ProgMailer, FALSE); 106625a99e2eSeric fputs("\n", f); 1067db8841e9Seric (void) fclose(f); 106832d19d43Seric (void) fflush(stdout); 1069e36b99e2Seric 107027628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 1071c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 107232d19d43Seric exit(EX_OK); 107313bbc08cSeric /*NOTREACHED*/ 107432d19d43Seric } 107532d19d43Seric else 107632d19d43Seric { 107732d19d43Seric /* parent -- wait for exit status */ 1078*588cad61Seric int st; 107932d19d43Seric 1080*588cad61Seric st = waitfor(pid); 1081*588cad61Seric if ((st & 0377) != 0) 1082*588cad61Seric return (EX_UNAVAILABLE); 1083*588cad61Seric else 1084*588cad61Seric return ((st >> 8) & 0377); 108532d19d43Seric } 108625a99e2eSeric } 1087ea4dc939Seric /* 1088ea4dc939Seric ** SENDALL -- actually send all the messages. 1089ea4dc939Seric ** 1090ea4dc939Seric ** Parameters: 10910c52a0b3Seric ** e -- the envelope to send. 1092276723a8Seric ** mode -- the delivery mode to use. 1093ea4dc939Seric ** 1094ea4dc939Seric ** Returns: 1095ea4dc939Seric ** none. 1096ea4dc939Seric ** 1097ea4dc939Seric ** Side Effects: 1098ea4dc939Seric ** Scans the send lists and sends everything it finds. 10990c52a0b3Seric ** Delivers any appropriate error messages. 1100276723a8Seric ** If we are running in a non-interactive mode, takes the 1101276723a8Seric ** appropriate action. 1102ea4dc939Seric */ 1103ea4dc939Seric 1104276723a8Seric sendall(e, mode) 11050c52a0b3Seric ENVELOPE *e; 1106276723a8Seric char mode; 1107ea4dc939Seric { 1108e77e673fSeric register ADDRESS *q; 110914a8ed7aSeric bool oldverbose; 1110276723a8Seric int pid; 1111ea4dc939Seric 1112772e6e50Seric #ifdef DEBUG 1113df864a8fSeric if (tTd(13, 1)) 1114772e6e50Seric { 1115276723a8Seric printf("\nSENDALL: mode %c, sendqueue:\n", mode); 11160c52a0b3Seric printaddr(e->e_sendqueue, TRUE); 1117772e6e50Seric } 1118772e6e50Seric #endif DEBUG 1119ea4dc939Seric 11200c52a0b3Seric /* 1121276723a8Seric ** Do any preprocessing necessary for the mode we are running. 1122*588cad61Seric ** Check to make sure the hop count is reasonable. 1123*588cad61Seric ** Delete sends to the sender in mailing lists. 1124276723a8Seric */ 1125276723a8Seric 1126*588cad61Seric CurEnv = e; 1127276723a8Seric 1128*588cad61Seric if (e->e_hopcount > MAXHOP) 1129276723a8Seric { 1130*588cad61Seric syserr("sendall: too many hops (%d max)", MAXHOP); 1131*588cad61Seric return; 1132*588cad61Seric } 1133*588cad61Seric 1134*588cad61Seric if (!MeToo) 1135276723a8Seric { 1136*588cad61Seric e->e_from.q_flags |= QDONTSEND; 1137*588cad61Seric recipient(&e->e_from, &e->e_sendqueue); 1138276723a8Seric } 1139*588cad61Seric 1140*588cad61Seric # ifdef QUEUE 1141b254bcb6Seric if ((mode == SM_QUEUE || mode == SM_FORK || 1142b254bcb6Seric (mode != SM_VERIFY && SuperSafe)) && 1143b254bcb6Seric !bitset(EF_INQUEUE, e->e_flags)) 1144*588cad61Seric queueup(e, TRUE, mode == SM_QUEUE); 1145276723a8Seric #endif QUEUE 1146276723a8Seric 1147276723a8Seric oldverbose = Verbose; 1148276723a8Seric switch (mode) 1149276723a8Seric { 1150276723a8Seric case SM_VERIFY: 1151276723a8Seric Verbose = TRUE; 1152276723a8Seric break; 1153276723a8Seric 1154276723a8Seric case SM_QUEUE: 1155b254bcb6Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 1156276723a8Seric return; 1157276723a8Seric 1158276723a8Seric case SM_FORK: 1159b254bcb6Seric if (Xscript != NULL) 1160a6fce3d8Seric (void) fflush(Xscript); 1161276723a8Seric pid = fork(); 1162276723a8Seric if (pid < 0) 1163276723a8Seric { 1164276723a8Seric mode = SM_DELIVER; 1165276723a8Seric break; 1166276723a8Seric } 1167276723a8Seric else if (pid > 0) 1168a6fce3d8Seric { 1169a6fce3d8Seric /* be sure we leave the temp files to our child */ 1170b254bcb6Seric e->e_id = e->e_df = NULL; 1171276723a8Seric return; 1172a6fce3d8Seric } 1173276723a8Seric 1174276723a8Seric /* double fork to avoid zombies */ 1175276723a8Seric if (fork() > 0) 1176276723a8Seric exit(EX_OK); 1177276723a8Seric 1178a6fce3d8Seric /* be sure we are immune from the terminal */ 1179a6fce3d8Seric disconnect(TRUE); 1180a6fce3d8Seric 1181276723a8Seric break; 1182276723a8Seric } 1183276723a8Seric 1184276723a8Seric /* 11850c52a0b3Seric ** Run through the list and send everything. 11860c52a0b3Seric */ 11870c52a0b3Seric 11880c52a0b3Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 1189ea4dc939Seric { 1190276723a8Seric if (mode == SM_VERIFY) 1191ea4dc939Seric { 1192a6fce3d8Seric e->e_to = q->q_paddr; 1193e77e673fSeric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 1194ea4dc939Seric message(Arpa_Info, "deliverable"); 1195ea4dc939Seric } 1196ea4dc939Seric else 1197*588cad61Seric (void) deliver(e, q); 1198ea4dc939Seric } 119914a8ed7aSeric Verbose = oldverbose; 12000c52a0b3Seric 12010c52a0b3Seric /* 12020c52a0b3Seric ** Now run through and check for errors. 12030c52a0b3Seric */ 12040c52a0b3Seric 1205276723a8Seric if (mode == SM_VERIFY) 12060c52a0b3Seric return; 12070c52a0b3Seric 12080c52a0b3Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 12090c52a0b3Seric { 12100c52a0b3Seric register ADDRESS *qq; 12110c52a0b3Seric 1212df864a8fSeric # ifdef DEBUG 1213df864a8fSeric if (tTd(13, 3)) 1214df864a8fSeric { 1215df864a8fSeric printf("Checking "); 1216df864a8fSeric printaddr(q, FALSE); 1217df864a8fSeric } 1218df864a8fSeric # endif DEBUG 1219df864a8fSeric 1220b254bcb6Seric /* only send errors if the message failed */ 1221b254bcb6Seric if (!bitset(QBADADDR, q->q_flags)) 1222b254bcb6Seric continue; 12230c52a0b3Seric 12240c52a0b3Seric /* we have an address that failed -- find the parent */ 12250c52a0b3Seric for (qq = q; qq != NULL; qq = qq->q_alias) 12260c52a0b3Seric { 12270c52a0b3Seric char obuf[MAXNAME + 6]; 12280c52a0b3Seric extern char *aliaslookup(); 12290c52a0b3Seric 12300c52a0b3Seric /* we can only have owners for local addresses */ 12310c52a0b3Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 12320c52a0b3Seric continue; 12330c52a0b3Seric 12340c52a0b3Seric /* see if the owner list exists */ 12350c52a0b3Seric (void) strcpy(obuf, "owner-"); 1236cec031e3Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 1237cec031e3Seric (void) strcat(obuf, "owner"); 1238cec031e3Seric else 12390c52a0b3Seric (void) strcat(obuf, qq->q_user); 12400c52a0b3Seric if (aliaslookup(obuf) == NULL) 12410c52a0b3Seric continue; 12420c52a0b3Seric 1243df864a8fSeric # ifdef DEBUG 1244df864a8fSeric if (tTd(13, 4)) 1245df864a8fSeric printf("Errors to %s\n", obuf); 1246df864a8fSeric # endif DEBUG 1247df864a8fSeric 12480c52a0b3Seric /* owner list exists -- add it to the error queue */ 1249*588cad61Seric sendto(obuf, (ADDRESS *) NULL, &e->e_errorqueue); 1250*588cad61Seric ErrorMode == EM_MAIL; 12510c52a0b3Seric break; 12520c52a0b3Seric } 12530c52a0b3Seric 12540c52a0b3Seric /* if we did not find an owner, send to the sender */ 12557455aa0bSeric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 1256656d6d13Seric sendto(e->e_from.q_paddr, qq, &e->e_errorqueue); 12570c52a0b3Seric } 1258276723a8Seric 1259276723a8Seric if (mode == SM_FORK) 1260276723a8Seric finis(); 12610c52a0b3Seric } 1262