|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.