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