Annotation of 43BSD/usr.lib/sendmail/src/daemon.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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