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