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