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: }

Defined functions

adios defined in line 364; used 7 times
advise defined in line 379; used 13 times
arginit defined in line 275; used 1 times
  • in line 78
chldser defined in line 349; used 2 times
envinit defined in line 301; used 1 times
  • in line 79
main defined in line 62; never used
server defined in line 161; used 1 times
shuffle defined in line 195; used 1 times

Defined variables

debug defined in line 37; used 2 times
in_socket defined in line 47; used 1 times
  • in line 48
isock defined in line 48; used 6 times
msock defined in line 52; used 7 times
myhost defined in line 43; used 4 times
myname defined in line 42; used 9 times
myprotocol defined in line 44; used 3 times
myservice defined in line 45; used 3 times
nbits defined in line 38; used 3 times
options defined in line 39; used 1 times
sm_socket defined in line 51; used 1 times
  • in line 52
smtphost defined in line 50; used 5 times

Defined macros

NOTOK defined in line 28; used 10 times
OK defined in line 29; never used
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1570
Valid CSS Valid XHTML 1.0 Strict