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