Annotation of 43BSDReno/usr.sbin/sendmail/src/deliver.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1983 Eric P. Allman
        !             3:  * Copyright (c) 1988 Regents of the University of California.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms are permitted provided
        !             7:  * that: (1) source distributions retain this entire copyright notice and
        !             8:  * comment, and (2) distributions including binaries display the following
        !             9:  * acknowledgement:  ``This product includes software developed by the
        !            10:  * University of California, Berkeley and its contributors'' in the
        !            11:  * documentation or other materials provided with the distribution and in
        !            12:  * all advertising materials mentioning features or use of this software.
        !            13:  * Neither the name of the University nor the names of its contributors may
        !            14:  * be used to endorse or promote products derived from this software without
        !            15:  * specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  */
        !            20: 
        !            21: #ifndef lint
        !            22: static char sccsid[] = "@(#)deliver.c  5.38 (Berkeley) 6/1/90";
        !            23: #endif /* not lint */
        !            24: 
        !            25: #include "sendmail.h"
        !            26: #include <sys/signal.h>
        !            27: #include <sys/stat.h>
        !            28: #include <netdb.h>
        !            29: #include <fcntl.h>
        !            30: #include <errno.h>
        !            31: #ifdef NAMED_BIND
        !            32: #include <arpa/nameser.h>
        !            33: #include <resolv.h>
        !            34: #endif
        !            35: 
        !            36: /*
        !            37: **  DELIVER -- Deliver a message to a list of addresses.
        !            38: **
        !            39: **     This routine delivers to everyone on the same host as the
        !            40: **     user on the head of the list.  It is clever about mailers
        !            41: **     that don't handle multiple users.  It is NOT guaranteed
        !            42: **     that it will deliver to all these addresses however -- so
        !            43: **     deliver should be called once for each address on the
        !            44: **     list.
        !            45: **
        !            46: **     Parameters:
        !            47: **             e -- the envelope to deliver.
        !            48: **             firstto -- head of the address list to deliver to.
        !            49: **
        !            50: **     Returns:
        !            51: **             zero -- successfully delivered.
        !            52: **             else -- some failure, see ExitStat for more info.
        !            53: **
        !            54: **     Side Effects:
        !            55: **             The standard input is passed off to someone.
        !            56: */
        !            57: 
        !            58: deliver(e, firstto)
        !            59:        register ENVELOPE *e;
        !            60:        ADDRESS *firstto;
        !            61: {
        !            62:        char *host;                     /* host being sent to */
        !            63:        char *user;                     /* user being sent to */
        !            64:        char **pvp;
        !            65:        register char **mvp;
        !            66:        register char *p;
        !            67:        register MAILER *m;             /* mailer for this recipient */
        !            68:        ADDRESS *ctladdr;
        !            69:        register ADDRESS *to = firstto;
        !            70:        bool clever = FALSE;            /* running user smtp to this mailer */
        !            71:        ADDRESS *tochain = NULL;        /* chain of users in this mailer call */
        !            72:        int rcode;              /* response code */
        !            73:        char *pv[MAXPV+1];
        !            74:        char tobuf[MAXLINE-50];         /* text line of to people */
        !            75:        char buf[MAXNAME];
        !            76:        char tfrombuf[MAXNAME];         /* translated from person */
        !            77:        extern bool checkcompat();
        !            78:        extern ADDRESS *getctladdr();
        !            79:        extern char *remotename();
        !            80: 
        !            81:        errno = 0;
        !            82:        if (bitset(QDONTSEND, to->q_flags))
        !            83:                return (0);
        !            84: 
        !            85: #ifdef NAMED_BIND
        !            86:        /* unless interactive, try twice, over a minute */
        !            87:        if (OpMode == MD_DAEMON || OpMode == MD_SMTP) {
        !            88:                _res.retrans = 30;
        !            89:                _res.retry = 2;
        !            90:        }
        !            91: #endif 
        !            92: 
        !            93:        m = to->q_mailer;
        !            94:        host = to->q_host;
        !            95: 
        !            96:        if (tTd(10, 1))
        !            97:                printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
        !            98:                        m->m_mno, host, to->q_user);
        !            99: 
        !           100:        /*
        !           101:        **  If this mailer is expensive, and if we don't want to make
        !           102:        **  connections now, just mark these addresses and return.
        !           103:        **      This is useful if we want to batch connections to
        !           104:        **      reduce load.  This will cause the messages to be
        !           105:        **      queued up, and a daemon will come along to send the
        !           106:        **      messages later.
        !           107:        **              This should be on a per-mailer basis.
        !           108:        */
        !           109: 
        !           110:        if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) &&
        !           111:            !Verbose)
        !           112:        {
        !           113:                for (; to != NULL; to = to->q_next)
        !           114:                {
        !           115:                        if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m)
        !           116:                                continue;
        !           117:                        to->q_flags |= QQUEUEUP|QDONTSEND;
        !           118:                        e->e_to = to->q_paddr;
        !           119:                        message(Arpa_Info, "queued");
        !           120:                        if (LogLevel > 4)
        !           121:                                logdelivery("queued");
        !           122:                }
        !           123:                e->e_to = NULL;
        !           124:                return (0);
        !           125:        }
        !           126: 
        !           127:        /*
        !           128:        **  Do initial argv setup.
        !           129:        **      Insert the mailer name.  Notice that $x expansion is
        !           130:        **      NOT done on the mailer name.  Then, if the mailer has
        !           131:        **      a picky -f flag, we insert it as appropriate.  This
        !           132:        **      code does not check for 'pv' overflow; this places a
        !           133:        **      manifest lower limit of 4 for MAXPV.
        !           134:        **              The from address rewrite is expected to make
        !           135:        **              the address relative to the other end.
        !           136:        */
        !           137: 
        !           138:        /* rewrite from address, using rewriting rules */
        !           139:        expand("\001f", buf, &buf[sizeof buf - 1], e);
        !           140:        (void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE));
        !           141: 
        !           142:        define('g', tfrombuf, e);               /* translated sender address */
        !           143:        define('h', host, e);                   /* to host */
        !           144:        Errors = 0;
        !           145:        pvp = pv;
        !           146:        *pvp++ = m->m_argv[0];
        !           147: 
        !           148:        /* insert -f or -r flag as appropriate */
        !           149:        if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))
        !           150:        {
        !           151:                if (bitnset(M_FOPT, m->m_flags))
        !           152:                        *pvp++ = "-f";
        !           153:                else
        !           154:                        *pvp++ = "-r";
        !           155:                expand("\001g", buf, &buf[sizeof buf - 1], e);
        !           156:                *pvp++ = newstr(buf);
        !           157:        }
        !           158: 
        !           159:        /*
        !           160:        **  Append the other fixed parts of the argv.  These run
        !           161:        **  up to the first entry containing "$u".  There can only
        !           162:        **  be one of these, and there are only a few more slots
        !           163:        **  in the pv after it.
        !           164:        */
        !           165: 
        !           166:        for (mvp = m->m_argv; (p = *++mvp) != NULL; )
        !           167:        {
        !           168:                while ((p = index(p, '\001')) != NULL)
        !           169:                        if (*++p == 'u')
        !           170:                                break;
        !           171:                if (p != NULL)
        !           172:                        break;
        !           173: 
        !           174:                /* this entry is safe -- go ahead and process it */
        !           175:                expand(*mvp, buf, &buf[sizeof buf - 1], e);
        !           176:                *pvp++ = newstr(buf);
        !           177:                if (pvp >= &pv[MAXPV - 3])
        !           178:                {
        !           179:                        syserr("Too many parameters to %s before $u", pv[0]);
        !           180:                        return (-1);
        !           181:                }
        !           182:        }
        !           183: 
        !           184:        /*
        !           185:        **  If we have no substitution for the user name in the argument
        !           186:        **  list, we know that we must supply the names otherwise -- and
        !           187:        **  SMTP is the answer!!
        !           188:        */
        !           189: 
        !           190:        if (*mvp == NULL)
        !           191:        {
        !           192:                /* running SMTP */
        !           193: # ifdef SMTP
        !           194:                clever = TRUE;
        !           195:                *pvp = NULL;
        !           196: # else SMTP
        !           197:                /* oops!  we don't implement SMTP */
        !           198:                syserr("SMTP style mailer");
        !           199:                return (EX_SOFTWARE);
        !           200: # endif SMTP
        !           201:        }
        !           202: 
        !           203:        /*
        !           204:        **  At this point *mvp points to the argument with $u.  We
        !           205:        **  run through our address list and append all the addresses
        !           206:        **  we can.  If we run out of space, do not fret!  We can
        !           207:        **  always send another copy later.
        !           208:        */
        !           209: 
        !           210:        tobuf[0] = '\0';
        !           211:        e->e_to = tobuf;
        !           212:        ctladdr = NULL;
        !           213:        for (; to != NULL; to = to->q_next)
        !           214:        {
        !           215:                /* avoid sending multiple recipients to dumb mailers */
        !           216:                if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
        !           217:                        break;
        !           218: 
        !           219:                /* if already sent or not for this host, don't send */
        !           220:                if (bitset(QDONTSEND, to->q_flags) ||
        !           221:                    strcmp(to->q_host, host) != 0 ||
        !           222:                    to->q_mailer != firstto->q_mailer)
        !           223:                        continue;
        !           224: 
        !           225:                /* avoid overflowing tobuf */
        !           226:                if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2))
        !           227:                        break;
        !           228: 
        !           229:                if (tTd(10, 1))
        !           230:                {
        !           231:                        printf("\nsend to ");
        !           232:                        printaddr(to, FALSE);
        !           233:                }
        !           234: 
        !           235:                /* compute effective uid/gid when sending */
        !           236:                if (to->q_mailer == ProgMailer)
        !           237:                        ctladdr = getctladdr(to);
        !           238: 
        !           239:                user = to->q_user;
        !           240:                e->e_to = to->q_paddr;
        !           241:                to->q_flags |= QDONTSEND;
        !           242: 
        !           243:                /*
        !           244:                **  Check to see that these people are allowed to
        !           245:                **  talk to each other.
        !           246:                */
        !           247: 
        !           248:                if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
        !           249:                {
        !           250:                        NoReturn = TRUE;
        !           251:                        usrerr("Message is too large; %ld bytes max", m->m_maxsize);
        !           252:                        giveresponse(EX_UNAVAILABLE, m, e);
        !           253:                        continue;
        !           254:                }
        !           255:                if (!checkcompat(to))
        !           256:                {
        !           257:                        giveresponse(EX_UNAVAILABLE, m, e);
        !           258:                        continue;
        !           259:                }
        !           260: 
        !           261:                /*
        !           262:                **  Strip quote bits from names if the mailer is dumb
        !           263:                **      about them.
        !           264:                */
        !           265: 
        !           266:                if (bitnset(M_STRIPQ, m->m_flags))
        !           267:                {
        !           268:                        stripquotes(user, TRUE);
        !           269:                        stripquotes(host, TRUE);
        !           270:                }
        !           271:                else
        !           272:                {
        !           273:                        stripquotes(user, FALSE);
        !           274:                        stripquotes(host, FALSE);
        !           275:                }
        !           276: 
        !           277:                /* hack attack -- delivermail compatibility */
        !           278:                if (m == ProgMailer && *user == '|')
        !           279:                        user++;
        !           280: 
        !           281:                /*
        !           282:                **  If an error message has already been given, don't
        !           283:                **      bother to send to this address.
        !           284:                **
        !           285:                **      >>>>>>>>>> This clause assumes that the local mailer
        !           286:                **      >> NOTE >> cannot do any further aliasing; that
        !           287:                **      >>>>>>>>>> function is subsumed by sendmail.
        !           288:                */
        !           289: 
        !           290:                if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
        !           291:                        continue;
        !           292: 
        !           293:                /* save statistics.... */
        !           294:                markstats(e, to);
        !           295: 
        !           296:                /*
        !           297:                **  See if this user name is "special".
        !           298:                **      If the user name has a slash in it, assume that this
        !           299:                **      is a file -- send it off without further ado.  Note
        !           300:                **      that this type of addresses is not processed along
        !           301:                **      with the others, so we fudge on the To person.
        !           302:                */
        !           303: 
        !           304:                if (m == LocalMailer)
        !           305:                {
        !           306:                        if (user[0] == '/')
        !           307:                        {
        !           308:                                rcode = mailfile(user, getctladdr(to));
        !           309:                                giveresponse(rcode, m, e);
        !           310:                                continue;
        !           311:                        }
        !           312:                }
        !           313: 
        !           314:                /*
        !           315:                **  Address is verified -- add this user to mailer
        !           316:                **  argv, and add it to the print list of recipients.
        !           317:                */
        !           318: 
        !           319:                /* link together the chain of recipients */
        !           320:                to->q_tchain = tochain;
        !           321:                tochain = to;
        !           322: 
        !           323:                /* create list of users for error messages */
        !           324:                (void) strcat(tobuf, ",");
        !           325:                (void) strcat(tobuf, to->q_paddr);
        !           326:                define('u', user, e);           /* to user */
        !           327:                define('z', to->q_home, e);     /* user's home */
        !           328: 
        !           329:                /*
        !           330:                **  Expand out this user into argument list.
        !           331:                */
        !           332: 
        !           333:                if (!clever)
        !           334:                {
        !           335:                        expand(*mvp, buf, &buf[sizeof buf - 1], e);
        !           336:                        *pvp++ = newstr(buf);
        !           337:                        if (pvp >= &pv[MAXPV - 2])
        !           338:                        {
        !           339:                                /* allow some space for trailing parms */
        !           340:                                break;
        !           341:                        }
        !           342:                }
        !           343:        }
        !           344: 
        !           345:        /* see if any addresses still exist */
        !           346:        if (tobuf[0] == '\0')
        !           347:        {
        !           348:                define('g', (char *) NULL, e);
        !           349:                return (0);
        !           350:        }
        !           351: 
        !           352:        /* print out messages as full list */
        !           353:        e->e_to = tobuf + 1;
        !           354: 
        !           355:        /*
        !           356:        **  Fill out any parameters after the $u parameter.
        !           357:        */
        !           358: 
        !           359:        while (!clever && *++mvp != NULL)
        !           360:        {
        !           361:                expand(*mvp, buf, &buf[sizeof buf - 1], e);
        !           362:                *pvp++ = newstr(buf);
        !           363:                if (pvp >= &pv[MAXPV])
        !           364:                        syserr("deliver: pv overflow after $u for %s", pv[0]);
        !           365:        }
        !           366:        *pvp++ = NULL;
        !           367: 
        !           368:        /*
        !           369:        **  Call the mailer.
        !           370:        **      The argument vector gets built, pipes
        !           371:        **      are created as necessary, and we fork & exec as
        !           372:        **      appropriate.
        !           373:        **      If we are running SMTP, we just need to clean up.
        !           374:        */
        !           375: 
        !           376:        if (ctladdr == NULL)
        !           377:                ctladdr = &e->e_from;
        !           378: #ifdef NAMED_BIND
        !           379:        _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);           /* XXX */
        !           380: #endif
        !           381: #ifdef SMTP
        !           382:        if (clever)
        !           383:        {
        !           384:                rcode = EX_OK;
        !           385: #ifdef NAMED_BIND
        !           386:                if (host[0] && host[0] != '[')
        !           387:                {
        !           388:                        expand("\001w", buf, &buf[sizeof(buf) - 1], e);
        !           389:                        Nmx = getmxrr(host, MxHosts, buf, &rcode);
        !           390:                }
        !           391:                else
        !           392: #endif
        !           393:                {
        !           394:                        Nmx = 1;
        !           395:                        MxHosts[0] = host;
        !           396:                }
        !           397:                if (Nmx >= 0)
        !           398:                {
        !           399:                        message(Arpa_Info, "Connecting to %s (%s)...",
        !           400:                            MxHosts[0], m->m_name);
        !           401:                        if ((rcode = smtpinit(m, pv)) == EX_OK) {
        !           402:                                register char *t = tobuf;
        !           403:                                register int i;
        !           404: 
        !           405:                                /* send the recipient list */
        !           406:                                tobuf[0] = '\0';
        !           407:                                for (to = tochain; to; to = to->q_tchain) {
        !           408:                                        e->e_to = to->q_paddr;
        !           409:                                        if ((i = smtprcpt(to, m)) != EX_OK) {
        !           410:                                                markfailure(e, to, i);
        !           411:                                                giveresponse(i, m, e);
        !           412:                                        }
        !           413:                                        else {
        !           414:                                                *t++ = ',';
        !           415:                                                for (p = to->q_paddr; *p; *t++ = *p++);
        !           416:                                        }
        !           417:                                }
        !           418: 
        !           419:                                /* now send the data */
        !           420:                                if (tobuf[0] == '\0')
        !           421:                                        e->e_to = NULL;
        !           422:                                else {
        !           423:                                        e->e_to = tobuf + 1;
        !           424:                                        rcode = smtpdata(m, e);
        !           425:                                }
        !           426: 
        !           427:                                /* now close the connection */
        !           428:                                smtpquit(m);
        !           429:                        }
        !           430:                }
        !           431:        }
        !           432:        else
        !           433: #endif /* SMTP */
        !           434:        {
        !           435:                message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name);
        !           436:                rcode = sendoff(e, m, pv, ctladdr);
        !           437:        }
        !           438: #ifdef NAMED_BIND
        !           439:        _res.options |= RES_DEFNAMES | RES_DNSRCH;      /* XXX */
        !           440: #endif
        !           441: 
        !           442:        /*
        !           443:        **  Do final status disposal.
        !           444:        **      We check for something in tobuf for the SMTP case.
        !           445:        **      If we got a temporary failure, arrange to queue the
        !           446:        **              addressees.
        !           447:        */
        !           448: 
        !           449:        if (tobuf[0] != '\0')
        !           450:                giveresponse(rcode, m, e);
        !           451:        if (rcode != EX_OK)
        !           452:                for (to = tochain; to != NULL; to = to->q_tchain)
        !           453:                        markfailure(e, to, rcode);
        !           454: 
        !           455:        errno = 0;
        !           456:        define('g', (char *) NULL, e);
        !           457:        return (rcode);
        !           458: }
        !           459: /*
        !           460: **  MARKFAILURE -- mark a failure on a specific address.
        !           461: **
        !           462: **     Parameters:
        !           463: **             e -- the envelope we are sending.
        !           464: **             q -- the address to mark.
        !           465: **             rcode -- the code signifying the particular failure.
        !           466: **
        !           467: **     Returns:
        !           468: **             none.
        !           469: **
        !           470: **     Side Effects:
        !           471: **             marks the address (and possibly the envelope) with the
        !           472: **                     failure so that an error will be returned or
        !           473: **                     the message will be queued, as appropriate.
        !           474: */
        !           475: 
        !           476: markfailure(e, q, rcode)
        !           477:        register ENVELOPE *e;
        !           478:        register ADDRESS *q;
        !           479:        int rcode;
        !           480: {
        !           481:        if (rcode == EX_OK)
        !           482:                return;
        !           483:        else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR)
        !           484:                q->q_flags |= QBADADDR;
        !           485:        else if (curtime() > e->e_ctime + TimeOut)
        !           486:        {
        !           487:                extern char *pintvl();
        !           488:                char buf[MAXLINE];
        !           489: 
        !           490:                if (!bitset(EF_TIMEOUT, e->e_flags))
        !           491:                {
        !           492:                        (void) sprintf(buf, "Cannot send message for %s",
        !           493:                                pintvl(TimeOut, FALSE));
        !           494:                        if (e->e_message != NULL)
        !           495:                                free(e->e_message);
        !           496:                        e->e_message = newstr(buf);
        !           497:                        message(Arpa_Info, buf);
        !           498:                }
        !           499:                q->q_flags |= QBADADDR;
        !           500:                e->e_flags |= EF_TIMEOUT;
        !           501:        }
        !           502:        else
        !           503:                q->q_flags |= QQUEUEUP;
        !           504: }
        !           505: /*
        !           506: **  DOFORK -- do a fork, retrying a couple of times on failure.
        !           507: **
        !           508: **     This MUST be a macro, since after a vfork we are running
        !           509: **     two processes on the same stack!!!
        !           510: **
        !           511: **     Parameters:
        !           512: **             none.
        !           513: **
        !           514: **     Returns:
        !           515: **             From a macro???  You've got to be kidding!
        !           516: **
        !           517: **     Side Effects:
        !           518: **             Modifies the ==> LOCAL <== variable 'pid', leaving:
        !           519: **                     pid of child in parent, zero in child.
        !           520: **                     -1 on unrecoverable error.
        !           521: **
        !           522: **     Notes:
        !           523: **             I'm awfully sorry this looks so awful.  That's
        !           524: **             vfork for you.....
        !           525: */
        !           526: 
        !           527: # define NFORKTRIES    5
        !           528: # ifdef VMUNIX
        !           529: # define XFORK vfork
        !           530: # else VMUNIX
        !           531: # define XFORK fork
        !           532: # endif VMUNIX
        !           533: 
        !           534: # define DOFORK(fORKfN) \
        !           535: {\
        !           536:        register int i;\
        !           537: \
        !           538:        for (i = NFORKTRIES; --i >= 0; )\
        !           539:        {\
        !           540:                pid = fORKfN();\
        !           541:                if (pid >= 0)\
        !           542:                        break;\
        !           543:                if (i > 0)\
        !           544:                        sleep((unsigned) NFORKTRIES - i);\
        !           545:        }\
        !           546: }
        !           547: /*
        !           548: **  DOFORK -- simple fork interface to DOFORK.
        !           549: **
        !           550: **     Parameters:
        !           551: **             none.
        !           552: **
        !           553: **     Returns:
        !           554: **             pid of child in parent.
        !           555: **             zero in child.
        !           556: **             -1 on error.
        !           557: **
        !           558: **     Side Effects:
        !           559: **             returns twice, once in parent and once in child.
        !           560: */
        !           561: 
        !           562: dofork()
        !           563: {
        !           564:        register int pid;
        !           565: 
        !           566:        DOFORK(fork);
        !           567:        return (pid);
        !           568: }
        !           569: /*
        !           570: **  SENDOFF -- send off call to mailer & collect response.
        !           571: **
        !           572: **     Parameters:
        !           573: **             e -- the envelope to mail.
        !           574: **             m -- mailer descriptor.
        !           575: **             pvp -- parameter vector to send to it.
        !           576: **             ctladdr -- an address pointer controlling the
        !           577: **                     user/groupid etc. of the mailer.
        !           578: **
        !           579: **     Returns:
        !           580: **             exit status of mailer.
        !           581: **
        !           582: **     Side Effects:
        !           583: **             none.
        !           584: */
        !           585: static
        !           586: sendoff(e, m, pvp, ctladdr)
        !           587:        register ENVELOPE *e;
        !           588:        MAILER *m;
        !           589:        char **pvp;
        !           590:        ADDRESS *ctladdr;
        !           591: {
        !           592:        auto FILE *mfile;
        !           593:        auto FILE *rfile;
        !           594:        register int i;
        !           595:        int pid;
        !           596: 
        !           597:        /*
        !           598:        **  Create connection to mailer.
        !           599:        */
        !           600: 
        !           601:        pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile);
        !           602:        if (pid < 0)
        !           603:                return (-1);
        !           604: 
        !           605:        /*
        !           606:        **  Format and send message.
        !           607:        */
        !           608: 
        !           609:        putfromline(mfile, m);
        !           610:        (*e->e_puthdr)(mfile, m, e);
        !           611:        putline("\n", mfile, m);
        !           612:        (*e->e_putbody)(mfile, m, e);
        !           613:        (void) fclose(mfile);
        !           614:        if (rfile != NULL)
        !           615:                (void) fclose(rfile);
        !           616: 
        !           617:        i = endmailer(pid, pvp[0]);
        !           618: 
        !           619:        /* arrange a return receipt if requested */
        !           620:        if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags))
        !           621:        {
        !           622:                e->e_flags |= EF_SENDRECEIPT;
        !           623:                /* do we want to send back more info? */
        !           624:        }
        !           625: 
        !           626:        return (i);
        !           627: }
        !           628: /*
        !           629: **  ENDMAILER -- Wait for mailer to terminate.
        !           630: **
        !           631: **     We should never get fatal errors (e.g., segmentation
        !           632: **     violation), so we report those specially.  For other
        !           633: **     errors, we choose a status message (into statmsg),
        !           634: **     and if it represents an error, we print it.
        !           635: **
        !           636: **     Parameters:
        !           637: **             pid -- pid of mailer.
        !           638: **             name -- name of mailer (for error messages).
        !           639: **
        !           640: **     Returns:
        !           641: **             exit code of mailer.
        !           642: **
        !           643: **     Side Effects:
        !           644: **             none.
        !           645: */
        !           646: 
        !           647: endmailer(pid, name)
        !           648:        int pid;
        !           649:        char *name;
        !           650: {
        !           651:        int st;
        !           652: 
        !           653:        /* in the IPC case there is nothing to wait for */
        !           654:        if (pid == 0)
        !           655:                return (EX_OK);
        !           656: 
        !           657:        /* wait for the mailer process to die and collect status */
        !           658:        st = waitfor(pid);
        !           659:        if (st == -1)
        !           660:        {
        !           661:                syserr("endmailer %s: wait", name);
        !           662:                return (EX_SOFTWARE);
        !           663:        }
        !           664: 
        !           665:        /* see if it died a horrid death */
        !           666:        if ((st & 0377) != 0)
        !           667:        {
        !           668:                syserr("mailer %s died with signal %o", name, st);
        !           669:                ExitStat = EX_TEMPFAIL;
        !           670:                return (EX_TEMPFAIL);
        !           671:        }
        !           672: 
        !           673:        /* normal death -- return status */
        !           674:        st = (st >> 8) & 0377;
        !           675:        return (st);
        !           676: }
        !           677: /*
        !           678: **  OPENMAILER -- open connection to mailer.
        !           679: **
        !           680: **     Parameters:
        !           681: **             m -- mailer descriptor.
        !           682: **             pvp -- parameter vector to pass to mailer.
        !           683: **             ctladdr -- controlling address for user.
        !           684: **             clever -- create a full duplex connection.
        !           685: **             pmfile -- pointer to mfile (to mailer) connection.
        !           686: **             prfile -- pointer to rfile (from mailer) connection.
        !           687: **
        !           688: **     Returns:
        !           689: **             pid of mailer ( > 0 ).
        !           690: **             -1 on error.
        !           691: **             zero on an IPC connection.
        !           692: **
        !           693: **     Side Effects:
        !           694: **             creates a mailer in a subprocess.
        !           695: */
        !           696: 
        !           697: openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
        !           698:        MAILER *m;
        !           699:        char **pvp;
        !           700:        ADDRESS *ctladdr;
        !           701:        bool clever;
        !           702:        FILE **pmfile;
        !           703:        FILE **prfile;
        !           704: {
        !           705:        int pid;
        !           706:        int mpvect[2];
        !           707:        int rpvect[2];
        !           708:        FILE *mfile = NULL;
        !           709:        FILE *rfile = NULL;
        !           710:        extern FILE *fdopen();
        !           711: 
        !           712:        if (tTd(11, 1))
        !           713:        {
        !           714:                printf("openmailer:");
        !           715:                printav(pvp);
        !           716:        }
        !           717:        errno = 0;
        !           718: 
        !           719:        CurHostName = m->m_mailer;
        !           720: 
        !           721:        /*
        !           722:        **  Deal with the special case of mail handled through an IPC
        !           723:        **  connection.
        !           724:        **      In this case we don't actually fork.  We must be
        !           725:        **      running SMTP for this to work.  We will return a
        !           726:        **      zero pid to indicate that we are running IPC.
        !           727:        **  We also handle a debug version that just talks to stdin/out.
        !           728:        */
        !           729: 
        !           730:        /* check for Local Person Communication -- not for mortals!!! */
        !           731:        if (strcmp(m->m_mailer, "[LPC]") == 0)
        !           732:        {
        !           733:                *pmfile = stdout;
        !           734:                *prfile = stdin;
        !           735:                return (0);
        !           736:        }
        !           737: 
        !           738:        if (strcmp(m->m_mailer, "[IPC]") == 0)
        !           739:        {
        !           740: #ifdef HOSTINFO
        !           741:                register STAB *st;
        !           742:                extern STAB *stab();
        !           743: #endif HOSTINFO
        !           744: #ifdef DAEMON
        !           745:                register int i, j;
        !           746:                register u_short port;
        !           747: 
        !           748:                CurHostName = pvp[1];
        !           749:                if (!clever)
        !           750:                        syserr("non-clever IPC");
        !           751:                if (pvp[2] != NULL)
        !           752:                        port = atoi(pvp[2]);
        !           753:                else
        !           754:                        port = 0;
        !           755:                for (j = 0; j < Nmx; j++)
        !           756:                {
        !           757:                        CurHostName = MxHosts[j];
        !           758: #ifdef HOSTINFO
        !           759:                /* see if we have already determined that this host is fried */
        !           760:                        st = stab(MxHosts[j], ST_HOST, ST_FIND);
        !           761:                        if (st == NULL || st->s_host.ho_exitstat == EX_OK) {
        !           762:                                if (j > 1)
        !           763:                                        message(Arpa_Info,
        !           764:                                            "Connecting to %s (%s)...",
        !           765:                                            MxHosts[j], m->m_name);
        !           766:                                i = makeconnection(MxHosts[j], port, pmfile, prfile);
        !           767:                        }
        !           768:                        else
        !           769:                        {
        !           770:                                i = st->s_host.ho_exitstat;
        !           771:                                errno = st->s_host.ho_errno;
        !           772:                        }
        !           773: #else HOSTINFO
        !           774:                        i = makeconnection(MxHosts[j], port, pmfile, prfile);
        !           775: #endif HOSTINFO
        !           776:                        if (i != EX_OK)
        !           777:                        {
        !           778: #ifdef HOSTINFO
        !           779:                                /* enter status of this host */
        !           780:                                if (st == NULL)
        !           781:                                        st = stab(MxHosts[j], ST_HOST, ST_ENTER);
        !           782:                                st->s_host.ho_exitstat = i;
        !           783:                                st->s_host.ho_errno = errno;
        !           784: #endif HOSTINFO
        !           785:                                ExitStat = i;
        !           786:                                continue;
        !           787:                        }
        !           788:                        else
        !           789:                                return (0);
        !           790:                }
        !           791:                return (-1);
        !           792: #else DAEMON
        !           793:                syserr("openmailer: no IPC");
        !           794:                return (-1);
        !           795: #endif DAEMON
        !           796:        }
        !           797: 
        !           798:        /* create a pipe to shove the mail through */
        !           799:        if (pipe(mpvect) < 0)
        !           800:        {
        !           801:                syserr("openmailer: pipe (to mailer)");
        !           802:                return (-1);
        !           803:        }
        !           804: 
        !           805: #ifdef SMTP
        !           806:        /* if this mailer speaks smtp, create a return pipe */
        !           807:        if (clever && pipe(rpvect) < 0)
        !           808:        {
        !           809:                syserr("openmailer: pipe (from mailer)");
        !           810:                (void) close(mpvect[0]);
        !           811:                (void) close(mpvect[1]);
        !           812:                return (-1);
        !           813:        }
        !           814: #endif SMTP
        !           815: 
        !           816:        /*
        !           817:        **  Actually fork the mailer process.
        !           818:        **      DOFORK is clever about retrying.
        !           819:        **
        !           820:        **      Dispose of SIGCHLD signal catchers that may be laying
        !           821:        **      around so that endmail will get it.
        !           822:        */
        !           823: 
        !           824:        if (CurEnv->e_xfp != NULL)
        !           825:                (void) fflush(CurEnv->e_xfp);           /* for debugging */
        !           826:        (void) fflush(stdout);
        !           827: # ifdef SIGCHLD
        !           828:        (void) signal(SIGCHLD, SIG_DFL);
        !           829: # endif SIGCHLD
        !           830:        DOFORK(XFORK);
        !           831:        /* pid is set by DOFORK */
        !           832:        if (pid < 0)
        !           833:        {
        !           834:                /* failure */
        !           835:                syserr("openmailer: cannot fork");
        !           836:                (void) close(mpvect[0]);
        !           837:                (void) close(mpvect[1]);
        !           838: #ifdef SMTP
        !           839:                if (clever)
        !           840:                {
        !           841:                        (void) close(rpvect[0]);
        !           842:                        (void) close(rpvect[1]);
        !           843:                }
        !           844: #endif SMTP
        !           845:                return (-1);
        !           846:        }
        !           847:        else if (pid == 0)
        !           848:        {
        !           849:                int i;
        !           850:                extern int DtableSize;
        !           851: 
        !           852:                /* child -- set up input & exec mailer */
        !           853:                /* make diagnostic output be standard output */
        !           854:                (void) signal(SIGINT, SIG_IGN);
        !           855:                (void) signal(SIGHUP, SIG_IGN);
        !           856:                (void) signal(SIGTERM, SIG_DFL);
        !           857: 
        !           858:                /* arrange to filter standard & diag output of command */
        !           859:                if (clever)
        !           860:                {
        !           861:                        (void) close(rpvect[0]);
        !           862:                        (void) close(1);
        !           863:                        (void) dup(rpvect[1]);
        !           864:                        (void) close(rpvect[1]);
        !           865:                }
        !           866:                else if (OpMode == MD_SMTP || HoldErrs)
        !           867:                {
        !           868:                        /* put mailer output in transcript */
        !           869:                        (void) close(1);
        !           870:                        (void) dup(fileno(CurEnv->e_xfp));
        !           871:                }
        !           872:                (void) close(2);
        !           873:                (void) dup(1);
        !           874: 
        !           875:                /* arrange to get standard input */
        !           876:                (void) close(mpvect[1]);
        !           877:                (void) close(0);
        !           878:                if (dup(mpvect[0]) < 0)
        !           879:                {
        !           880:                        syserr("Cannot dup to zero!");
        !           881:                        _exit(EX_OSERR);
        !           882:                }
        !           883:                (void) close(mpvect[0]);
        !           884:                if (!bitnset(M_RESTR, m->m_flags))
        !           885:                {
        !           886:                        if (ctladdr == NULL || ctladdr->q_uid == 0)
        !           887:                        {
        !           888:                                (void) setgid(DefGid);
        !           889:                                (void) initgroups(DefUser, DefGid);
        !           890:                                (void) setuid(DefUid);
        !           891:                        }
        !           892:                        else
        !           893:                        {
        !           894:                                (void) setgid(ctladdr->q_gid);
        !           895:                                (void) initgroups(ctladdr->q_ruser?
        !           896:                                        ctladdr->q_ruser: ctladdr->q_user,
        !           897:                                        ctladdr->q_gid);
        !           898:                                (void) setuid(ctladdr->q_uid);
        !           899:                        }
        !           900:                }
        !           901: 
        !           902:                /* arrange for all the files to be closed */
        !           903:                for (i = 3; i < DtableSize; i++) {
        !           904:                        register int j;
        !           905:                        if ((j = fcntl(i, F_GETFD, 0)) != -1)
        !           906:                                (void)fcntl(i, F_SETFD, j|1);
        !           907:                }
        !           908: 
        !           909:                /* try to execute the mailer */
        !           910:                execve(m->m_mailer, pvp, UserEnviron);
        !           911:                syserr("Cannot exec %s", m->m_mailer);
        !           912:                if (m == LocalMailer || errno == EIO || errno == EAGAIN ||
        !           913:                    errno == ENOMEM || errno == EPROCLIM)
        !           914:                        _exit(EX_TEMPFAIL);
        !           915:                else
        !           916:                        _exit(EX_UNAVAILABLE);
        !           917:        }
        !           918: 
        !           919:        /*
        !           920:        **  Set up return value.
        !           921:        */
        !           922: 
        !           923:        (void) close(mpvect[0]);
        !           924:        mfile = fdopen(mpvect[1], "w");
        !           925:        if (clever)
        !           926:        {
        !           927:                (void) close(rpvect[1]);
        !           928:                rfile = fdopen(rpvect[0], "r");
        !           929:        } else
        !           930:                rfile = NULL;
        !           931: 
        !           932:        *pmfile = mfile;
        !           933:        *prfile = rfile;
        !           934: 
        !           935:        return (pid);
        !           936: }
        !           937: /*
        !           938: **  GIVERESPONSE -- Interpret an error response from a mailer
        !           939: **
        !           940: **     Parameters:
        !           941: **             stat -- the status code from the mailer (high byte
        !           942: **                     only; core dumps must have been taken care of
        !           943: **                     already).
        !           944: **             m -- the mailer descriptor for this mailer.
        !           945: **
        !           946: **     Returns:
        !           947: **             none.
        !           948: **
        !           949: **     Side Effects:
        !           950: **             Errors may be incremented.
        !           951: **             ExitStat may be set.
        !           952: */
        !           953: 
        !           954: giveresponse(stat, m, e)
        !           955:        int stat;
        !           956:        register MAILER *m;
        !           957:        ENVELOPE *e;
        !           958: {
        !           959:        register char *statmsg;
        !           960:        extern char *SysExMsg[];
        !           961:        register int i;
        !           962:        extern int N_SysEx;
        !           963: #ifdef NAMED_BIND
        !           964:        extern int h_errno;
        !           965: #endif
        !           966:        char buf[MAXLINE];
        !           967: 
        !           968: #ifdef lint
        !           969:        if (m == NULL)
        !           970:                return;
        !           971: #endif lint
        !           972: 
        !           973:        /*
        !           974:        **  Compute status message from code.
        !           975:        */
        !           976: 
        !           977:        i = stat - EX__BASE;
        !           978:        if (stat == 0)
        !           979:                statmsg = "250 Sent";
        !           980:        else if (i < 0 || i > N_SysEx)
        !           981:        {
        !           982:                (void) sprintf(buf, "554 unknown mailer error %d", stat);
        !           983:                stat = EX_UNAVAILABLE;
        !           984:                statmsg = buf;
        !           985:        }
        !           986:        else if (stat == EX_TEMPFAIL)
        !           987:        {
        !           988:                (void) strcpy(buf, SysExMsg[i]);
        !           989: #ifdef NAMED_BIND
        !           990:                if (h_errno == TRY_AGAIN)
        !           991:                {
        !           992:                        extern char *errstring();
        !           993: 
        !           994:                        statmsg = errstring(h_errno+MAX_ERRNO);
        !           995:                }
        !           996:                else
        !           997: #endif
        !           998:                {
        !           999:                        if (errno != 0)
        !          1000:                        {
        !          1001:                                extern char *errstring();
        !          1002: 
        !          1003:                                statmsg = errstring(errno);
        !          1004:                        }
        !          1005:                        else
        !          1006:                        {
        !          1007: #ifdef SMTP
        !          1008:                                extern char SmtpError[];
        !          1009: 
        !          1010:                                statmsg = SmtpError;
        !          1011: #else SMTP
        !          1012:                                statmsg = NULL;
        !          1013: #endif SMTP
        !          1014:                        }
        !          1015:                }
        !          1016:                if (statmsg != NULL && statmsg[0] != '\0')
        !          1017:                {
        !          1018:                        (void) strcat(buf, ": ");
        !          1019:                        (void) strcat(buf, statmsg);
        !          1020:                }
        !          1021:                statmsg = buf;
        !          1022:        }
        !          1023:        else
        !          1024:        {
        !          1025:                statmsg = SysExMsg[i];
        !          1026:        }
        !          1027: 
        !          1028:        /*
        !          1029:        **  Print the message as appropriate
        !          1030:        */
        !          1031: 
        !          1032:        if (stat == EX_OK || stat == EX_TEMPFAIL)
        !          1033:                message(Arpa_Info, &statmsg[4]);
        !          1034:        else
        !          1035:        {
        !          1036:                Errors++;
        !          1037:                usrerr(statmsg);
        !          1038:        }
        !          1039: 
        !          1040:        /*
        !          1041:        **  Final cleanup.
        !          1042:        **      Log a record of the transaction.  Compute the new
        !          1043:        **      ExitStat -- if we already had an error, stick with
        !          1044:        **      that.
        !          1045:        */
        !          1046: 
        !          1047:        if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2))
        !          1048:                logdelivery(&statmsg[4]);
        !          1049: 
        !          1050:        if (stat != EX_TEMPFAIL)
        !          1051:                setstat(stat);
        !          1052:        if (stat != EX_OK)
        !          1053:        {
        !          1054:                if (e->e_message != NULL)
        !          1055:                        free(e->e_message);
        !          1056:                e->e_message = newstr(&statmsg[4]);
        !          1057:        }
        !          1058:        errno = 0;
        !          1059: #ifdef NAMED_BIND
        !          1060:        h_errno = 0;
        !          1061: #endif
        !          1062: }
        !          1063: /*
        !          1064: **  LOGDELIVERY -- log the delivery in the system log
        !          1065: **
        !          1066: **     Parameters:
        !          1067: **             stat -- the message to print for the status
        !          1068: **
        !          1069: **     Returns:
        !          1070: **             none
        !          1071: **
        !          1072: **     Side Effects:
        !          1073: **             none
        !          1074: */
        !          1075: 
        !          1076: logdelivery(stat)
        !          1077:        char *stat;
        !          1078: {
        !          1079:        extern char *pintvl();
        !          1080: 
        !          1081: # ifdef LOG
        !          1082:        syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id,
        !          1083:               CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat);
        !          1084: # endif LOG
        !          1085: }
        !          1086: /*
        !          1087: **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
        !          1088: **
        !          1089: **     This can be made an arbitrary message separator by changing $l
        !          1090: **
        !          1091: **     One of the ugliest hacks seen by human eyes is contained herein:
        !          1092: **     UUCP wants those stupid "remote from <host>" lines.  Why oh why
        !          1093: **     does a well-meaning programmer such as myself have to deal with
        !          1094: **     this kind of antique garbage????
        !          1095: **
        !          1096: **     Parameters:
        !          1097: **             fp -- the file to output to.
        !          1098: **             m -- the mailer describing this entry.
        !          1099: **
        !          1100: **     Returns:
        !          1101: **             none
        !          1102: **
        !          1103: **     Side Effects:
        !          1104: **             outputs some text to fp.
        !          1105: */
        !          1106: 
        !          1107: putfromline(fp, m)
        !          1108:        register FILE *fp;
        !          1109:        register MAILER *m;
        !          1110: {
        !          1111:        char *template = "\001l\n";
        !          1112:        char buf[MAXLINE];
        !          1113: 
        !          1114:        if (bitnset(M_NHDR, m->m_flags))
        !          1115:                return;
        !          1116: 
        !          1117: # ifdef UGLYUUCP
        !          1118:        if (bitnset(M_UGLYUUCP, m->m_flags))
        !          1119:        {
        !          1120:                char *bang;
        !          1121:                char xbuf[MAXLINE];
        !          1122: 
        !          1123:                expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
        !          1124:                bang = index(buf, '!');
        !          1125:                if (bang == NULL)
        !          1126:                        syserr("No ! in UUCP! (%s)", buf);
        !          1127:                else
        !          1128:                {
        !          1129:                        *bang++ = '\0';
        !          1130:                        (void) sprintf(xbuf, "From %s  \001d remote from %s\n", bang, buf);
        !          1131:                        template = xbuf;
        !          1132:                }
        !          1133:        }
        !          1134: # endif UGLYUUCP
        !          1135:        expand(template, buf, &buf[sizeof buf - 1], CurEnv);
        !          1136:        putline(buf, fp, m);
        !          1137: }
        !          1138: /*
        !          1139: **  PUTBODY -- put the body of a message.
        !          1140: **
        !          1141: **     Parameters:
        !          1142: **             fp -- file to output onto.
        !          1143: **             m -- a mailer descriptor to control output format.
        !          1144: **             e -- the envelope to put out.
        !          1145: **
        !          1146: **     Returns:
        !          1147: **             none.
        !          1148: **
        !          1149: **     Side Effects:
        !          1150: **             The message is written onto fp.
        !          1151: */
        !          1152: 
        !          1153: putbody(fp, m, e)
        !          1154:        FILE *fp;
        !          1155:        MAILER *m;
        !          1156:        register ENVELOPE *e;
        !          1157: {
        !          1158:        char buf[MAXLINE];
        !          1159: 
        !          1160:        /*
        !          1161:        **  Output the body of the message
        !          1162:        */
        !          1163: 
        !          1164:        if (e->e_dfp == NULL)
        !          1165:        {
        !          1166:                if (e->e_df != NULL)
        !          1167:                {
        !          1168:                        e->e_dfp = fopen(e->e_df, "r");
        !          1169:                        if (e->e_dfp == NULL)
        !          1170:                                syserr("putbody: Cannot open %s for %s from %s",
        !          1171:                                e->e_df, e->e_to, e->e_from);
        !          1172:                }
        !          1173:                else
        !          1174:                        putline("<<< No Message Collected >>>", fp, m);
        !          1175:        }
        !          1176:        if (e->e_dfp != NULL)
        !          1177:        {
        !          1178:                rewind(e->e_dfp);
        !          1179:                while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
        !          1180:                {
        !          1181:                        if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) &&
        !          1182:                            strncmp(buf, "From ", 5) == 0)
        !          1183:                                (void) putc('>', fp);
        !          1184:                        putline(buf, fp, m);
        !          1185:                }
        !          1186: 
        !          1187:                if (ferror(e->e_dfp))
        !          1188:                {
        !          1189:                        syserr("putbody: read error");
        !          1190:                        ExitStat = EX_IOERR;
        !          1191:                }
        !          1192:        }
        !          1193: 
        !          1194:        (void) fflush(fp);
        !          1195:        if (ferror(fp) && errno != EPIPE)
        !          1196:        {
        !          1197:                syserr("putbody: write error");
        !          1198:                ExitStat = EX_IOERR;
        !          1199:        }
        !          1200:        errno = 0;
        !          1201: }
        !          1202: /*
        !          1203: **  MAILFILE -- Send a message to a file.
        !          1204: **
        !          1205: **     If the file has the setuid/setgid bits set, but NO execute
        !          1206: **     bits, sendmail will try to become the owner of that file
        !          1207: **     rather than the real user.  Obviously, this only works if
        !          1208: **     sendmail runs as root.
        !          1209: **
        !          1210: **     This could be done as a subordinate mailer, except that it
        !          1211: **     is used implicitly to save messages in ~/dead.letter.  We
        !          1212: **     view this as being sufficiently important as to include it
        !          1213: **     here.  For example, if the system is dying, we shouldn't have
        !          1214: **     to create another process plus some pipes to save the message.
        !          1215: **
        !          1216: **     Parameters:
        !          1217: **             filename -- the name of the file to send to.
        !          1218: **             ctladdr -- the controlling address header -- includes
        !          1219: **                     the userid/groupid to be when sending.
        !          1220: **
        !          1221: **     Returns:
        !          1222: **             The exit code associated with the operation.
        !          1223: **
        !          1224: **     Side Effects:
        !          1225: **             none.
        !          1226: */
        !          1227: 
        !          1228: mailfile(filename, ctladdr)
        !          1229:        char *filename;
        !          1230:        ADDRESS *ctladdr;
        !          1231: {
        !          1232:        register FILE *f;
        !          1233:        register int pid;
        !          1234:        ENVELOPE *e = CurEnv;
        !          1235: 
        !          1236:        /*
        !          1237:        **  Fork so we can change permissions here.
        !          1238:        **      Note that we MUST use fork, not vfork, because of
        !          1239:        **      the complications of calling subroutines, etc.
        !          1240:        */
        !          1241: 
        !          1242:        DOFORK(fork);
        !          1243: 
        !          1244:        if (pid < 0)
        !          1245:                return (EX_OSERR);
        !          1246:        else if (pid == 0)
        !          1247:        {
        !          1248:                /* child -- actually write to file */
        !          1249:                struct stat stb;
        !          1250: 
        !          1251:                (void) signal(SIGINT, SIG_DFL);
        !          1252:                (void) signal(SIGHUP, SIG_DFL);
        !          1253:                (void) signal(SIGTERM, SIG_DFL);
        !          1254:                (void) umask(OldUmask);
        !          1255:                if (stat(filename, &stb) < 0)
        !          1256:                {
        !          1257:                        errno = 0;
        !          1258:                        stb.st_mode = 0666;
        !          1259:                }
        !          1260:                if (bitset(0111, stb.st_mode))
        !          1261:                        exit(EX_CANTCREAT);
        !          1262:                if (ctladdr == NULL)
        !          1263:                        ctladdr = &e->e_from;
        !          1264:                /* we have to open the dfile BEFORE setuid */
        !          1265:                if (e->e_dfp == NULL &&  e->e_df != NULL)
        !          1266:                {
        !          1267:                        e->e_dfp = fopen(e->e_df, "r");
        !          1268:                        if (e->e_dfp == NULL) {
        !          1269:                                syserr("mailfile: Cannot open %s for %s from %s",
        !          1270:                                e->e_df, e->e_to, e->e_from);
        !          1271:                        }
        !          1272:                }
        !          1273: 
        !          1274:                if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0)
        !          1275:                {
        !          1276:                        if (ctladdr->q_uid == 0) {
        !          1277:                                (void) setgid(DefGid);
        !          1278:                                (void) initgroups(DefUser, DefGid);
        !          1279:                        } else {
        !          1280:                                (void) setgid(ctladdr->q_gid);
        !          1281:                                (void) initgroups(ctladdr->q_ruser?
        !          1282:                                        ctladdr->q_ruser: ctladdr->q_user,
        !          1283:                                        ctladdr->q_gid);
        !          1284:                        }
        !          1285:                }
        !          1286:                if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0)
        !          1287:                {
        !          1288:                        if (ctladdr->q_uid == 0)
        !          1289:                                (void) setuid(DefUid);
        !          1290:                        else
        !          1291:                                (void) setuid(ctladdr->q_uid);
        !          1292:                }
        !          1293:                f = dfopen(filename, "a");
        !          1294:                if (f == NULL)
        !          1295:                        exit(EX_CANTCREAT);
        !          1296: 
        !          1297:                putfromline(f, ProgMailer);
        !          1298:                (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv);
        !          1299:                putline("\n", f, ProgMailer);
        !          1300:                (*CurEnv->e_putbody)(f, ProgMailer, CurEnv);
        !          1301:                putline("\n", f, ProgMailer);
        !          1302:                (void) fclose(f);
        !          1303:                (void) fflush(stdout);
        !          1304: 
        !          1305:                /* reset ISUID & ISGID bits for paranoid systems */
        !          1306:                (void) chmod(filename, (int) stb.st_mode);
        !          1307:                exit(EX_OK);
        !          1308:                /*NOTREACHED*/
        !          1309:        }
        !          1310:        else
        !          1311:        {
        !          1312:                /* parent -- wait for exit status */
        !          1313:                int st;
        !          1314: 
        !          1315:                st = waitfor(pid);
        !          1316:                if ((st & 0377) != 0)
        !          1317:                        return (EX_UNAVAILABLE);
        !          1318:                else
        !          1319:                        return ((st >> 8) & 0377);
        !          1320:                /*NOTREACHED*/
        !          1321:        }
        !          1322: }
        !          1323: /*
        !          1324: **  SENDALL -- actually send all the messages.
        !          1325: **
        !          1326: **     Parameters:
        !          1327: **             e -- the envelope to send.
        !          1328: **             mode -- the delivery mode to use.  If SM_DEFAULT, use
        !          1329: **                     the current SendMode.
        !          1330: **
        !          1331: **     Returns:
        !          1332: **             none.
        !          1333: **
        !          1334: **     Side Effects:
        !          1335: **             Scans the send lists and sends everything it finds.
        !          1336: **             Delivers any appropriate error messages.
        !          1337: **             If we are running in a non-interactive mode, takes the
        !          1338: **                     appropriate action.
        !          1339: */
        !          1340: 
        !          1341: sendall(e, mode)
        !          1342:        ENVELOPE *e;
        !          1343:        char mode;
        !          1344: {
        !          1345:        register ADDRESS *q;
        !          1346:        bool oldverbose;
        !          1347:        int pid;
        !          1348:        FILE *lockfp = NULL, *queueup();
        !          1349: 
        !          1350:        /* determine actual delivery mode */
        !          1351:        if (mode == SM_DEFAULT)
        !          1352:        {
        !          1353:                extern bool shouldqueue();
        !          1354: 
        !          1355:                if (shouldqueue(e->e_msgpriority))
        !          1356:                        mode = SM_QUEUE;
        !          1357:                else
        !          1358:                        mode = SendMode;
        !          1359:        }
        !          1360: 
        !          1361:        if (tTd(13, 1))
        !          1362:        {
        !          1363:                printf("\nSENDALL: mode %c, sendqueue:\n", mode);
        !          1364:                printaddr(e->e_sendqueue, TRUE);
        !          1365:        }
        !          1366: 
        !          1367:        /*
        !          1368:        **  Do any preprocessing necessary for the mode we are running.
        !          1369:        **      Check to make sure the hop count is reasonable.
        !          1370:        **      Delete sends to the sender in mailing lists.
        !          1371:        */
        !          1372: 
        !          1373:        CurEnv = e;
        !          1374: 
        !          1375:        if (e->e_hopcount > MAXHOP)
        !          1376:        {
        !          1377:                errno = 0;
        !          1378:                syserr("sendall: too many hops %d (%d max): from %s, to %s",
        !          1379:                        e->e_hopcount, MAXHOP, e->e_from, e->e_to);
        !          1380:                return;
        !          1381:        }
        !          1382: 
        !          1383:        if (!MeToo)
        !          1384:        {
        !          1385:                extern ADDRESS *recipient();
        !          1386: 
        !          1387:                e->e_from.q_flags |= QDONTSEND;
        !          1388:                (void) recipient(&e->e_from, &e->e_sendqueue);
        !          1389:        }
        !          1390: 
        !          1391: # ifdef QUEUE
        !          1392:        if ((mode == SM_QUEUE || mode == SM_FORK ||
        !          1393:             (mode != SM_VERIFY && SuperSafe)) &&
        !          1394:            !bitset(EF_INQUEUE, e->e_flags))
        !          1395:                lockfp = queueup(e, TRUE, mode == SM_QUEUE);
        !          1396: #endif QUEUE
        !          1397: 
        !          1398:        oldverbose = Verbose;
        !          1399:        switch (mode)
        !          1400:        {
        !          1401:          case SM_VERIFY:
        !          1402:                Verbose = TRUE;
        !          1403:                break;
        !          1404: 
        !          1405:          case SM_QUEUE:
        !          1406:                e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
        !          1407:                return;
        !          1408: 
        !          1409:          case SM_FORK:
        !          1410:                if (e->e_xfp != NULL)
        !          1411:                        (void) fflush(e->e_xfp);
        !          1412:                pid = fork();
        !          1413:                if (pid < 0)
        !          1414:                {
        !          1415:                        mode = SM_DELIVER;
        !          1416:                        break;
        !          1417:                }
        !          1418:                else if (pid > 0)
        !          1419:                {
        !          1420:                        /* be sure we leave the temp files to our child */
        !          1421:                        e->e_id = e->e_df = NULL;
        !          1422:                        if (lockfp != NULL)
        !          1423:                                (void) fclose(lockfp);
        !          1424:                        return;
        !          1425:                }
        !          1426: 
        !          1427:                /* double fork to avoid zombies */
        !          1428:                if (fork() > 0)
        !          1429:                        exit(EX_OK);
        !          1430: 
        !          1431:                /* be sure we are immune from the terminal */
        !          1432:                disconnect(FALSE);
        !          1433: 
        !          1434:                break;
        !          1435:        }
        !          1436: 
        !          1437:        /*
        !          1438:        **  Run through the list and send everything.
        !          1439:        */
        !          1440: 
        !          1441:        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        !          1442:        {
        !          1443:                if (mode == SM_VERIFY)
        !          1444:                {
        !          1445:                        e->e_to = q->q_paddr;
        !          1446:                        if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
        !          1447:                                message(Arpa_Info, "deliverable");
        !          1448:                }
        !          1449:                else
        !          1450:                        (void) deliver(e, q);
        !          1451:        }
        !          1452:        Verbose = oldverbose;
        !          1453: 
        !          1454:        /*
        !          1455:        **  Now run through and check for errors.
        !          1456:        */
        !          1457: 
        !          1458:        if (mode == SM_VERIFY) {
        !          1459:                if (lockfp != NULL)
        !          1460:                        (void) fclose(lockfp);
        !          1461:                return;
        !          1462:        }
        !          1463: 
        !          1464:        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
        !          1465:        {
        !          1466:                register ADDRESS *qq;
        !          1467: 
        !          1468:                if (tTd(13, 3))
        !          1469:                {
        !          1470:                        printf("Checking ");
        !          1471:                        printaddr(q, FALSE);
        !          1472:                }
        !          1473: 
        !          1474:                /* only send errors if the message failed */
        !          1475:                if (!bitset(QBADADDR, q->q_flags))
        !          1476:                        continue;
        !          1477: 
        !          1478:                /* we have an address that failed -- find the parent */
        !          1479:                for (qq = q; qq != NULL; qq = qq->q_alias)
        !          1480:                {
        !          1481:                        char obuf[MAXNAME + 6];
        !          1482:                        extern char *aliaslookup();
        !          1483: 
        !          1484:                        /* we can only have owners for local addresses */
        !          1485:                        if (!bitnset(M_LOCAL, qq->q_mailer->m_flags))
        !          1486:                                continue;
        !          1487: 
        !          1488:                        /* see if the owner list exists */
        !          1489:                        (void) strcpy(obuf, "owner-");
        !          1490:                        if (strncmp(qq->q_user, "owner-", 6) == 0)
        !          1491:                                (void) strcat(obuf, "owner");
        !          1492:                        else
        !          1493:                                (void) strcat(obuf, qq->q_user);
        !          1494:                        makelower(obuf);
        !          1495:                        if (aliaslookup(obuf) == NULL)
        !          1496:                                continue;
        !          1497: 
        !          1498:                        if (tTd(13, 4))
        !          1499:                                printf("Errors to %s\n", obuf);
        !          1500: 
        !          1501:                        /* owner list exists -- add it to the error queue */
        !          1502:                        sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue);
        !          1503:                        ErrorMode = EM_MAIL;
        !          1504:                        break;
        !          1505:                }
        !          1506: 
        !          1507:                /* if we did not find an owner, send to the sender */
        !          1508:                if (qq == NULL && bitset(QBADADDR, q->q_flags))
        !          1509:                        sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue);
        !          1510:        }
        !          1511: 
        !          1512:        /* this removes the lock on the file */
        !          1513:        if (lockfp != NULL)
        !          1514:                (void) fclose(lockfp);
        !          1515: 
        !          1516:        if (mode == SM_FORK)
        !          1517:                finis();
        !          1518: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.