|
|
1.1 root 1: # include <errno.h>
2: # include "sendmail.h"
3:
4: #ifndef DAEMON
5: SCCSID(@(#)4.1a_daemon.c 3.35+ 12/5/82 (w/o daemon mode));
6: #else
7:
8: # include <sys/socket.h>
9: # include <net/in.h>
10: # include <wait.h>
11:
12: SCCSID(@(#)4.1a_daemon.c 3.35+ 12/5/82 (with daemon mode));
13:
14: /*
15: ** DAEMON.C -- routines to use when running as a daemon.
16: **
17: ** 4.1a BSD version -- this version is not well supported.
18: **
19: ** This entire file is highly dependent on the 4.1a BSD
20: ** interprocess communication primitives. No attempt has
21: ** been made to make this file portable to Version 7,
22: ** Version 6, MPX files, etc. If you should try such a
23: ** thing yourself, I recommend chucking the entire file
24: ** and starting from scratch. Basic semantics are:
25: **
26: ** getrequests()
27: ** Opens a port and initiates a connection.
28: ** Returns in a child. Must set InChannel and
29: ** OutChannel appropriately.
30: ** makeconnection(host, port, outfile, infile)
31: ** Make a connection to the named host on the given
32: ** port. Set *outfile and *infile to the files
33: ** appropriate for communication. Returns zero on
34: ** success, else an exit status describing the
35: ** error.
36: **
37: ** The semantics of both of these should be clean.
38: */
39: /*
40: ** GETREQUESTS -- open mail IPC port and get requests.
41: **
42: ** Parameters:
43: ** none.
44: **
45: ** Returns:
46: ** none.
47: **
48: ** Side Effects:
49: ** Waits until some interesting activity occurs. When
50: ** it does, a child is created to process it, and the
51: ** parent waits for completion. Return from this
52: ** routine is always in the child.
53: */
54:
55: getrequests()
56: {
57: union wait status;
58:
59: for (;;)
60: {
61: register int pid;
62: register int port;
63:
64: /*
65: ** Wait for a connection.
66: */
67:
68: while ((port = getconnection()) < 0)
69: {
70: # ifdef LOG
71: if (LogLevel > 0)
72: syslog(LOG_SALERT, "cannot get connection");
73: # endif LOG
74: finis();
75: }
76:
77: /*
78: ** Create a subprocess to process the mail.
79: */
80:
81: # ifdef DEBUG
82: if (tTd(15, 2))
83: printf("getrequests: forking (port = %d)\n", port);
84: # endif DEBUG
85:
86: pid = fork();
87: if (pid < 0)
88: {
89: syserr("daemon: cannot fork");
90: sleep(10);
91: (void) close(port);
92: continue;
93: }
94:
95: if (pid == 0)
96: {
97: /*
98: ** CHILD -- return to caller.
99: ** Verify calling user id if possible here.
100: */
101:
102: InChannel = fdopen(port, "r");
103: OutChannel = fdopen(port, "w");
104: # ifdef DEBUG
105: if (tTd(15, 2))
106: printf("getreq: returning\n");
107: # endif DEBUG
108: # ifdef LOG
109: if (LogLevel > 11)
110: syslog(LOG_DEBUG, "connected, pid=%d", getpid());
111: # endif LOG
112: return;
113: }
114:
115: /*
116: ** PARENT -- wait for child to terminate.
117: ** Perhaps we should allow concurrent processing?
118: */
119:
120: # ifdef DEBUG
121: if (tTd(15, 2))
122: {
123: sleep(2);
124: printf("getreq: parent waiting\n");
125: }
126: # endif DEBUG
127:
128: /* close the port so that others will hang (for a while) */
129: (void) close(port);
130:
131: /* pick up old zombies; implement load limiting */
132: while (wait3(&status, WNOHANG, 0) > 0)
133: continue;
134: }
135: }
136: /*
137: ** GETCONNECTION -- make a connection with the outside world
138: **
139: ** This routine is horribly contorted to try to get around a bunch
140: ** of 4.1a IPC bugs. There appears to be nothing we can do to make
141: ** it "right" -- the code to interrupt accepts just doesn't work
142: ** right. However, this is an attempt to minimize the probablity
143: ** of problems.
144: **
145: ** Parameters:
146: ** none.
147: **
148: ** Returns:
149: ** The port for mail traffic.
150: **
151: ** Side Effects:
152: ** Waits for a connection.
153: */
154:
155: #define IPPORT_PLAYPORT 3055 /* random number */
156:
157: struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP };
158:
159: getconnection()
160: {
161: int s;
162: #ifdef NVMUNIX
163: int t;
164: #endif NVMUNIX
165: struct sockaddr otherend;
166:
167: /*
168: ** Set up the address for the mailer.
169: */
170:
171: SendmailAddress.sin_addr.s_addr = 0;
172: SendmailAddress.sin_port = IPPORT_SMTP;
173: # ifdef DEBUG
174: if (tTd(15, 15))
175: SendmailAddress.sin_port = IPPORT_PLAYPORT;
176: # endif DEBUG
177: SendmailAddress.sin_port = htons(SendmailAddress.sin_port);
178:
179: /*
180: ** Try to actually open the connection.
181: */
182:
183: # ifdef DEBUG
184: if (tTd(15, 1))
185: printf("getconnection\n");
186: # endif DEBUG
187:
188: for (;; sleep(15))
189: {
190: int i;
191:
192: /* get a socket for the SMTP connection */
193: #ifdef NVMUNIX
194: s = socket(AF_INET, SOCK_STREAM, 0, 0);
195: bind(s, &SendmailAddress, sizeof SendmailAddress, 0);
196: listen(s, 10);
197: #else NVMUNIX
198: /* do loop is to avoid 4.1b kernel bug (?) */
199: i = 60;
200: do
201: {
202: s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN);
203: if (s < 0)
204: sleep(10);
205: } while (--i > 0 && s < 0);
206: #endif NVMUNIX
207: if (s < 0)
208: {
209: /* probably another daemon already */
210: syserr("getconnection: can't create socket");
211: return (-1);
212: }
213:
214: # ifdef DEBUG
215: if (tTd(15, 1))
216: printf("getconnection: %d\n", s);
217: # endif DEBUG
218:
219: /* wait for a connection */
220: do
221: {
222: errno = 0;
223: #ifdef NVMUNIX
224: lotherend = sizeof otherend;
225: t = accept(s, &otherend, &lotherend, 0);
226: if (t >= 0)
227: return (t);
228: #else NVMUNIX
229: if (accept(s, &otherend) >= 0)
230: return (s);
231: #endif NVMUNIX
232: } while (errno == EINTR);
233: syserr("getconnection: accept");
234: sleep(5);
235: (void) close(s);
236: }
237: }
238: /*
239: ** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
240: **
241: ** Parameters:
242: ** host -- the name of the host.
243: ** port -- the port number to connect to.
244: ** outfile -- a pointer to a place to put the outfile
245: ** descriptor.
246: ** infile -- ditto for infile.
247: **
248: ** Returns:
249: ** An exit code telling whether the connection could be
250: ** made and if not why not.
251: **
252: ** Side Effects:
253: ** none.
254: */
255:
256: makeconnection(host, port, outfile, infile)
257: char *host;
258: u_short port;
259: FILE **outfile;
260: FILE **infile;
261: {
262: register int s;
263:
264: /*
265: ** Set up the address for the mailer.
266: ** Accept "[a.b.c.d]" syntax for host name.
267: */
268:
269: if (host[0] == '[')
270: {
271: long hid = 0;
272: int i, j;
273: register char *p = host;
274:
275: for (i = 3; i >= 0 && *p != ']' && *p != '\0'; i--)
276: {
277: j = 0;
278: while (isdigit(*++p))
279: j = j * 10 + (*p - '0');
280: if (*p != (i == 0 ? ']' : '.') || j > 255 || j < 0)
281: break;
282: hid |= j << ((3 - i) * 8);
283: }
284: if (i >= 0 || *p != ']' || *++p != '\0')
285: {
286: usrerr("Invalid numeric domain spec \"%s\"", host);
287: return (EX_NOHOST);
288: }
289: SendmailAddress.sin_addr.s_addr = hid;
290: }
291: else if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1)
292: return (EX_NOHOST);
293: if (port == 0)
294: port = IPPORT_SMTP;
295: SendmailAddress.sin_port = htons(port);
296:
297: /*
298: ** Try to actually open the connection.
299: */
300:
301: # ifdef DEBUG
302: if (tTd(16, 1))
303: printf("makeconnection (%s)\n", host);
304: # endif DEBUG
305:
306: #ifdef NVMUNIX
307: s = socket(AF_INET, SOCK_STREAM, 0, 0);
308: #else NVMUNIX
309: s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0);
310: #endif NVMUNIX
311: if (s < 0)
312: {
313: syserr("makeconnection: no socket");
314: goto failure;
315: }
316:
317: # ifdef DEBUG
318: if (tTd(16, 1))
319: printf("makeconnection: %d\n", s);
320: # endif DEBUG
321: (void) fflush(CurEnv->e_xfp); /* for debugging */
322: #ifdef NVMUNIX
323: bind(s, &SendmailAddress, sizeof SendmailAddress, 0);
324: if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0)
325: #else NVMUNIX
326: if (connect(s, &SendmailAddress) < 0)
327: #endif NVMUNIX
328: {
329: /* failure, decide if temporary or not */
330: failure:
331: switch (errno)
332: {
333: case EISCONN:
334: case ETIMEDOUT:
335: case EINPROGRESS:
336: case EALREADY:
337: case EADDRINUSE:
338: case ENETDOWN:
339: case ENETRESET:
340: case ENOBUFS:
341: case ECONNREFUSED:
342: /* there are others, I'm sure..... */
343: return (EX_TEMPFAIL);
344:
345: default:
346: return (EX_UNAVAILABLE);
347: }
348: }
349:
350: /* connection ok, put it into canonical form */
351: *outfile = fdopen(s, "w");
352: *infile = fdopen(s, "r");
353:
354: return (0);
355: }
356:
357: /*
358: ** MYHOSTNAME -- return the name of this host.
359: **
360: ** Parameters:
361: ** hostbuf -- a place to return the name of this host.
362: ** size -- the size of hostbuf.
363: **
364: ** Returns:
365: ** A list of aliases for this host.
366: ** NULL if it can't find an alias list.
367: **
368: ** Side Effects:
369: ** none.
370: */
371:
372: char **
373: myhostname(hostbuf, size)
374: char hostbuf[];
375: int size;
376: {
377: register char *p;
378:
379: gethostname(hostbuf, size);
380: for (p = hostbuf; *p != '\0'; p++)
381: if (islower(*p))
382: *p -= 'a' - 'A';
383:
384: /* now where would we find an alias list? */
385: return (NULL);
386: }
387:
388: # else DAEMON
389:
390: /*
391: ** MYHOSTNAME -- stub version for case of no daemon code.
392: **
393: ** Can't convert to upper case here because might be a UUCP name.
394: */
395:
396: char **
397: myhostname(hostbuf, size)
398: char hostbuf[];
399: int size;
400: {
401: register FILE *f;
402:
403: hostbuf[0] = '\0';
404: f = fopen("/usr/include/whoami", "r");
405: if (f != NULL)
406: {
407: (void) fgets(hostbuf, size, f);
408: fixcrlf(hostbuf, TRUE);
409: (void) fclose(f);
410: }
411: return (NULL);
412: }
413:
414: #endif DAEMON
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.