|
|
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.