|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Eric P. Allman
3: * Copyright (c) 1988 Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms are permitted provided
7: * that: (1) source distributions retain this entire copyright notice and
8: * comment, and (2) distributions including binaries display the following
9: * acknowledgement: ``This product includes software developed by the
10: * University of California, Berkeley and its contributors'' in the
11: * documentation or other materials provided with the distribution and in
12: * all advertising materials mentioning features or use of this software.
13: * Neither the name of the University nor the names of its contributors may
14: * be used to endorse or promote products derived from this software without
15: * specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: */
20:
21: #include <errno.h>
22: #include "sendmail.h"
23:
24: #ifndef lint
25: #ifdef DAEMON
26: static char sccsid[] = "@(#)daemon.c 5.36 (Berkeley) 6/1/90 (with daemon mode)";
27: #else
28: static char sccsid[] = "@(#)daemon.c 5.36 (Berkeley) 6/1/90 (without daemon mode)";
29: #endif
30: #endif /* not lint */
31:
32: int la; /* load average */
33:
34: #ifdef DAEMON
35:
36: # include <netdb.h>
37: # include <sys/signal.h>
38: # include <sys/wait.h>
39: # include <sys/time.h>
40: # include <sys/resource.h>
41:
42: /*
43: ** DAEMON.C -- routines to use when running as a daemon.
44: **
45: ** This entire file is highly dependent on the 4.2 BSD
46: ** interprocess communication primitives. No attempt has
47: ** been made to make this file portable to Version 7,
48: ** Version 6, MPX files, etc. If you should try such a
49: ** thing yourself, I recommend chucking the entire file
50: ** and starting from scratch. Basic semantics are:
51: **
52: ** getrequests()
53: ** Opens a port and initiates a connection.
54: ** Returns in a child. Must set InChannel and
55: ** OutChannel appropriately.
56: ** clrdaemon()
57: ** Close any open files associated with getting
58: ** the connection; this is used when running the queue,
59: ** etc., to avoid having extra file descriptors during
60: ** the queue run and to avoid confusing the network
61: ** code (if it cares).
62: ** makeconnection(host, port, outfile, infile)
63: ** Make a connection to the named host on the given
64: ** port. Set *outfile and *infile to the files
65: ** appropriate for communication. Returns zero on
66: ** success, else an exit status describing the
67: ** error.
68: ** maphostname(hbuf, hbufsize)
69: ** Convert the entry in hbuf into a canonical form. It
70: ** may not be larger than hbufsize.
71: */
72: /*
73: ** GETREQUESTS -- open mail IPC port and get requests.
74: **
75: ** Parameters:
76: ** none.
77: **
78: ** Returns:
79: ** none.
80: **
81: ** Side Effects:
82: ** Waits until some interesting activity occurs. When
83: ** it does, a child is created to process it, and the
84: ** parent waits for completion. Return from this
85: ** routine is always in the child. The file pointers
86: ** "InChannel" and "OutChannel" should be set to point
87: ** to the communication channel.
88: */
89:
90: struct sockaddr_in SendmailAddress;/* internet address of sendmail */
91:
92: int DaemonSocket = -1; /* fd describing socket */
93: char *NetName; /* name of home (local?) network */
94:
95: getrequests()
96: {
97: int t;
98: register struct servent *sp;
99: int on = 1;
100: extern reapchild();
101:
102: /*
103: ** Set up the address for the mailer.
104: */
105:
106: sp = getservbyname("smtp", "tcp");
107: if (sp == NULL)
108: {
109: syserr("server \"smtp\" unknown");
110: goto severe;
111: }
112: SendmailAddress.sin_family = AF_INET;
113: SendmailAddress.sin_addr.s_addr = INADDR_ANY;
114: SendmailAddress.sin_port = sp->s_port;
115:
116: /*
117: ** Try to actually open the connection.
118: */
119:
120: if (tTd(15, 1))
121: printf("getrequests: port 0x%x\n", SendmailAddress.sin_port);
122:
123: /* get a socket for the SMTP connection */
124: DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
125: if (DaemonSocket < 0)
126: {
127: /* probably another daemon already */
128: syserr("getrequests: can't create socket");
129: severe:
130: # ifdef LOG
131: if (LogLevel > 0)
132: syslog(LOG_ALERT, "cannot get connection");
133: # endif LOG
134: finis();
135: }
136:
137: /* turn on network debugging? */
138: if (tTd(15, 15))
139: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
140:
141: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
142: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
143:
144: if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress) < 0)
145: {
146: syserr("getrequests: cannot bind");
147: (void) close(DaemonSocket);
148: goto severe;
149: }
150: if (listen(DaemonSocket, 10) < 0)
151: {
152: syserr("getrequests: cannot listen");
153: (void) close(DaemonSocket);
154: goto severe;
155: }
156:
157: (void) signal(SIGCHLD, reapchild);
158:
159: if (tTd(15, 1))
160: printf("getrequests: %d\n", DaemonSocket);
161:
162: for (;;)
163: {
164: register int pid;
165: auto int lotherend;
166: extern int RefuseLA;
167:
168: /* see if we are rejecting connections */
169: while ((la = getla()) > RefuseLA)
170: {
171: setproctitle("rejecting connections: load average: %.2f", (double)la);
172: sleep(5);
173: }
174:
175: /* wait for a connection */
176: setproctitle("accepting connections");
177: do
178: {
179: errno = 0;
180: lotherend = sizeof RealHostAddr;
181: t = accept(DaemonSocket, &RealHostAddr, &lotherend);
182: } while (t < 0 && errno == EINTR);
183: if (t < 0)
184: {
185: syserr("getrequests: accept");
186: sleep(5);
187: continue;
188: }
189:
190: /*
191: ** Create a subprocess to process the mail.
192: */
193:
194: if (tTd(15, 2))
195: printf("getrequests: forking (fd = %d)\n", t);
196:
197: pid = fork();
198: if (pid < 0)
199: {
200: syserr("daemon: cannot fork");
201: sleep(10);
202: (void) close(t);
203: continue;
204: }
205:
206: if (pid == 0)
207: {
208: extern struct hostent *gethostbyaddr();
209: register struct hostent *hp;
210: char buf[MAXNAME];
211:
212: /*
213: ** CHILD -- return to caller.
214: ** Collect verified idea of sending host.
215: ** Verify calling user id if possible here.
216: */
217:
218: (void) signal(SIGCHLD, SIG_DFL);
219:
220: /* determine host name */
221: hp = gethostbyaddr((char *) &RealHostAddr.sin_addr, sizeof RealHostAddr.sin_addr, AF_INET);
222: if (hp != NULL)
223: (void) strcpy(buf, hp->h_name);
224: else
225: {
226: extern char *inet_ntoa();
227:
228: /* produce a dotted quad */
229: (void) sprintf(buf, "[%s]",
230: inet_ntoa(RealHostAddr.sin_addr));
231: }
232:
233: /* should we check for illegal connection here? XXX */
234:
235: RealHostName = newstr(buf);
236:
237: (void) close(DaemonSocket);
238: InChannel = fdopen(t, "r");
239: OutChannel = fdopen(dup(t), "w");
240: if (tTd(15, 2))
241: printf("getreq: returning\n");
242: # ifdef LOG
243: if (LogLevel > 11)
244: syslog(LOG_DEBUG, "connected, pid=%d", getpid());
245: # endif LOG
246: return;
247: }
248:
249: /* close the port so that others will hang (for a while) */
250: (void) close(t);
251: }
252: /*NOTREACHED*/
253: }
254: /*
255: ** CLRDAEMON -- reset the daemon connection
256: **
257: ** Parameters:
258: ** none.
259: **
260: ** Returns:
261: ** none.
262: **
263: ** Side Effects:
264: ** releases any resources used by the passive daemon.
265: */
266:
267: clrdaemon()
268: {
269: if (DaemonSocket >= 0)
270: (void) close(DaemonSocket);
271: DaemonSocket = -1;
272: }
273: /*
274: ** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
275: **
276: ** Parameters:
277: ** host -- the name of the host.
278: ** port -- the port number to connect to.
279: ** outfile -- a pointer to a place to put the outfile
280: ** descriptor.
281: ** infile -- ditto for infile.
282: **
283: ** Returns:
284: ** An exit code telling whether the connection could be
285: ** made and if not why not.
286: **
287: ** Side Effects:
288: ** none.
289: */
290:
291: makeconnection(host, port, outfile, infile)
292: char *host;
293: u_short port;
294: FILE **outfile;
295: FILE **infile;
296: {
297: register int i, s;
298: register struct hostent *hp = (struct hostent *)NULL;
299: extern char *inet_ntoa();
300: int sav_errno;
301: #ifdef NAMED_BIND
302: extern int h_errno;
303: #endif
304:
305: /*
306: ** Set up the address for the mailer.
307: ** Accept "[a.b.c.d]" syntax for host name.
308: */
309:
310: #ifdef NAMED_BIND
311: h_errno = 0;
312: #endif
313: errno = 0;
314:
315: if (host[0] == '[')
316: {
317: long hid;
318: register char *p = index(host, ']');
319:
320: if (p != NULL)
321: {
322: *p = '\0';
323: hid = inet_addr(&host[1]);
324: *p = ']';
325: }
326: if (p == NULL || hid == -1)
327: {
328: usrerr("Invalid numeric domain spec \"%s\"", host);
329: return (EX_NOHOST);
330: }
331: SendmailAddress.sin_addr.s_addr = hid;
332: }
333: else
334: {
335: hp = gethostbyname(host);
336: if (hp == NULL)
337: {
338: #ifdef NAMED_BIND
339: if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
340: return (EX_TEMPFAIL);
341:
342: /* if name server is specified, assume temp fail */
343: if (errno == ECONNREFUSED && UseNameServer)
344: return (EX_TEMPFAIL);
345: #endif
346:
347: /*
348: ** XXX Should look for mail forwarder record here
349: ** XXX if (h_errno == NO_ADDRESS).
350: */
351:
352: return (EX_NOHOST);
353: }
354: bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length);
355: i = 1;
356: }
357:
358: /*
359: ** Determine the port number.
360: */
361:
362: if (port != 0)
363: SendmailAddress.sin_port = htons(port);
364: else
365: {
366: register struct servent *sp = getservbyname("smtp", "tcp");
367:
368: if (sp == NULL)
369: {
370: syserr("makeconnection: server \"smtp\" unknown");
371: return (EX_OSFILE);
372: }
373: SendmailAddress.sin_port = sp->s_port;
374: }
375:
376: /*
377: ** Try to actually open the connection.
378: */
379:
380: again:
381: if (tTd(16, 1))
382: printf("makeconnection (%s [%s])\n", host,
383: inet_ntoa(SendmailAddress.sin_addr.s_addr));
384:
385: s = socket(AF_INET, SOCK_STREAM, 0);
386: if (s < 0)
387: {
388: syserr("makeconnection: no socket");
389: sav_errno = errno;
390: goto failure;
391: }
392:
393: if (tTd(16, 1))
394: printf("makeconnection: %d\n", s);
395:
396: /* turn on network debugging? */
397: if (tTd(16, 14))
398: {
399: int on = 1;
400: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
401: }
402: if (CurEnv->e_xfp != NULL)
403: (void) fflush(CurEnv->e_xfp); /* for debugging */
404: errno = 0; /* for debugging */
405: SendmailAddress.sin_family = AF_INET;
406: if (connect(s, &SendmailAddress, sizeof SendmailAddress) < 0)
407: {
408: sav_errno = errno;
409: (void) close(s);
410: if (hp && hp->h_addr_list[i])
411: {
412: bcopy(hp->h_addr_list[i++],
413: (char *)&SendmailAddress.sin_addr, hp->h_length);
414: goto again;
415: }
416:
417: /* failure, decide if temporary or not */
418: failure:
419: switch (sav_errno)
420: {
421: case EISCONN:
422: case ETIMEDOUT:
423: case EINPROGRESS:
424: case EALREADY:
425: case EADDRINUSE:
426: case EHOSTDOWN:
427: case ENETDOWN:
428: case ENETRESET:
429: case ENOBUFS:
430: case ECONNREFUSED:
431: case ECONNRESET:
432: case EHOSTUNREACH:
433: case ENETUNREACH:
434: /* there are others, I'm sure..... */
435: return (EX_TEMPFAIL);
436:
437: case EPERM:
438: /* why is this happening? */
439: syserr("makeconnection: funny failure, addr=%lx, port=%x",
440: SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
441: return (EX_TEMPFAIL);
442:
443: default:
444: {
445: extern char *errstring();
446:
447: message(Arpa_Info, "%s", errstring(sav_errno));
448: return (EX_UNAVAILABLE);
449: }
450: }
451: }
452:
453: /* connection ok, put it into canonical form */
454: *outfile = fdopen(s, "w");
455: *infile = fdopen(dup(s), "r");
456:
457: return (EX_OK);
458: }
459: /*
460: ** MYHOSTNAME -- return the name of this host.
461: **
462: ** Parameters:
463: ** hostbuf -- a place to return the name of this host.
464: ** size -- the size of hostbuf.
465: **
466: ** Returns:
467: ** A list of aliases for this host.
468: **
469: ** Side Effects:
470: ** none.
471: */
472:
473: char **
474: myhostname(hostbuf, size)
475: char hostbuf[];
476: int size;
477: {
478: extern struct hostent *gethostbyname();
479: struct hostent *hp;
480:
481: if (gethostname(hostbuf, size) < 0)
482: {
483: (void) strcpy(hostbuf, "localhost");
484: }
485: hp = gethostbyname(hostbuf);
486: if (hp != NULL)
487: {
488: (void) strcpy(hostbuf, hp->h_name);
489: return (hp->h_aliases);
490: }
491: else
492: return (NULL);
493: }
494:
495: /*
496: * MAPHOSTNAME -- turn a hostname into canonical form
497: *
498: * Parameters:
499: * hbuf -- a buffer containing a hostname.
500: * hbsize -- the size of hbuf.
501: *
502: * Returns:
503: * none.
504: *
505: * Side Effects:
506: * Looks up the host specified in hbuf. If it is not
507: * the canonical name for that host, replace it with
508: * the canonical name. If the name is unknown, or it
509: * is already the canonical name, leave it unchanged.
510: */
511: maphostname(hbuf, hbsize)
512: char *hbuf;
513: int hbsize;
514: {
515: register struct hostent *hp;
516: u_long in_addr;
517: char ptr[256], *cp;
518: struct hostent *gethostbyaddr();
519:
520: /*
521: * If first character is a bracket, then it is an address
522: * lookup. Address is copied into a temporary buffer to
523: * strip the brackets and to preserve hbuf if address is
524: * unknown.
525: */
526: if (*hbuf != '[') {
527: getcanonname(hbuf, hbsize);
528: return;
529: }
530: if ((cp = index(strcpy(ptr, hbuf), ']')) == NULL)
531: return;
532: *cp = '\0';
533: in_addr = inet_addr(&ptr[1]);
534: hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
535: if (hp == NULL)
536: return;
537: if (strlen(hp->h_name) >= hbsize)
538: hp->h_name[hbsize - 1] = '\0';
539: (void)strcpy(hbuf, hp->h_name);
540: }
541:
542: # else DAEMON
543: /* code for systems without sophisticated networking */
544:
545: /*
546: ** MYHOSTNAME -- stub version for case of no daemon code.
547: **
548: ** Can't convert to upper case here because might be a UUCP name.
549: **
550: ** Mark, you can change this to be anything you want......
551: */
552:
553: char **
554: myhostname(hostbuf, size)
555: char hostbuf[];
556: int size;
557: {
558: register FILE *f;
559:
560: hostbuf[0] = '\0';
561: f = fopen("/usr/include/whoami", "r");
562: if (f != NULL)
563: {
564: (void) fgets(hostbuf, size, f);
565: fixcrlf(hostbuf, TRUE);
566: (void) fclose(f);
567: }
568: return (NULL);
569: }
570: /*
571: ** MAPHOSTNAME -- turn a hostname into canonical form
572: **
573: ** Parameters:
574: ** hbuf -- a buffer containing a hostname.
575: ** hbsize -- the size of hbuf.
576: **
577: ** Returns:
578: ** none.
579: **
580: ** Side Effects:
581: ** Looks up the host specified in hbuf. If it is not
582: ** the canonical name for that host, replace it with
583: ** the canonical name. If the name is unknown, or it
584: ** is already the canonical name, leave it unchanged.
585: */
586:
587: /*ARGSUSED*/
588: maphostname(hbuf, hbsize)
589: char *hbuf;
590: int hbsize;
591: {
592: return;
593: }
594:
595: #endif DAEMON
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.