Annotation of 43BSDReno/usr.sbin/sendmail/src/daemon.c, revision 1.1.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: #include <errno.h>
                     22: #include "sendmail.h"
                     23: 
                     24: #ifndef lint
                     25: #ifdef DAEMON
                     26: static char sccsid[] = "@(#)daemon.c   5.36 (Berkeley) 6/1/90 (with daemon mode)";
                     27: #else
                     28: static char sccsid[] = "@(#)daemon.c   5.36 (Berkeley) 6/1/90 (without daemon mode)";
                     29: #endif
                     30: #endif /* not lint */
                     31: 
                     32: int la;        /* load average */
                     33: 
                     34: #ifdef DAEMON
                     35: 
                     36: # include <netdb.h>
                     37: # include <sys/signal.h>
                     38: # include <sys/wait.h>
                     39: # include <sys/time.h>
                     40: # include <sys/resource.h>
                     41: 
                     42: /*
                     43: **  DAEMON.C -- routines to use when running as a daemon.
                     44: **
                     45: **     This entire file is highly dependent on the 4.2 BSD
                     46: **     interprocess communication primitives.  No attempt has
                     47: **     been made to make this file portable to Version 7,
                     48: **     Version 6, MPX files, etc.  If you should try such a
                     49: **     thing yourself, I recommend chucking the entire file
                     50: **     and starting from scratch.  Basic semantics are:
                     51: **
                     52: **     getrequests()
                     53: **             Opens a port and initiates a connection.
                     54: **             Returns in a child.  Must set InChannel and
                     55: **             OutChannel appropriately.
                     56: **     clrdaemon()
                     57: **             Close any open files associated with getting
                     58: **             the connection; this is used when running the queue,
                     59: **             etc., to avoid having extra file descriptors during
                     60: **             the queue run and to avoid confusing the network
                     61: **             code (if it cares).
                     62: **     makeconnection(host, port, outfile, infile)
                     63: **             Make a connection to the named host on the given
                     64: **             port.  Set *outfile and *infile to the files
                     65: **             appropriate for communication.  Returns zero on
                     66: **             success, else an exit status describing the
                     67: **             error.
                     68: **     maphostname(hbuf, hbufsize)
                     69: **             Convert the entry in hbuf into a canonical form.  It
                     70: **             may not be larger than hbufsize.
                     71: */
                     72: /*
                     73: **  GETREQUESTS -- open mail IPC port and get requests.
                     74: **
                     75: **     Parameters:
                     76: **             none.
                     77: **
                     78: **     Returns:
                     79: **             none.
                     80: **
                     81: **     Side Effects:
                     82: **             Waits until some interesting activity occurs.  When
                     83: **             it does, a child is created to process it, and the
                     84: **             parent waits for completion.  Return from this
                     85: **             routine is always in the child.  The file pointers
                     86: **             "InChannel" and "OutChannel" should be set to point
                     87: **             to the communication channel.
                     88: */
                     89: 
                     90: struct sockaddr_in     SendmailAddress;/* internet address of sendmail */
                     91: 
                     92: int    DaemonSocket    = -1;           /* fd describing socket */
                     93: char   *NetName;                       /* name of home (local?) network */
                     94: 
                     95: getrequests()
                     96: {
                     97:        int t;
                     98:        register struct servent *sp;
                     99:        int on = 1;
                    100:        extern reapchild();
                    101: 
                    102:        /*
                    103:        **  Set up the address for the mailer.
                    104:        */
                    105: 
                    106:        sp = getservbyname("smtp", "tcp");
                    107:        if (sp == NULL)
                    108:        {
                    109:                syserr("server \"smtp\" unknown");
                    110:                goto severe;
                    111:        }
                    112:        SendmailAddress.sin_family = AF_INET;
                    113:        SendmailAddress.sin_addr.s_addr = INADDR_ANY;
                    114:        SendmailAddress.sin_port = sp->s_port;
                    115: 
                    116:        /*
                    117:        **  Try to actually open the connection.
                    118:        */
                    119: 
                    120:        if (tTd(15, 1))
                    121:                printf("getrequests: port 0x%x\n", SendmailAddress.sin_port);
                    122: 
                    123:        /* get a socket for the SMTP connection */
                    124:        DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
                    125:        if (DaemonSocket < 0)
                    126:        {
                    127:                /* probably another daemon already */
                    128:                syserr("getrequests: can't create socket");
                    129:          severe:
                    130: # ifdef LOG
                    131:                if (LogLevel > 0)
                    132:                        syslog(LOG_ALERT, "cannot get connection");
                    133: # endif LOG
                    134:                finis();
                    135:        }
                    136: 
                    137:        /* turn on network debugging? */
                    138:        if (tTd(15, 15))
                    139:                (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
                    140: 
                    141:        (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
                    142:        (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
                    143: 
                    144:        if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress) < 0)
                    145:        {
                    146:                syserr("getrequests: cannot bind");
                    147:                (void) close(DaemonSocket);
                    148:                goto severe;
                    149:        }
                    150:        if (listen(DaemonSocket, 10) < 0)
                    151:        {
                    152:                syserr("getrequests: cannot listen");
                    153:                (void) close(DaemonSocket);
                    154:                goto severe;
                    155:        }
                    156: 
                    157:        (void) signal(SIGCHLD, reapchild);
                    158: 
                    159:        if (tTd(15, 1))
                    160:                printf("getrequests: %d\n", DaemonSocket);
                    161: 
                    162:        for (;;)
                    163:        {
                    164:                register int pid;
                    165:                auto int lotherend;
                    166:                extern int RefuseLA;
                    167: 
                    168:                /* see if we are rejecting connections */
                    169:                while ((la = getla()) > RefuseLA)
                    170:                {
                    171:                        setproctitle("rejecting connections: load average: %.2f", (double)la);
                    172:                        sleep(5);
                    173:                }
                    174: 
                    175:                /* wait for a connection */
                    176:                setproctitle("accepting connections");
                    177:                do
                    178:                {
                    179:                        errno = 0;
                    180:                        lotherend = sizeof RealHostAddr;
                    181:                        t = accept(DaemonSocket, &RealHostAddr, &lotherend);
                    182:                } while (t < 0 && errno == EINTR);
                    183:                if (t < 0)
                    184:                {
                    185:                        syserr("getrequests: accept");
                    186:                        sleep(5);
                    187:                        continue;
                    188:                }
                    189: 
                    190:                /*
                    191:                **  Create a subprocess to process the mail.
                    192:                */
                    193: 
                    194:                if (tTd(15, 2))
                    195:                        printf("getrequests: forking (fd = %d)\n", t);
                    196: 
                    197:                pid = fork();
                    198:                if (pid < 0)
                    199:                {
                    200:                        syserr("daemon: cannot fork");
                    201:                        sleep(10);
                    202:                        (void) close(t);
                    203:                        continue;
                    204:                }
                    205: 
                    206:                if (pid == 0)
                    207:                {
                    208:                        extern struct hostent *gethostbyaddr();
                    209:                        register struct hostent *hp;
                    210:                        char buf[MAXNAME];
                    211: 
                    212:                        /*
                    213:                        **  CHILD -- return to caller.
                    214:                        **      Collect verified idea of sending host.
                    215:                        **      Verify calling user id if possible here.
                    216:                        */
                    217: 
                    218:                        (void) signal(SIGCHLD, SIG_DFL);
                    219: 
                    220:                        /* determine host name */
                    221:                        hp = gethostbyaddr((char *) &RealHostAddr.sin_addr, sizeof RealHostAddr.sin_addr, AF_INET);
                    222:                        if (hp != NULL)
                    223:                                (void) strcpy(buf, hp->h_name);
                    224:                        else
                    225:                        {
                    226:                                extern char *inet_ntoa();
                    227: 
                    228:                                /* produce a dotted quad */
                    229:                                (void) sprintf(buf, "[%s]",
                    230:                                        inet_ntoa(RealHostAddr.sin_addr));
                    231:                        }
                    232: 
                    233:                        /* should we check for illegal connection here? XXX */
                    234: 
                    235:                        RealHostName = newstr(buf);
                    236: 
                    237:                        (void) close(DaemonSocket);
                    238:                        InChannel = fdopen(t, "r");
                    239:                        OutChannel = fdopen(dup(t), "w");
                    240:                        if (tTd(15, 2))
                    241:                                printf("getreq: returning\n");
                    242: # ifdef LOG
                    243:                        if (LogLevel > 11)
                    244:                                syslog(LOG_DEBUG, "connected, pid=%d", getpid());
                    245: # endif LOG
                    246:                        return;
                    247:                }
                    248: 
                    249:                /* close the port so that others will hang (for a while) */
                    250:                (void) close(t);
                    251:        }
                    252:        /*NOTREACHED*/
                    253: }
                    254: /*
                    255: **  CLRDAEMON -- reset the daemon connection
                    256: **
                    257: **     Parameters:
                    258: **             none.
                    259: **
                    260: **     Returns:
                    261: **             none.
                    262: **
                    263: **     Side Effects:
                    264: **             releases any resources used by the passive daemon.
                    265: */
                    266: 
                    267: clrdaemon()
                    268: {
                    269:        if (DaemonSocket >= 0)
                    270:                (void) close(DaemonSocket);
                    271:        DaemonSocket = -1;
                    272: }
                    273: /*
                    274: **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
                    275: **
                    276: **     Parameters:
                    277: **             host -- the name of the host.
                    278: **             port -- the port number to connect to.
                    279: **             outfile -- a pointer to a place to put the outfile
                    280: **                     descriptor.
                    281: **             infile -- ditto for infile.
                    282: **
                    283: **     Returns:
                    284: **             An exit code telling whether the connection could be
                    285: **                     made and if not why not.
                    286: **
                    287: **     Side Effects:
                    288: **             none.
                    289: */
                    290: 
                    291: makeconnection(host, port, outfile, infile)
                    292:        char *host;
                    293:        u_short port;
                    294:        FILE **outfile;
                    295:        FILE **infile;
                    296: {
                    297:        register int i, s;
                    298:        register struct hostent *hp = (struct hostent *)NULL;
                    299:        extern char *inet_ntoa();
                    300:        int sav_errno;
                    301: #ifdef NAMED_BIND
                    302:        extern int h_errno;
                    303: #endif
                    304: 
                    305:        /*
                    306:        **  Set up the address for the mailer.
                    307:        **      Accept "[a.b.c.d]" syntax for host name.
                    308:        */
                    309: 
                    310: #ifdef NAMED_BIND
                    311:        h_errno = 0;
                    312: #endif
                    313:        errno = 0;
                    314: 
                    315:        if (host[0] == '[')
                    316:        {
                    317:                long hid;
                    318:                register char *p = index(host, ']');
                    319: 
                    320:                if (p != NULL)
                    321:                {
                    322:                        *p = '\0';
                    323:                        hid = inet_addr(&host[1]);
                    324:                        *p = ']';
                    325:                }
                    326:                if (p == NULL || hid == -1)
                    327:                {
                    328:                        usrerr("Invalid numeric domain spec \"%s\"", host);
                    329:                        return (EX_NOHOST);
                    330:                }
                    331:                SendmailAddress.sin_addr.s_addr = hid;
                    332:        }
                    333:        else
                    334:        {
                    335:                hp = gethostbyname(host);
                    336:                if (hp == NULL)
                    337:                {
                    338: #ifdef NAMED_BIND
                    339:                        if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
                    340:                                return (EX_TEMPFAIL);
                    341: 
                    342:                        /* if name server is specified, assume temp fail */
                    343:                        if (errno == ECONNREFUSED && UseNameServer)
                    344:                                return (EX_TEMPFAIL);
                    345: #endif
                    346: 
                    347:                        /*
                    348:                        **  XXX Should look for mail forwarder record here
                    349:                        **  XXX if (h_errno == NO_ADDRESS).
                    350:                        */
                    351: 
                    352:                        return (EX_NOHOST);
                    353:                }
                    354:                bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length);
                    355:                i = 1;
                    356:        }
                    357: 
                    358:        /*
                    359:        **  Determine the port number.
                    360:        */
                    361: 
                    362:        if (port != 0)
                    363:                SendmailAddress.sin_port = htons(port);
                    364:        else
                    365:        {
                    366:                register struct servent *sp = getservbyname("smtp", "tcp");
                    367: 
                    368:                if (sp == NULL)
                    369:                {
                    370:                        syserr("makeconnection: server \"smtp\" unknown");
                    371:                        return (EX_OSFILE);
                    372:                }
                    373:                SendmailAddress.sin_port = sp->s_port;
                    374:        }
                    375: 
                    376:        /*
                    377:        **  Try to actually open the connection.
                    378:        */
                    379: 
                    380: again:
                    381:        if (tTd(16, 1))
                    382:                printf("makeconnection (%s [%s])\n", host,
                    383:                    inet_ntoa(SendmailAddress.sin_addr.s_addr));
                    384: 
                    385:        s = socket(AF_INET, SOCK_STREAM, 0);
                    386:        if (s < 0)
                    387:        {
                    388:                syserr("makeconnection: no socket");
                    389:                sav_errno = errno;
                    390:                goto failure;
                    391:        }
                    392: 
                    393:        if (tTd(16, 1))
                    394:                printf("makeconnection: %d\n", s);
                    395: 
                    396:        /* turn on network debugging? */
                    397:        if (tTd(16, 14))
                    398:        {
                    399:                int on = 1;
                    400:                (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
                    401:        }
                    402:        if (CurEnv->e_xfp != NULL)
                    403:                (void) fflush(CurEnv->e_xfp);           /* for debugging */
                    404:        errno = 0;                                      /* for debugging */
                    405:        SendmailAddress.sin_family = AF_INET;
                    406:        if (connect(s, &SendmailAddress, sizeof SendmailAddress) < 0)
                    407:        {
                    408:                sav_errno = errno;
                    409:                (void) close(s);
                    410:                if (hp && hp->h_addr_list[i])
                    411:                {
                    412:                        bcopy(hp->h_addr_list[i++],
                    413:                            (char *)&SendmailAddress.sin_addr, hp->h_length);
                    414:                        goto again;
                    415:                }
                    416: 
                    417:                /* failure, decide if temporary or not */
                    418:        failure:
                    419:                switch (sav_errno)
                    420:                {
                    421:                  case EISCONN:
                    422:                  case ETIMEDOUT:
                    423:                  case EINPROGRESS:
                    424:                  case EALREADY:
                    425:                  case EADDRINUSE:
                    426:                  case EHOSTDOWN:
                    427:                  case ENETDOWN:
                    428:                  case ENETRESET:
                    429:                  case ENOBUFS:
                    430:                  case ECONNREFUSED:
                    431:                  case ECONNRESET:
                    432:                  case EHOSTUNREACH:
                    433:                  case ENETUNREACH:
                    434:                        /* there are others, I'm sure..... */
                    435:                        return (EX_TEMPFAIL);
                    436: 
                    437:                  case EPERM:
                    438:                        /* why is this happening? */
                    439:                        syserr("makeconnection: funny failure, addr=%lx, port=%x",
                    440:                                SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
                    441:                        return (EX_TEMPFAIL);
                    442: 
                    443:                  default:
                    444:                        {
                    445:                                extern char *errstring();
                    446: 
                    447:                                message(Arpa_Info, "%s", errstring(sav_errno));
                    448:                                return (EX_UNAVAILABLE);
                    449:                        }
                    450:                }
                    451:        }
                    452: 
                    453:        /* connection ok, put it into canonical form */
                    454:        *outfile = fdopen(s, "w");
                    455:        *infile = fdopen(dup(s), "r");
                    456: 
                    457:        return (EX_OK);
                    458: }
                    459: /*
                    460: **  MYHOSTNAME -- return the name of this host.
                    461: **
                    462: **     Parameters:
                    463: **             hostbuf -- a place to return the name of this host.
                    464: **             size -- the size of hostbuf.
                    465: **
                    466: **     Returns:
                    467: **             A list of aliases for this host.
                    468: **
                    469: **     Side Effects:
                    470: **             none.
                    471: */
                    472: 
                    473: char **
                    474: myhostname(hostbuf, size)
                    475:        char hostbuf[];
                    476:        int size;
                    477: {
                    478:        extern struct hostent *gethostbyname();
                    479:        struct hostent *hp;
                    480: 
                    481:        if (gethostname(hostbuf, size) < 0)
                    482:        {
                    483:                (void) strcpy(hostbuf, "localhost");
                    484:        }
                    485:        hp = gethostbyname(hostbuf);
                    486:        if (hp != NULL)
                    487:        {
                    488:                (void) strcpy(hostbuf, hp->h_name);
                    489:                return (hp->h_aliases);
                    490:        }
                    491:        else
                    492:                return (NULL);
                    493: }
                    494: 
                    495: /*
                    496:  *  MAPHOSTNAME -- turn a hostname into canonical form
                    497:  *
                    498:  *     Parameters:
                    499:  *             hbuf -- a buffer containing a hostname.
                    500:  *             hbsize -- the size of hbuf.
                    501:  *
                    502:  *     Returns:
                    503:  *             none.
                    504:  *
                    505:  *     Side Effects:
                    506:  *             Looks up the host specified in hbuf.  If it is not
                    507:  *             the canonical name for that host, replace it with
                    508:  *             the canonical name.  If the name is unknown, or it
                    509:  *             is already the canonical name, leave it unchanged.
                    510:  */
                    511: maphostname(hbuf, hbsize)
                    512:        char *hbuf;
                    513:        int hbsize;
                    514: {
                    515:        register struct hostent *hp;
                    516:        u_long in_addr;
                    517:        char ptr[256], *cp;
                    518:        struct hostent *gethostbyaddr();
                    519: 
                    520:        /*
                    521:         * If first character is a bracket, then it is an address
                    522:         * lookup.  Address is copied into a temporary buffer to
                    523:         * strip the brackets and to preserve hbuf if address is
                    524:         * unknown.
                    525:         */
                    526:        if (*hbuf != '[') {
                    527:                getcanonname(hbuf, hbsize);
                    528:                return;
                    529:        }
                    530:        if ((cp = index(strcpy(ptr, hbuf), ']')) == NULL)
                    531:                return;
                    532:        *cp = '\0';
                    533:        in_addr = inet_addr(&ptr[1]);
                    534:        hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
                    535:        if (hp == NULL)
                    536:                return;
                    537:        if (strlen(hp->h_name) >= hbsize)
                    538:                hp->h_name[hbsize - 1] = '\0';
                    539:        (void)strcpy(hbuf, hp->h_name);
                    540: }
                    541: 
                    542: # else DAEMON
                    543: /* code for systems without sophisticated networking */
                    544: 
                    545: /*
                    546: **  MYHOSTNAME -- stub version for case of no daemon code.
                    547: **
                    548: **     Can't convert to upper case here because might be a UUCP name.
                    549: **
                    550: **     Mark, you can change this to be anything you want......
                    551: */
                    552: 
                    553: char **
                    554: myhostname(hostbuf, size)
                    555:        char hostbuf[];
                    556:        int size;
                    557: {
                    558:        register FILE *f;
                    559: 
                    560:        hostbuf[0] = '\0';
                    561:        f = fopen("/usr/include/whoami", "r");
                    562:        if (f != NULL)
                    563:        {
                    564:                (void) fgets(hostbuf, size, f);
                    565:                fixcrlf(hostbuf, TRUE);
                    566:                (void) fclose(f);
                    567:        }
                    568:        return (NULL);
                    569: }
                    570: /*
                    571: **  MAPHOSTNAME -- turn a hostname into canonical form
                    572: **
                    573: **     Parameters:
                    574: **             hbuf -- a buffer containing a hostname.
                    575: **             hbsize -- the size of hbuf.
                    576: **
                    577: **     Returns:
                    578: **             none.
                    579: **
                    580: **     Side Effects:
                    581: **             Looks up the host specified in hbuf.  If it is not
                    582: **             the canonical name for that host, replace it with
                    583: **             the canonical name.  If the name is unknown, or it
                    584: **             is already the canonical name, leave it unchanged.
                    585: */
                    586: 
                    587: /*ARGSUSED*/
                    588: maphostname(hbuf, hbsize)
                    589:        char *hbuf;
                    590:        int hbsize;
                    591: {
                    592:        return;
                    593: }
                    594: 
                    595: #endif DAEMON

unix.superglobalmegacorp.com

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