1294Seric # include <signal.h> 24123Seric # include <errno.h> 34621Seric # include "sendmail.h" 44327Seric # include <sys/stat.h> 5294Seric 6*9206Seric SCCSID(@(#)deliver.c 3.128 11/14/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 239*9206Seric /* hack attack -- delivermail compatibility */ 240*9206Seric if (m == ProgMailer && *user == '|') 241*9206Seric user++; 242*9206Seric 2433233Seric /* 2447052Seric ** Do initial connection setup if needed. 2457052Seric */ 2467052Seric 2477052Seric if (notopen) 2487052Seric { 2497052Seric message(Arpa_Info, "Connecting to %s.%s...", host, m->m_name); 2507052Seric # ifdef SMTP 2517052Seric if (clever) 2527052Seric { 2537052Seric /* send the initial SMTP protocol */ 2548003Seric rcode = smtpinit(m, pv, (ADDRESS *) NULL); 2557052Seric } 2567052Seric # ifdef SMTP 2577052Seric notopen = FALSE; 2587052Seric } 2597052Seric 2607052Seric /* 2616059Seric ** Pass it to the other host if we are running SMTP. 2626059Seric */ 2636059Seric 2646059Seric if (clever) 2656059Seric { 2666059Seric # ifdef SMTP 2678003Seric if (rcode == EX_OK) 2688003Seric rcode = smtprcpt(to); 2698003Seric if (rcode != EX_OK) 2706059Seric { 2718003Seric if (rcode == EX_TEMPFAIL) 2726059Seric to->q_flags |= QQUEUEUP; 2736059Seric else 2746059Seric to->q_flags |= QBADADDR; 2758003Seric giveresponse(rcode, TRUE, m); 2766059Seric } 2776059Seric # else SMTP 2786059Seric syserr("trying to be clever"); 2796059Seric # endif SMTP 2806059Seric } 2816059Seric 2826059Seric /* 2834161Seric ** If an error message has already been given, don't 2844161Seric ** bother to send to this address. 2854161Seric ** 2864161Seric ** >>>>>>>>>> This clause assumes that the local mailer 2874161Seric ** >> NOTE >> cannot do any further aliasing; that 2884161Seric ** >>>>>>>>>> function is subsumed by sendmail. 2894161Seric */ 2904161Seric 2917293Seric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 2924161Seric continue; 2934161Seric 2944283Seric /* save statistics.... */ 2954596Seric Stat.stat_nt[to->q_mailer->m_mno]++; 2966900Seric Stat.stat_bt[to->q_mailer->m_mno] += kbytes(CurEnv->e_msgsize); 2974283Seric 2984161Seric /* 2993233Seric ** See if this user name is "special". 3003233Seric ** If the user name has a slash in it, assume that this 3016974Seric ** is a file -- send it off without further ado. Note 3026974Seric ** that this type of addresses is not processed along 3036974Seric ** with the others, so we fudge on the To person. 3043233Seric */ 3053233Seric 3064596Seric if (m == LocalMailer) 3073233Seric { 3085599Seric if (user[0] == '/') 309294Seric { 3108003Seric rcode = mailfile(user, getctladdr(to)); 3118003Seric giveresponse(rcode, TRUE, m); 3123233Seric continue; 313294Seric } 314294Seric } 3153233Seric 3164315Seric /* 3174315Seric ** Address is verified -- add this user to mailer 3184315Seric ** argv, and add it to the print list of recipients. 3194315Seric */ 3204315Seric 3216059Seric /* link together the chain of recipients */ 3226272Seric to->q_tchain = tochain; 3236272Seric tochain = to; 3246059Seric 3253233Seric /* create list of users for error messages */ 3263233Seric if (tobuf[0] != '\0') 3274082Seric (void) strcat(tobuf, ","); 3284082Seric (void) strcat(tobuf, to->q_paddr); 3293233Seric define('u', user); /* to user */ 3304078Seric define('z', to->q_home); /* user's home */ 3313233Seric 3324863Seric /* 3336059Seric ** Expand out this user into argument list. 3344863Seric */ 3354863Seric 3366059Seric if (!clever) 3373233Seric { 3386974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3394863Seric *pvp++ = newstr(buf); 3404863Seric if (pvp >= &pv[MAXPV - 2]) 3414863Seric { 3424863Seric /* allow some space for trailing parms */ 3434863Seric break; 3444863Seric } 3454863Seric } 346294Seric } 347294Seric 3484067Seric /* see if any addresses still exist */ 3494067Seric if (tobuf[0] == '\0') 3504863Seric { 3515179Seric # ifdef SMTP 3528906Seric if (clever && !notopen) 3537228Seric smtpquit(pv[0], FALSE); 3545179Seric # endif SMTP 3557003Seric define('g', (char *) NULL); 3564067Seric return (0); 3574863Seric } 3584067Seric 3593233Seric /* print out messages as full list */ 3606900Seric CurEnv->e_to = tobuf; 3613233Seric 362294Seric /* 3633233Seric ** Fill out any parameters after the $u parameter. 364294Seric */ 365294Seric 3664863Seric while (!clever && *++mvp != NULL) 367294Seric { 3686974Seric expand(*mvp, buf, &buf[sizeof buf - 1], CurEnv); 3693233Seric *pvp++ = newstr(buf); 3703233Seric if (pvp >= &pv[MAXPV]) 3713233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 372294Seric } 3733233Seric *pvp++ = NULL; 374294Seric 375294Seric /* 376294Seric ** Call the mailer. 3772898Seric ** The argument vector gets built, pipes 378294Seric ** are created as necessary, and we fork & exec as 3792898Seric ** appropriate. 3804863Seric ** If we are running SMTP, we just need to clean up. 381294Seric */ 382294Seric 3834397Seric if (ctladdr == NULL) 3846900Seric ctladdr = &CurEnv->e_from; 3855179Seric # ifdef SMTP 3864863Seric if (clever) 3874863Seric { 3888003Seric rcode = smtpfinish(m, CurEnv); 3898003Seric if (rcode != EX_OK) 3908003Seric giveresponse(rcode, TRUE, m); 3918003Seric smtpquit(pv[0], rcode == EX_OK); 3924863Seric } 3934863Seric else 3945179Seric # endif SMTP 3958003Seric rcode = sendoff(m, pv, ctladdr); 3963233Seric 3974621Seric /* 3984621Seric ** If we got a temporary failure, arrange to queue the 3994621Seric ** addressees. 4004621Seric */ 4014621Seric 4028003Seric if (rcode == EX_TEMPFAIL) 4034621Seric { 4045032Seric for (to = tochain; to != NULL; to = to->q_tchain) 4054621Seric to->q_flags |= QQUEUEUP; 4064621Seric } 4074621Seric 4084488Seric errno = 0; 4097003Seric define('g', (char *) NULL); 4108003Seric return (rcode); 4113233Seric } 4123233Seric /* 4134214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4144214Seric ** 4154214Seric ** This MUST be a macro, since after a vfork we are running 4164214Seric ** two processes on the same stack!!! 4174214Seric ** 4184214Seric ** Parameters: 4194214Seric ** none. 4204214Seric ** 4214214Seric ** Returns: 4224214Seric ** From a macro??? You've got to be kidding! 4234214Seric ** 4244214Seric ** Side Effects: 4254214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4264214Seric ** pid of child in parent, zero in child. 4274214Seric ** -1 on unrecoverable error. 4284214Seric ** 4294214Seric ** Notes: 4304214Seric ** I'm awfully sorry this looks so awful. That's 4314214Seric ** vfork for you..... 4324214Seric */ 4334214Seric 4344214Seric # define NFORKTRIES 5 4359148Seric # ifdef VMUNIX 4364214Seric # define XFORK vfork 4379148Seric # else VMUNIX 4384214Seric # define XFORK fork 4399148Seric # endif VMUNIX 4404214Seric 4414214Seric # define DOFORK(fORKfN) \ 4424214Seric {\ 4434214Seric register int i;\ 4444214Seric \ 4454214Seric for (i = NFORKTRIES; i-- > 0; )\ 4464214Seric {\ 4474214Seric pid = fORKfN();\ 4484214Seric if (pid >= 0)\ 4494214Seric break;\ 4507003Seric sleep(NFORKTRIES - i);\ 4514214Seric }\ 4524214Seric } 4534214Seric /* 4544637Seric ** DOFORK -- simple fork interface to DOFORK. 4554637Seric ** 4564637Seric ** Parameters: 4574637Seric ** none. 4584637Seric ** 4594637Seric ** Returns: 4604637Seric ** pid of child in parent. 4614637Seric ** zero in child. 4624637Seric ** -1 on error. 4634637Seric ** 4644637Seric ** Side Effects: 4654637Seric ** returns twice, once in parent and once in child. 4664637Seric */ 4674637Seric 4684637Seric dofork() 4694637Seric { 4704637Seric register int pid; 4714637Seric 4724637Seric DOFORK(fork); 4734637Seric return (pid); 4744637Seric } 4754637Seric /* 4763233Seric ** SENDOFF -- send off call to mailer & collect response. 4773233Seric ** 4783233Seric ** Parameters: 4793233Seric ** m -- mailer descriptor. 4803233Seric ** pvp -- parameter vector to send to it. 4814397Seric ** ctladdr -- an address pointer controlling the 4824397Seric ** user/groupid etc. of the mailer. 4833233Seric ** 4843233Seric ** Returns: 4853233Seric ** exit status of mailer. 4863233Seric ** 4873233Seric ** Side Effects: 4883233Seric ** none. 4893233Seric */ 4903233Seric 4916974Seric sendoff(m, pvp, ctladdr) 4923233Seric struct mailer *m; 4933233Seric char **pvp; 4944397Seric ADDRESS *ctladdr; 4953233Seric { 4964863Seric auto FILE *mfile; 4974863Seric auto FILE *rfile; 4983233Seric register int i; 4993233Seric int pid; 5004863Seric 5014863Seric /* 5024863Seric ** Create connection to mailer. 5034863Seric */ 5044863Seric 5054863Seric pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile); 5064863Seric if (pid < 0) 5074863Seric return (-1); 5084863Seric 5094863Seric /* 5104863Seric ** Format and send message. 5114863Seric */ 5124863Seric 5134863Seric (void) signal(SIGPIPE, SIG_IGN); 5146974Seric putfromline(mfile, m); 5156974Seric (*CurEnv->e_puthdr)(mfile, m, CurEnv); 5166974Seric fprintf(mfile, "\n"); 5176974Seric (*CurEnv->e_putbody)(mfile, m, FALSE); 5184863Seric (void) fclose(mfile); 5194863Seric 5204863Seric i = endmailer(pid, pvp[0]); 5214863Seric giveresponse(i, TRUE, m); 5225981Seric 5235981Seric /* arrange a return receipt if requested */ 5248062Seric if (CurEnv->e_receiptto != NULL && bitset(M_LOCAL, m->m_flags)) 5255981Seric { 5266900Seric CurEnv->e_sendreceipt = TRUE; 5278062Seric if (ExitStat == EX_OK) 5288062Seric fprintf(Xscript, "%s... successfully delivered\n", 5298062Seric CurEnv->e_to); 5305981Seric /* do we want to send back more info? */ 5315981Seric } 5325981Seric 5334863Seric return (i); 5344863Seric } 5354863Seric /* 5364863Seric ** ENDMAILER -- Wait for mailer to terminate. 5374863Seric ** 5384863Seric ** We should never get fatal errors (e.g., segmentation 5394863Seric ** violation), so we report those specially. For other 5404863Seric ** errors, we choose a status message (into statmsg), 5414863Seric ** and if it represents an error, we print it. 5424863Seric ** 5434863Seric ** Parameters: 5444863Seric ** pid -- pid of mailer. 5454863Seric ** name -- name of mailer (for error messages). 5464863Seric ** 5474863Seric ** Returns: 5484863Seric ** exit code of mailer. 5494863Seric ** 5504863Seric ** Side Effects: 5514863Seric ** none. 5524863Seric */ 5534863Seric 5544863Seric endmailer(pid, name) 5554863Seric int pid; 5564863Seric char *name; 5574863Seric { 5584863Seric register int i; 5594863Seric auto int st; 5604863Seric 5616038Seric /* in the IPC case there is nothing to wait for */ 5626038Seric if (pid == 0) 5636038Seric return (EX_OK); 5646038Seric 5656038Seric /* wait for the mailer process to die and collect status */ 5668127Seric do 5678127Seric { 5688127Seric errno = 0; 5698127Seric i = wait(&st); 5708133Seric } while ((i >= 0 && i != pid) || errno == EINTR); 5714863Seric if (i < 0) 5724863Seric { 5734863Seric syserr("wait"); 5744863Seric return (-1); 5754863Seric } 5766038Seric 5776038Seric /* see if it died a horrid death */ 5784863Seric if ((st & 0377) != 0) 5794863Seric { 5804863Seric syserr("%s: stat %o", name, st); 5814863Seric ExitStat = EX_UNAVAILABLE; 5824863Seric return (-1); 5834863Seric } 5846038Seric 5856038Seric /* normal death -- return status */ 5864863Seric i = (st >> 8) & 0377; 5874863Seric return (i); 5884863Seric } 5894863Seric /* 5904863Seric ** OPENMAILER -- open connection to mailer. 5914863Seric ** 5924863Seric ** Parameters: 5934863Seric ** m -- mailer descriptor. 5944863Seric ** pvp -- parameter vector to pass to mailer. 5954863Seric ** ctladdr -- controlling address for user. 5964863Seric ** clever -- create a full duplex connection. 5974863Seric ** pmfile -- pointer to mfile (to mailer) connection. 5984863Seric ** prfile -- pointer to rfile (from mailer) connection. 5994863Seric ** 6004863Seric ** Returns: 6016038Seric ** pid of mailer ( > 0 ). 6024863Seric ** -1 on error. 6036038Seric ** zero on an IPC connection. 6044863Seric ** 6054863Seric ** Side Effects: 6064863Seric ** creates a mailer in a subprocess. 6074863Seric */ 6084863Seric 6094863Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile) 6104863Seric struct mailer *m; 6114863Seric char **pvp; 6124863Seric ADDRESS *ctladdr; 6134863Seric bool clever; 6144863Seric FILE **pmfile; 6154863Seric FILE **prfile; 6164863Seric { 6174863Seric int pid; 6184709Seric int mpvect[2]; 6194863Seric int rpvect[2]; 6203233Seric FILE *mfile; 6214863Seric FILE *rfile; 6223233Seric extern FILE *fdopen(); 6233233Seric 6243233Seric # ifdef DEBUG 6257672Seric if (tTd(11, 1)) 626294Seric { 6278178Seric printf("openmailer:"); 6283233Seric printav(pvp); 629294Seric } 6303233Seric # endif DEBUG 6314488Seric errno = 0; 6323233Seric 6336038Seric # ifdef DAEMON 6346038Seric /* 6356038Seric ** Deal with the special case of mail handled through an IPC 6366038Seric ** connection. 6376038Seric ** In this case we don't actually fork. We must be 6386038Seric ** running SMTP for this to work. We will return a 6396038Seric ** zero pid to indicate that we are running IPC. 6406038Seric */ 6416038Seric 6426038Seric if (strcmp(m->m_mailer, "[IPC]") == 0) 6436038Seric { 6446038Seric register int i; 6457285Seric register u_short port; 6466038Seric 6476038Seric if (!clever) 6486038Seric syserr("non-clever IPC"); 6496632Seric if (pvp[2] != NULL) 6507285Seric port = atoi(pvp[2]); 6516632Seric else 6527285Seric port = 0; 6537285Seric i = makeconnection(pvp[1], port, pmfile, prfile); 6546038Seric if (i != EX_OK) 6556047Seric { 6566047Seric ExitStat = i; 6576038Seric return (-1); 6586047Seric } 6596038Seric else 6606038Seric return (0); 6616038Seric } 6626038Seric # endif DAEMON 6636038Seric 6642898Seric /* create a pipe to shove the mail through */ 6654709Seric if (pipe(mpvect) < 0) 666294Seric { 6674863Seric syserr("pipe (to mailer)"); 668294Seric return (-1); 669294Seric } 6704863Seric 6715179Seric # ifdef SMTP 6724863Seric /* if this mailer speaks smtp, create a return pipe */ 6734863Seric if (clever && pipe(rpvect) < 0) 6744863Seric { 6754863Seric syserr("pipe (from mailer)"); 6764863Seric (void) close(mpvect[0]); 6774863Seric (void) close(mpvect[1]); 6784863Seric return (-1); 6794863Seric } 6805179Seric # endif SMTP 6814863Seric 6826038Seric /* 6836038Seric ** Actually fork the mailer process. 6846038Seric ** DOFORK is clever about retrying. 6856038Seric */ 6866038Seric 6877672Seric (void) fflush(Xscript); /* for debugging */ 6884214Seric DOFORK(XFORK); 6894327Seric /* pid is set by DOFORK */ 690294Seric if (pid < 0) 691294Seric { 6926038Seric /* failure */ 693294Seric syserr("Cannot fork"); 6944709Seric (void) close(mpvect[0]); 6954709Seric (void) close(mpvect[1]); 6964863Seric if (clever) 6974863Seric { 6984863Seric (void) close(rpvect[0]); 6994863Seric (void) close(rpvect[1]); 7004863Seric } 701294Seric return (-1); 702294Seric } 703294Seric else if (pid == 0) 704294Seric { 705294Seric /* child -- set up input & exec mailer */ 7061621Seric /* make diagnostic output be standard output */ 7074477Seric (void) signal(SIGINT, SIG_IGN); 7084477Seric (void) signal(SIGHUP, SIG_IGN); 7094215Seric (void) signal(SIGTERM, SIG_DFL); 7104709Seric 7114709Seric /* arrange to filter standard & diag output of command */ 7124863Seric if (clever) 7134709Seric { 7144863Seric (void) close(rpvect[0]); 7154709Seric (void) close(1); 7164863Seric (void) dup(rpvect[1]); 7174863Seric (void) close(rpvect[1]); 7184863Seric } 7199107Seric else if (Smtp || HoldErrs) 7204863Seric { 7214863Seric (void) close(1); 7229107Seric (void) dup(fileno(Xscript)); 7234709Seric } 7244082Seric (void) close(2); 7254082Seric (void) dup(1); 7264709Seric 7274709Seric /* arrange to get standard input */ 7284709Seric (void) close(mpvect[1]); 7294082Seric (void) close(0); 7304709Seric if (dup(mpvect[0]) < 0) 731294Seric { 7322898Seric syserr("Cannot dup to zero!"); 7332898Seric _exit(EX_OSERR); 734294Seric } 7354709Seric (void) close(mpvect[0]); 7362968Seric if (!bitset(M_RESTR, m->m_flags)) 7374215Seric { 7384417Seric if (ctladdr->q_uid == 0) 7394417Seric { 7404417Seric (void) setgid(DefGid); 7414417Seric (void) setuid(DefUid); 7424417Seric } 7434417Seric else 7444415Seric { 7454417Seric (void) setgid(ctladdr->q_gid); 7464417Seric (void) setuid(ctladdr->q_uid); 7474415Seric } 7484215Seric } 7499148Seric # ifndef VMUNIX 7502774Seric /* 7512774Seric ** We have to be careful with vfork - we can't mung up the 7522774Seric ** memory but we don't want the mailer to inherit any extra 7532774Seric ** open files. Chances are the mailer won't 7542774Seric ** care about an extra file, but then again you never know. 7552774Seric ** Actually, we would like to close(fileno(pwf)), but it's 7562774Seric ** declared static so we can't. But if we fclose(pwf), which 7572774Seric ** is what endpwent does, it closes it in the parent too and 7582774Seric ** the next getpwnam will be slower. If you have a weird 7592774Seric ** mailer that chokes on the extra file you should do the 7609148Seric ** endpwent(). -MRH 7612774Seric ** 7622774Seric ** Similar comments apply to log. However, openlog is 7632774Seric ** clever enough to set the FIOCLEX mode on the file, 7642774Seric ** so it will be closed automatically on the exec. 7652774Seric */ 7662774Seric 7672774Seric endpwent(); 768294Seric # ifdef LOG 7692089Seric closelog(); 770294Seric # endif LOG 7719148Seric # endif VMUNIX 7726038Seric 7736038Seric /* try to execute the mailer */ 774294Seric execv(m->m_mailer, pvp); 7756038Seric 776294Seric /* syserr fails because log is closed */ 777294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 7784214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 7794082Seric (void) fflush(stdout); 7801619Seric _exit(EX_UNAVAILABLE); 781294Seric } 782294Seric 7834709Seric /* 7844863Seric ** Set up return value. 7854709Seric */ 7864709Seric 7874709Seric (void) close(mpvect[0]); 7884709Seric mfile = fdopen(mpvect[1], "w"); 7894863Seric if (clever) 7904863Seric { 7914863Seric (void) close(rpvect[1]); 7924863Seric rfile = fdopen(rpvect[0], "r"); 7934863Seric } 794294Seric 7954863Seric *pmfile = mfile; 7964863Seric *prfile = rfile; 797294Seric 7984863Seric return (pid); 799294Seric } 800294Seric /* 801294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 802294Seric ** 803294Seric ** Parameters: 804294Seric ** stat -- the status code from the mailer (high byte 805294Seric ** only; core dumps must have been taken care of 806294Seric ** already). 807294Seric ** force -- if set, force an error message output, even 808294Seric ** if the mailer seems to like to print its own 809294Seric ** messages. 810294Seric ** m -- the mailer descriptor for this mailer. 811294Seric ** 812294Seric ** Returns: 8134082Seric ** none. 814294Seric ** 815294Seric ** Side Effects: 8161518Seric ** Errors may be incremented. 817294Seric ** ExitStat may be set. 818294Seric */ 819294Seric 820294Seric giveresponse(stat, force, m) 821294Seric int stat; 8227228Seric bool force; 823294Seric register struct mailer *m; 824294Seric { 825294Seric register char *statmsg; 826294Seric extern char *SysExMsg[]; 827294Seric register int i; 828294Seric extern int N_SysEx; 8291624Seric char buf[30]; 830294Seric 8314315Seric /* 8324315Seric ** Compute status message from code. 8334315Seric */ 8344315Seric 835294Seric i = stat - EX__BASE; 836294Seric if (i < 0 || i > N_SysEx) 837294Seric statmsg = NULL; 838294Seric else 839294Seric statmsg = SysExMsg[i]; 840294Seric if (stat == 0) 8414065Seric { 8428003Seric statmsg = "250 sent"; 8438003Seric message(Arpa_Info, &statmsg[4]); 8444065Seric } 8454621Seric else if (stat == EX_TEMPFAIL) 8464621Seric { 8478496Seric message(Arpa_Info, "deferred"); 8484621Seric } 849294Seric else 850294Seric { 8511518Seric Errors++; 8526047Seric FatalErrors = TRUE; 853294Seric if (statmsg == NULL && m->m_badstat != 0) 854294Seric { 855294Seric stat = m->m_badstat; 856294Seric i = stat - EX__BASE; 857294Seric # ifdef DEBUG 858294Seric if (i < 0 || i >= N_SysEx) 859294Seric syserr("Bad m_badstat %d", stat); 860294Seric else 861294Seric # endif DEBUG 8627344Seric statmsg = SysExMsg[i]; 863294Seric } 864294Seric if (statmsg == NULL) 865294Seric usrerr("unknown mailer response %d", stat); 8664065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 8678003Seric usrerr(statmsg); 8687344Seric else 8698003Seric fprintf(Xscript, "%s\n", &statmsg[4]); 870294Seric } 871294Seric 872294Seric /* 873294Seric ** Final cleanup. 874294Seric ** Log a record of the transaction. Compute the new 875294Seric ** ExitStat -- if we already had an error, stick with 876294Seric ** that. 877294Seric */ 878294Seric 8791624Seric if (statmsg == NULL) 8801624Seric { 8818003Seric (void) sprintf(buf, "554 error %d", stat); 8821624Seric statmsg = buf; 8831624Seric } 8841624Seric 8858496Seric /* log it in the system log */ 8867680Seric if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) 8878496Seric logdelivery(&statmsg[4]); 8887858Seric 8898496Seric /* set the exit status appropriately */ 8904621Seric if (stat != EX_TEMPFAIL) 8914621Seric setstat(stat); 892294Seric } 893294Seric /* 8948496Seric ** LOGDELIVERY -- log the delivery in the system log 8958496Seric ** 8968496Seric ** Parameters: 8978496Seric ** stat -- the message to print for the status 8988496Seric ** 8998496Seric ** Returns: 9008496Seric ** none 9018496Seric ** 9028496Seric ** Side Effects: 9038496Seric ** none 9048496Seric */ 9058496Seric 9068496Seric logdelivery(stat) 9078496Seric char *stat; 9088496Seric { 9098496Seric extern char *pintvl(); 9108496Seric 9118496Seric # ifdef LOG 9128496Seric syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, 9138496Seric CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); 9148496Seric # endif LOG 9158496Seric } 9168496Seric /* 9176974Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 918294Seric ** 9196974Seric ** This can be made an arbitrary message separator by changing $l 920294Seric ** 9216974Seric ** One of the ugliest hacks seen by human eyes is 9226974Seric ** contained herein: UUCP wants those stupid 9236974Seric ** "remote from <host>" lines. Why oh why does a 9246974Seric ** well-meaning programmer such as myself have to 9256974Seric ** deal with this kind of antique garbage???? 9266974Seric ** 927294Seric ** Parameters: 9286974Seric ** fp -- the file to output to. 9296974Seric ** m -- the mailer describing this entry. 930294Seric ** 931294Seric ** Returns: 9326974Seric ** none 933294Seric ** 934294Seric ** Side Effects: 9356974Seric ** outputs some text to fp. 936294Seric */ 937294Seric 9386974Seric putfromline(fp, m) 9396974Seric register FILE *fp; 9406974Seric register MAILER *m; 941294Seric { 9426974Seric char buf[MAXLINE]; 943294Seric 9446974Seric if (bitset(M_NHDR, m->m_flags)) 9456974Seric return; 9464315Seric 9476974Seric # ifdef UGLYUUCP 9486974Seric if (bitset(M_UGLYUUCP, m->m_flags)) 9494205Seric { 9506974Seric extern char *macvalue(); 9518178Seric char *sys = macvalue('g', CurEnv); 9526974Seric char *bang = index(sys, '!'); 9536041Seric 9546974Seric if (bang == NULL) 9556974Seric syserr("No ! in UUCP! (%s)", sys); 9565099Seric else 9576974Seric *bang = '\0'; 9587232Seric expand("From $f $d remote from $g\n", buf, 9596974Seric &buf[sizeof buf - 1], CurEnv); 9606974Seric *bang = '!'; 9616974Seric } 9626974Seric else 9635179Seric # endif UGLYUUCP 9646974Seric expand("$l\n", buf, &buf[sizeof buf - 1], CurEnv); 9657123Seric putline(buf, fp, bitset(M_FULLSMTP, m->m_flags)); 9665981Seric } 9675981Seric /* 9686974Seric ** PUTHEADER -- put the header part of a message from the in-core copy 9695981Seric ** 9705981Seric ** Parameters: 9715981Seric ** fp -- file to put it on. 9725981Seric ** m -- mailer to use. 9736974Seric ** e -- envelope to use. 9745981Seric ** 9755981Seric ** Returns: 9765981Seric ** none. 9775981Seric ** 9785981Seric ** Side Effects: 9795981Seric ** none. 9805981Seric */ 9815981Seric 9826974Seric putheader(fp, m, e) 9835981Seric register FILE *fp; 9845981Seric register struct mailer *m; 9856974Seric register ENVELOPE *e; 9865981Seric { 9875981Seric char buf[BUFSIZ]; 9885981Seric register HDR *h; 9895981Seric extern char *arpadate(); 9905981Seric extern char *capitalize(); 9915981Seric extern bool samefrom(); 9927123Seric char obuf[MAXLINE]; 9937123Seric register char *obp; 9947123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 9955981Seric 9968434Seric if (bitset(M_LOCAL, m->m_flags) && fullsmtp) 9978434Seric fprintf(fp, "Return-Path: <%s>\n", e->e_from); 9986974Seric for (h = e->e_header; h != NULL; h = h->h_link) 9991828Seric { 10004315Seric register char *p; 10014315Seric 10023389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 10038062Seric continue; 10044447Seric 10057756Seric p = h->h_value; 10068062Seric if (bitset(H_DEFAULT, h->h_flags)) 10073385Seric { 10087666Seric /* macro expand value if generated internally */ 10098062Seric expand(p, buf, &buf[sizeof buf], e); 10103385Seric p = buf; 10113385Seric } 10124447Seric if (p == NULL || *p == '\0') 10133389Seric continue; 10144209Seric 10158062Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 10164209Seric { 10178062Seric /* address field */ 10188093Seric bool oldstyle = e->e_oldstyle; 10198093Seric 10208093Seric if (bitset(H_FROM, h->h_flags)) 10218093Seric oldstyle = FALSE; 10228093Seric commaize(h, p, fp, oldstyle, m); 10234447Seric } 10248062Seric else 10254447Seric { 10268062Seric /* vanilla header line */ 10277123Seric (void) sprintf(obuf, "%s: %s\n", capitalize(h->h_field), p); 10287123Seric putline(obuf, fp, fullsmtp); 10294209Seric } 10308062Seric h->h_flags |= H_USED; 10312898Seric } 1032294Seric } 1033294Seric /* 10347756Seric ** COMMAIZE -- output a header field, making a comma-translated list. 10357756Seric ** 10367756Seric ** Parameters: 10378062Seric ** h -- the header field to output. 10388062Seric ** p -- the value to put in it. 10397756Seric ** fp -- file to put it to. 10407756Seric ** oldstyle -- TRUE if this is an old style header. 10418235Seric ** m -- a pointer to the mailer descriptor. If NULL, 10428235Seric ** don't transform the name at all. 10437756Seric ** 10447756Seric ** Returns: 10457756Seric ** none. 10467756Seric ** 10477756Seric ** Side Effects: 10487756Seric ** outputs "p" to file "fp". 10497756Seric */ 10507756Seric 10518062Seric commaize(h, p, fp, oldstyle, m) 10528062Seric register HDR *h; 10537756Seric register char *p; 10547756Seric FILE *fp; 10557756Seric bool oldstyle; 10568062Seric register MAILER *m; 10577756Seric { 10588062Seric register char *obp; 10598062Seric int opos; 10608235Seric bool fullsmtp = FALSE; 10617756Seric bool firstone = TRUE; 10627756Seric char obuf[MAXLINE]; 10637756Seric 10647756Seric /* 10657756Seric ** Output the address list translated by the 10667756Seric ** mailer and with commas. 10677756Seric */ 10687756Seric 10697756Seric # ifdef DEBUG 10707756Seric if (tTd(14, 2)) 10718062Seric printf("commaize(%s: %s)\n", h->h_field, p); 10727756Seric # endif DEBUG 10737756Seric 10748235Seric if (m != NULL && bitset(M_FULLSMTP, m->m_flags)) 10758235Seric fullsmtp = TRUE; 10768235Seric 10777756Seric obp = obuf; 10788062Seric (void) sprintf(obp, "%s: ", capitalize(h->h_field)); 10798062Seric opos = strlen(h->h_field) + 2; 10807756Seric obp += opos; 10817756Seric 10827756Seric /* 10837756Seric ** Run through the list of values. 10847756Seric */ 10857756Seric 10867756Seric while (*p != '\0') 10877756Seric { 10887756Seric register char *name; 10897756Seric char savechar; 10908062Seric extern char *remotename(); 10918077Seric extern char *DelimChar; /* defined in prescan */ 10927756Seric 10937756Seric /* 10947756Seric ** Find the end of the name. New style names 10957756Seric ** end with a comma, old style names end with 10967756Seric ** a space character. However, spaces do not 10977756Seric ** necessarily delimit an old-style name -- at 10987756Seric ** signs mean keep going. 10997756Seric */ 11007756Seric 11018077Seric /* find end of name */ 11028077Seric while (isspace(*p) || *p == ',') 11037756Seric p++; 11047756Seric name = p; 11058077Seric for (;;) 11067756Seric { 11078077Seric char *oldp; 11087756Seric extern bool isatword(); 11097756Seric 11108091Seric (void) prescan(p, oldstyle ? ' ' : ','); 11118077Seric p = DelimChar; 11127756Seric 11137756Seric /* look to see if we have an at sign */ 11147756Seric oldp = p; 11157756Seric while (*p != '\0' && isspace(*p)) 11167756Seric p++; 11177756Seric 11187756Seric if (*p != '@' && !isatword(p)) 11197756Seric { 11207756Seric p = oldp; 11217756Seric break; 11227756Seric } 11237756Seric p += *p == '@' ? 1 : 2; 11247756Seric while (*p != '\0' && isspace(*p)) 11257756Seric p++; 11267756Seric } 11277756Seric /* at the end of one complete name */ 11287756Seric 11297756Seric /* strip off trailing white space */ 11307756Seric while (p >= name && (isspace(*p) || *p == ',' || *p == '\0')) 11317756Seric p--; 11327756Seric if (++p == name) 11337756Seric continue; 11347756Seric savechar = *p; 11357756Seric *p = '\0'; 11367756Seric 11377756Seric /* translate the name to be relative */ 11388235Seric if (m != NULL) 11398235Seric name = remotename(name, m, bitset(H_FROM, h->h_flags)); 11407756Seric if (*name == '\0') 11417756Seric { 11427756Seric *p = savechar; 11437756Seric continue; 11447756Seric } 11457756Seric 11467756Seric /* output the name with nice formatting */ 11479040Seric opos += qstrlen(name); 11487756Seric if (!firstone) 11497756Seric opos += 2; 11507756Seric if (opos > 78 && !firstone) 11517756Seric { 11527756Seric (void) sprintf(obp, ",\n"); 11537756Seric putline(obuf, fp, fullsmtp); 11547756Seric obp = obuf; 11557756Seric (void) sprintf(obp, " "); 11567756Seric obp += strlen(obp); 11577756Seric opos = 8 + strlen(name); 11587756Seric } 11597756Seric else if (!firstone) 11607756Seric { 11617756Seric (void) sprintf(obp, ", "); 11627756Seric obp += 2; 11637756Seric } 11649040Seric 11659040Seric /* strip off quote bits as we output */ 11669040Seric while (*name != '\0') 11679040Seric { 11689040Seric if (bitset(0200, *name)) 11699040Seric *obp++ = '\\'; 11709040Seric *obp++ = *name++ & ~0200; 11719040Seric } 11727756Seric firstone = FALSE; 11737756Seric *p = savechar; 11747756Seric } 11757756Seric (void) strcpy(obp, "\n"); 11767756Seric putline(obuf, fp, fullsmtp); 11777756Seric } 11787756Seric /* 11796974Seric ** PUTBODY -- put the body of a message. 11806974Seric ** 11816974Seric ** Parameters: 11826974Seric ** fp -- file to output onto. 11836974Seric ** m -- a mailer descriptor. 11846974Seric ** xdot -- if set, use SMTP hidden dot algorithm. 11856974Seric ** 11866974Seric ** Returns: 11876974Seric ** none. 11886974Seric ** 11896974Seric ** Side Effects: 11906974Seric ** The message is written onto fp. 11916974Seric */ 11926974Seric 11936974Seric putbody(fp, m, xdot) 11946974Seric FILE *fp; 11956974Seric struct mailer *m; 11966974Seric bool xdot; 11976974Seric { 11986974Seric char buf[MAXLINE + 1]; 11997123Seric bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); 12006974Seric 12016974Seric /* 12026974Seric ** Output the body of the message 12036974Seric */ 12046974Seric 12057003Seric #ifdef lint 12067003Seric /* m will be needed later for complete smtp emulation */ 12077003Seric if (m == NULL) 12087003Seric return; 12097003Seric #endif lint 12107003Seric 12116974Seric if (TempFile != NULL) 12126974Seric { 12136974Seric rewind(TempFile); 12146974Seric buf[0] = '.'; 12156974Seric while (!ferror(fp) && fgets(&buf[1], sizeof buf - 1, TempFile) != NULL) 12167123Seric putline((xdot && buf[1] == '.') ? buf : &buf[1], fp, fullsmtp); 12176974Seric 12186974Seric if (ferror(TempFile)) 12196974Seric { 12206974Seric syserr("putbody: read error"); 12216974Seric ExitStat = EX_IOERR; 12226974Seric } 12236974Seric } 12246974Seric 12256974Seric (void) fflush(fp); 12266974Seric if (ferror(fp) && errno != EPIPE) 12276974Seric { 12286974Seric syserr("putbody: write error"); 12296974Seric ExitStat = EX_IOERR; 12306974Seric } 12316974Seric errno = 0; 12326974Seric } 12336974Seric /* 12345936Seric ** ISATWORD -- tell if the word we are pointing to is "at". 12355936Seric ** 12365936Seric ** Parameters: 12375936Seric ** p -- word to check. 12385936Seric ** 12395936Seric ** Returns: 12405936Seric ** TRUE -- if p is the word at. 12415936Seric ** FALSE -- otherwise. 12425936Seric ** 12435936Seric ** Side Effects: 12445936Seric ** none. 12455936Seric */ 12465936Seric 12475936Seric bool 12485936Seric isatword(p) 12495936Seric register char *p; 12505936Seric { 12515936Seric extern char lower(); 12525936Seric 12535936Seric if (lower(p[0]) == 'a' && lower(p[1]) == 't' && 12545936Seric p[2] != '\0' && isspace(p[2])) 12555936Seric return (TRUE); 12565936Seric return (FALSE); 12575936Seric } 12585936Seric /* 12594370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 12604370Seric ** 12614370Seric ** Parameters: 12624370Seric ** ifrom -- internally generated form of from address. 12634370Seric ** efrom -- external form of from address. 12644370Seric ** 12654370Seric ** Returns: 12664370Seric ** TRUE -- if they convey the same info. 12674370Seric ** FALSE -- if any information has been lost. 12684370Seric ** 12694370Seric ** Side Effects: 12704370Seric ** none. 12714370Seric */ 12724370Seric 12734370Seric bool 12744370Seric samefrom(ifrom, efrom) 12754370Seric char *ifrom; 12764370Seric char *efrom; 12774370Seric { 12784447Seric register char *p; 12794447Seric char buf[MAXNAME + 4]; 12804447Seric 12814447Seric # ifdef DEBUG 12827672Seric if (tTd(3, 8)) 12834447Seric printf("samefrom(%s,%s)-->", ifrom, efrom); 12844447Seric # endif DEBUG 12854447Seric if (strcmp(ifrom, efrom) == 0) 12864447Seric goto success; 12874447Seric p = index(ifrom, '@'); 12884447Seric if (p == NULL) 12894447Seric goto failure; 12904447Seric *p = '\0'; 12917003Seric (void) strcpy(buf, ifrom); 12927003Seric (void) strcat(buf, " at "); 12934447Seric *p++ = '@'; 12947003Seric (void) strcat(buf, p); 12954447Seric if (strcmp(buf, efrom) == 0) 12964447Seric goto success; 12974447Seric 12984447Seric failure: 12994447Seric # ifdef DEBUG 13007672Seric if (tTd(3, 8)) 13014447Seric printf("FALSE\n"); 13024447Seric # endif DEBUG 13034447Seric return (FALSE); 13044447Seric 13054447Seric success: 13064447Seric # ifdef DEBUG 13077672Seric if (tTd(3, 8)) 13084447Seric printf("TRUE\n"); 13094447Seric # endif DEBUG 13104447Seric return (TRUE); 13114370Seric } 13124370Seric /* 1313294Seric ** MAILFILE -- Send a message to a file. 1314294Seric ** 13154327Seric ** If the file has the setuid/setgid bits set, but NO execute 13164327Seric ** bits, sendmail will try to become the owner of that file 13174327Seric ** rather than the real user. Obviously, this only works if 13184327Seric ** sendmail runs as root. 13194327Seric ** 1320294Seric ** Parameters: 1321294Seric ** filename -- the name of the file to send to. 13224397Seric ** ctladdr -- the controlling address header -- includes 13234397Seric ** the userid/groupid to be when sending. 1324294Seric ** 1325294Seric ** Returns: 1326294Seric ** The exit code associated with the operation. 1327294Seric ** 1328294Seric ** Side Effects: 1329294Seric ** none. 1330294Seric */ 1331294Seric 13324397Seric mailfile(filename, ctladdr) 1333294Seric char *filename; 13344397Seric ADDRESS *ctladdr; 1335294Seric { 1336294Seric register FILE *f; 13374214Seric register int pid; 1338294Seric 13394214Seric /* 13404214Seric ** Fork so we can change permissions here. 13414214Seric ** Note that we MUST use fork, not vfork, because of 13424214Seric ** the complications of calling subroutines, etc. 13434214Seric */ 13444067Seric 13454214Seric DOFORK(fork); 13464214Seric 13474214Seric if (pid < 0) 13484214Seric return (EX_OSERR); 13494214Seric else if (pid == 0) 13504214Seric { 13514214Seric /* child -- actually write to file */ 13524327Seric struct stat stb; 13534327Seric 13544215Seric (void) signal(SIGINT, SIG_DFL); 13554215Seric (void) signal(SIGHUP, SIG_DFL); 13564215Seric (void) signal(SIGTERM, SIG_DFL); 13574327Seric umask(OldUmask); 13584327Seric if (stat(filename, &stb) < 0) 13594431Seric stb.st_mode = 0666; 13604327Seric if (bitset(0111, stb.st_mode)) 13614327Seric exit(EX_CANTCREAT); 13624401Seric if (ctladdr == NULL) 13636900Seric ctladdr = &CurEnv->e_from; 13644327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 13654417Seric { 13664417Seric if (ctladdr->q_uid == 0) 13674417Seric (void) setgid(DefGid); 13684417Seric else 13694417Seric (void) setgid(ctladdr->q_gid); 13704417Seric } 13714327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 13724417Seric { 13734417Seric if (ctladdr->q_uid == 0) 13744417Seric (void) setuid(DefUid); 13754417Seric else 13764417Seric (void) setuid(ctladdr->q_uid); 13774417Seric } 13786887Seric f = dfopen(filename, "a"); 13794214Seric if (f == NULL) 13804214Seric exit(EX_CANTCREAT); 13814214Seric 13826974Seric putfromline(f, Mailer[1]); 13836974Seric (*CurEnv->e_puthdr)(f, Mailer[1], CurEnv); 13847123Seric fputs("\n", f); 13856974Seric (*CurEnv->e_putbody)(f, Mailer[1], FALSE); 13864214Seric fputs("\n", f); 13874214Seric (void) fclose(f); 13884214Seric (void) fflush(stdout); 13894417Seric 13906887Seric /* reset ISUID & ISGID bits for paranoid systems */ 13914621Seric (void) chmod(filename, (int) stb.st_mode); 13924214Seric exit(EX_OK); 13934315Seric /*NOTREACHED*/ 13944214Seric } 13954214Seric else 13964214Seric { 13974214Seric /* parent -- wait for exit status */ 13984214Seric register int i; 13994214Seric auto int stat; 14004214Seric 14014214Seric while ((i = wait(&stat)) != pid) 14024214Seric { 14034214Seric if (i < 0) 14044214Seric { 14054214Seric stat = EX_OSERR << 8; 14064214Seric break; 14074214Seric } 14084214Seric } 14094215Seric if ((stat & 0377) != 0) 14104215Seric stat = EX_UNAVAILABLE << 8; 14114214Seric return ((stat >> 8) & 0377); 14124214Seric } 1413294Seric } 14144550Seric /* 14154550Seric ** SENDALL -- actually send all the messages. 14164550Seric ** 14174550Seric ** Parameters: 14187043Seric ** e -- the envelope to send. 14194550Seric ** verifyonly -- if set, only give verification messages. 14204550Seric ** 14214550Seric ** Returns: 14224550Seric ** none. 14234550Seric ** 14244550Seric ** Side Effects: 14254550Seric ** Scans the send lists and sends everything it finds. 14267043Seric ** Delivers any appropriate error messages. 14274550Seric */ 14284550Seric 14297043Seric sendall(e, verifyonly) 14307043Seric ENVELOPE *e; 14314550Seric bool verifyonly; 14324550Seric { 14335008Seric register ADDRESS *q; 14347779Seric bool oldverbose; 14354550Seric 14365032Seric # ifdef DEBUG 14378248Seric if (tTd(13, 1)) 14385032Seric { 14398542Seric printf("\nSENDALL: verify %d, sendqueue:\n", verifyonly); 14407043Seric printaddr(e->e_sendqueue, TRUE); 14415032Seric } 14425032Seric # endif DEBUG 14435008Seric 14447043Seric /* 14457043Seric ** Run through the list and send everything. 14467043Seric */ 14477043Seric 14487779Seric oldverbose = Verbose; 14497779Seric if (verifyonly) 14507779Seric Verbose = TRUE; 14517043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14524550Seric { 14535008Seric if (verifyonly) 14544550Seric { 14556900Seric CurEnv->e_to = q->q_paddr; 14565008Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 14577052Seric message(Arpa_Info, "deliverable"); 14584550Seric } 14595008Seric else 14606974Seric (void) deliver(q); 14614550Seric } 14627779Seric Verbose = oldverbose; 14637043Seric 14647043Seric /* 14657043Seric ** Now run through and check for errors. 14667043Seric */ 14677043Seric 14687043Seric if (verifyonly) 14697043Seric return; 14707043Seric 14717043Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 14727043Seric { 14737043Seric register ADDRESS *qq; 14747043Seric 14758248Seric # ifdef DEBUG 14768248Seric if (tTd(13, 3)) 14778248Seric { 14788248Seric printf("Checking "); 14798248Seric printaddr(q, FALSE); 14808248Seric } 14818248Seric # endif DEBUG 14828248Seric 14837043Seric if (bitset(QQUEUEUP, q->q_flags)) 14847043Seric e->e_queueup = TRUE; 14857043Seric 14867043Seric /* we have an address that failed -- find the parent */ 14877043Seric for (qq = q; qq != NULL; qq = qq->q_alias) 14887043Seric { 14897043Seric char obuf[MAXNAME + 6]; 14907043Seric extern char *aliaslookup(); 14917043Seric 14927043Seric /* we can only have owners for local addresses */ 14937043Seric if (!bitset(M_LOCAL, qq->q_mailer->m_flags)) 14947043Seric continue; 14957043Seric 14967043Seric /* see if the owner list exists */ 14977043Seric (void) strcpy(obuf, "owner-"); 14987047Seric if (strncmp(qq->q_user, "owner-", 6) == 0) 14997047Seric (void) strcat(obuf, "owner"); 15007047Seric else 15017047Seric (void) strcat(obuf, qq->q_user); 15027043Seric if (aliaslookup(obuf) == NULL) 15037043Seric continue; 15047043Seric 15058248Seric # ifdef DEBUG 15068248Seric if (tTd(13, 4)) 15078248Seric printf("Errors to %s\n", obuf); 15088248Seric # endif DEBUG 15098248Seric 15108248Seric /* add in an errors-to field */ 15118248Seric /* ugh... must happen before delivery..... 15128248Seric addheader("errors-to", newstr(obuf), e); 15138248Seric .... i guess this should go in sendto */ 15148248Seric 15158248Seric /* only send errors if the message failed */ 15168248Seric if (!bitset(QBADADDR, q->q_flags)) 15178248Seric break; 15188248Seric 15197043Seric /* owner list exists -- add it to the error queue */ 15207043Seric qq->q_flags &= ~QPRIMARY; 15218077Seric sendto(obuf, qq, &e->e_errorqueue); 15227043Seric MailBack = TRUE; 15237043Seric break; 15247043Seric } 15257043Seric 15267043Seric /* if we did not find an owner, send to the sender */ 15278426Seric if (qq == NULL && bitset(QBADADDR, q->q_flags)) 15288077Seric sendto(e->e_from.q_paddr, qq, &e->e_errorqueue); 15297043Seric } 15304550Seric } 15317043Seric /* 15327043Seric ** CHECKERRORS -- check a queue of addresses and process errors. 15337043Seric ** 15347043Seric ** Parameters: 15357043Seric ** e -- the envelope to check. 15367043Seric ** 15377043Seric ** Returns: 15387043Seric ** none. 15397043Seric ** 15407043Seric ** Side Effects: 15417043Seric ** Arranges to queue all tempfailed messages in q 15427043Seric ** or deliver error responses. 15437043Seric */ 15447043Seric 15457043Seric checkerrors(e) 15467043Seric register ENVELOPE *e; 15477043Seric { 15487808Seric register ADDRESS *q; 15497808Seric 15507043Seric # ifdef DEBUG 15517672Seric if (tTd(4, 1)) 15527043Seric { 15537371Seric printf("\ncheckerrors: FatalErrors %d, errorqueue:\n"); 15547043Seric printaddr(e->e_errorqueue, TRUE); 15557043Seric } 15567043Seric # endif DEBUG 15577043Seric 15587043Seric /* mail back the transcript on errors */ 15597043Seric if (FatalErrors) 15607043Seric savemail(); 15617043Seric 15627043Seric /* queue up anything laying around */ 15637858Seric if (e->e_dontqueue) 15647858Seric return; 15657808Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 15667043Seric { 15677808Seric if (bitset(QQUEUEUP, q->q_flags)) 15687808Seric { 15697043Seric # ifdef QUEUE 15707808Seric queueup(e, FALSE); 15718262Seric e->e_df = e->e_qf = NULL; 15728262Seric e->e_dontqueue = TRUE; 15737043Seric # else QUEUE 15747808Seric syserr("checkerrors: trying to queue %s", e->e_df); 15757043Seric # endif QUEUE 15767808Seric break; 15777808Seric } 15787043Seric } 15797043Seric } 1580