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

unix.superglobalmegacorp.com

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