Annotation of 43BSDReno/contrib/mh/support/pop/smtpd.c, revision 1.1.1.1

1.1       root        1: /* smtpd.c - the stub SMTP server for POP client hosts */
                      2: 
                      3: 
                      4: /* Author:     Marshall T. Rose        <MRose@NRTC>    (MTR)
                      5:                Northrop Research and Technology Center
                      6:                One Research park
                      7:                Palos Verdes Peninsula, CA  90274
                      8:                213/377-4811
                      9: 
                     10:    Date:       Wed May 15 00:04:12 1985
                     11:  */
                     12: 
                     13: #include <errno.h>
                     14: #include <signal.h>
                     15: #include <stdio.h>
                     16: #include <strings.h>
                     17: #include <syslog.h>
                     18: #include <sys/types.h>
                     19: #include <sys/file.h>
                     20: #include <sys/ioctl.h>
                     21: #include <sys/socket.h>
                     22: #include <sys/wait.h>
                     23: #include <netinet/in.h>
                     24: #include <netdb.h>
                     25: #include <arpa/inet.h>
                     26: 
                     27: 
                     28: #define        NOTOK   (-1)
                     29: #define        OK      0
                     30: 
                     31: /*  */
                     32: 
                     33: extern int  errno;
                     34: extern char *sys_siglist[];
                     35: 
                     36: 
                     37: int  debug = 0;
                     38: static int  nbits = ((sizeof (int)) * 8);
                     39: static int  options = 0;
                     40: 
                     41: 
                     42: char *myname = "smtpd";
                     43: char myhost[BUFSIZ];
                     44: static char *myprotocol = "tcp";
                     45: static char *myservice = "smtp";
                     46: 
                     47: static struct sockaddr_in   in_socket;
                     48: static struct sockaddr_in  *isock = &in_socket;
                     49: 
                     50: static char *smtphost;
                     51: static struct sockaddr_in   sm_socket;
                     52: static struct sockaddr_in  *msock = &sm_socket;
                     53: 
                     54: 
                     55: void   chldser ();
                     56: void   adios (), advise ();
                     57: 
                     58: /*  */
                     59: 
                     60: /* ARGSUSED */
                     61: 
                     62: main (argc, argv, envp)
                     63: int     argc;
                     64: char  **argv,
                     65:       **envp;
                     66: {
                     67:     int     fd,
                     68:             sd;
                     69:     struct servent *sp;
                     70:     struct sockaddr_in  out_socket,
                     71:                        *osock = &out_socket;
                     72: 
                     73:     if ((sp = getservbyname (myservice, myprotocol)) == NULL)
                     74:        adios (NULL, "%s/%s: unknown service", myprotocol, myservice);
                     75:     isock -> sin_family = AF_INET;
                     76:     isock -> sin_port = sp -> s_port;
                     77:     isock -> sin_addr.s_addr = INADDR_ANY;
                     78:     arginit (argv);
                     79:     envinit ();
                     80:     msock -> sin_port = isock -> sin_port;
                     81: 
                     82: #ifdef RESTART
                     83:     for (;;) {
                     84:        char    reason[BUFSIZ];
                     85:        union wait status;
                     86: 
                     87:        switch (fork ()) {
                     88:            case NOTOK: 
                     89:                sleep (5);
                     90:                continue;
                     91: 
                     92:            case OK: 
                     93:                break;
                     94: 
                     95:            default: 
                     96:                sleep (60);
                     97:                (void) wait3 (&status, 0, NULL);
                     98:                if (WIFEXITED (status))
                     99:                    (void) sprintf (reason, "exit=0%o", status.w_retcode);
                    100:                else
                    101:                    if (WIFSIGNALED (status))
                    102:                        (void) sprintf (reason, "signal=%s%s",
                    103:                                status.w_termsig < NSIG
                    104:                                ? sys_siglist[status.w_termsig] : "unknown",
                    105:                                status.w_coredump ? " (core dumped)" : NULL);
                    106:                    else
                    107:                        (void) strcpy (reason, "stopped(!!)");
                    108:                advise (NULL, LOG_WARNING, "%s/%s server has terminated -- %s",
                    109:                        sp -> s_proto, sp -> s_name, reason);
                    110:                continue;
                    111:        }
                    112:        break;
                    113:     }
                    114: 
                    115:     closelog ();
                    116:     openlog (myname, LOG_PID);
                    117:     advise (NULL, LOG_INFO, "restart");
                    118: #endif RESTART
                    119: 
                    120: /*  */
                    121: 
                    122:     if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
                    123:        adios ("socket", "unable to create");
                    124:     if (options & SO_DEBUG)
                    125:        if (setsockopt (sd, SOL_SOCKET, SO_DEBUG, NULL, 0) == NOTOK)
                    126:            advise ("SO_DEBUG", LOG_WARNING, "unable to set socket option");
                    127:     if (setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, NULL, 0) == NOTOK)
                    128:        advise ("SO_KEEPALIVE", LOG_WARNING, "unable to set socket option");
                    129:     if (bind (sd, isock, sizeof *isock) == NOTOK)
                    130:        adios ("socket", "unable to bind");
                    131: 
                    132:     (void) signal (SIGCHLD, chldser);
                    133:     (void) listen (sd, SOMAXCONN);
                    134:     for (;;) {
                    135:        int     i = sizeof *osock;
                    136: 
                    137:        if ((fd = accept (sd, osock, &i)) == NOTOK) {
                    138:            if (errno != EINTR)
                    139:                advise ("socket", LOG_WARNING,
                    140:                    "unable to accept connection on");
                    141:            continue;
                    142:        }
                    143:        switch (fork ()) {
                    144:            case OK: 
                    145:                (void) close (sd);
                    146:                (void) signal (SIGCHLD, SIG_DFL);
                    147:                server (fd, osock);
                    148:                _exit (0);
                    149: 
                    150:            case NOTOK: 
                    151:                advise ("socket", LOG_WARNING,
                    152:                    "no forks, so rejecting connection on");
                    153:            default: 
                    154:                (void) close (fd);
                    155:        }
                    156:     }
                    157: }
                    158: 
                    159: /*  */
                    160: 
                    161: static server (fd, sin)
                    162: int    fd;
                    163: struct sockaddr_in *sin;
                    164: {
                    165:     int     sd;
                    166:     u_short port;
                    167:     char    buffer[BUFSIZ];
                    168:     struct hostent *hp;
                    169:     struct in_addr *addr;
                    170: 
                    171:     closelog ();
                    172:     openlog (myname, LOG_PID);
                    173:     port = ntohs (sin -> sin_port);
                    174:     addr = &sin -> sin_addr;
                    175:     advise (NULL, LOG_INFO, "servicing %s/%d",
                    176:            (hp = gethostbyaddr (addr, sizeof *addr, sin -> sin_family))
                    177:            ? hp -> h_name : inet_ntoa (*addr), port);
                    178: 
                    179:     if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK
                    180:            || connect (sd, msock, sizeof *msock) == NOTOK) {
                    181:        advise (smtphost, LOG_WARNING,
                    182:                sd != NOTOK ? "unable to connect to" : "socket failed for");
                    183:        sprintf (buffer, "451 No %s/%s service available, try %s--%s\r\n",
                    184:                myprotocol, myservice, smtphost, "you might get lucky");
                    185:        write (fd, buffer, strlen (buffer));
                    186:        return;
                    187:     }
                    188: 
                    189:     advise (NULL, LOG_INFO, "connected to %s", smtphost);
                    190:     shuffle (fd, sd);
                    191: }
                    192: 
                    193: /*  */
                    194: 
                    195: shuffle (fd, sd)
                    196: int    fd,
                    197:        sd;
                    198: {
                    199:     int     cc,
                    200:             ibits,
                    201:             obits,
                    202:             on,
                    203:             scc,
                    204:             fcc;
                    205:     char   *sbp,
                    206:             sibuf[BUFSIZ],
                    207:            *fbp,
                    208:             fibuf[BUFSIZ];
                    209: 
                    210:     on = 1;
                    211:     ioctl (fd, FIONBIO, &on);
                    212:     ioctl (sd, FIONBIO, &on);
                    213: 
                    214:     for (fcc = scc = 0;;) {
                    215:        ibits = obits = 0;
                    216:        if (fcc)
                    217:            obits |= 1 << sd;
                    218:        else
                    219:            ibits |= 1 << fd;
                    220:        if (scc)
                    221:            obits |= 1 << fd;
                    222:        else
                    223:            ibits |= 1 << sd;
                    224:        if (fcc < 0 && scc < 0)
                    225:            break;
                    226: 
                    227:        select (nbits, &ibits, &obits, NULL, NULL);
                    228: 
                    229:        if (ibits == 0 && obits == 0) {
                    230:            sleep (5);
                    231:            continue;
                    232:        }
                    233: 
                    234:        if (ibits & (1 << fd)) {
                    235:            fcc = read (fd, fibuf, sizeof fibuf);
                    236:            if (fcc < 0 && errno == EWOULDBLOCK)
                    237:                fcc = 0;
                    238:            else {
                    239:                if (fcc <= 0)
                    240:                    break;
                    241:                fbp = fibuf;
                    242:            }
                    243:        }
                    244:        if (ibits & (1 << sd)) {
                    245:            scc = read (sd, sibuf, sizeof sibuf);
                    246:            if (scc < 0 && errno == EWOULDBLOCK)
                    247:                scc = 0;
                    248:            else {
                    249:                if (scc <= 0)
                    250:                    break;
                    251:                sbp = sibuf;
                    252:            }
                    253:        }
                    254: 
                    255:        if ((obits & (1 << fd)) && scc > 0) {
                    256:            cc = write (fd, sbp, scc);
                    257:            if (cc > 0)
                    258:                scc -= cc, sbp += cc;
                    259:        }
                    260:        if ((obits & (1 << sd)) && fcc > 0) {
                    261:            cc = write (sd, fbp, fcc);
                    262:            if (cc > 0)
                    263:                fcc -= cc, fbp += cc;
                    264:        }
                    265:     }
                    266: 
                    267:     advise (NULL, LOG_INFO, "terminating: fcc=%d scc=%d errno=%d",
                    268:            fcc, scc, errno);
                    269: }
                    270: 
                    271: /*  */
                    272: 
                    273: /* set options and isock -> sin_port here... */
                    274: 
                    275: static arginit (vec)
                    276: char   **vec;
                    277: {
                    278:     struct hostent *hp;
                    279: 
                    280:     if (myname = rindex (*vec, '/'))
                    281:        myname++;
                    282:     if (myname == NULL || *myname == NULL)
                    283:        myname = *vec;
                    284: 
                    285:     (void) gethostname (myhost, sizeof myhost);
                    286:     if (hp = gethostbyname (myhost))
                    287:        (void) strcpy (myhost, hp -> h_name);
                    288:     nbits = getdtablesize ();
                    289: 
                    290:     if ((smtphost = *++vec) == NULL)
                    291:        adios (NULL, "usage: %s server-host", myname);
                    292:     if ((hp = gethostbyname (smtphost)) == NULL)
                    293:        adios (NULL," %s: unknown host");
                    294:     bzero ((char *) msock, sizeof *msock);
                    295:     msock -> sin_family = hp -> h_addrtype;
                    296:     bcopy (hp -> h_addr, (char *) &msock -> sin_addr, hp -> h_length);
                    297: }
                    298: 
                    299: /*  */
                    300: 
                    301: static  envinit () {
                    302:     int     i,
                    303:             sd;
                    304: 
                    305:     if (!(debug = isatty (2))) {
                    306:        for (i = 0; i < 5; i++) {
                    307:            switch (fork ()) {
                    308:                case NOTOK: 
                    309:                    sleep (5);
                    310:                    continue;
                    311: 
                    312:                case OK: 
                    313:                    break;
                    314: 
                    315:                default: 
                    316:                    _exit (0);
                    317:            }
                    318:            break;
                    319:        }
                    320: 
                    321:        (void) chdir ("/");
                    322: 
                    323:        if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
                    324:            adios ("/dev/null", "unable to read");
                    325:        if (sd != 0)
                    326:            (void) dup2 (sd, 0), (void) close (sd);
                    327:        (void) dup2 (0, 1);
                    328:        (void) dup2 (0, 2);
                    329: 
                    330:        if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
                    331:            (void) ioctl (sd, TIOCNOTTY, NULL);
                    332:            (void) close (sd);
                    333:        }
                    334:     }
                    335: 
                    336:     for (sd = 3; sd < nbits; sd++)
                    337:        (void) close (sd);
                    338: 
                    339:     (void) signal (SIGPIPE, SIG_IGN);
                    340: 
                    341:     openlog (myname, LOG_PID);
                    342:     advise (NULL, LOG_INFO, "starting");
                    343: }
                    344: 
                    345: /*  */
                    346: 
                    347: /* ARGSUSED */
                    348: 
                    349: static void chldser (sig, code, sc)
                    350: int    sig;
                    351: long    code;
                    352: struct sigcontext *sc;
                    353: {
                    354:     union wait status;
                    355: 
                    356:     while (wait3 (&status, WNOHANG, NULL) > 0)
                    357:        continue;
                    358: }
                    359: 
                    360: /*  */
                    361: 
                    362: /* VARARGS */
                    363: 
                    364: void   adios (what, fmt, a, b, c, d)
                    365: char   *what,
                    366:        *fmt,
                    367:        *a,
                    368:        *b,
                    369:        *c,
                    370:        *d;
                    371: {
                    372:     advise (what, LOG_SALERT, fmt, a, b, c, d);
                    373:     _exit (1);
                    374: }
                    375: 
                    376: 
                    377: /* VARARGS */
                    378: 
                    379: void   advise (what, code, fmt, a, b, c, d)
                    380: char   *what,
                    381:        *fmt,
                    382:        *a,
                    383:        *b,
                    384:        *c,
                    385:        *d;
                    386: int    code;
                    387: {
                    388:     char    buffer[BUFSIZ];
                    389: 
                    390:     if (what) {
                    391:        sprintf (buffer, fmt, a, b, c, d);
                    392:        syslog (code, "%s %s: %m", buffer, what);
                    393:     }
                    394:     else
                    395:        syslog (code, fmt, a, b, c, d);
                    396: 
                    397:     if (debug) {
                    398:        fprintf (stderr, "[%d] ", code);
                    399:        fprintf (stderr, fmt, a, b, c, d);
                    400:        if (what)
                    401:            (void) fputc (' ', stderr), perror (what);
                    402:        else
                    403:            (void) fputc ('\n', stderr);
                    404:        (void) fflush (stderr);
                    405:     }
                    406: }

unix.superglobalmegacorp.com

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