minor cleanups for cray
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
CommitLineData
d185cb11 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
710322bb
KB
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
dc45ba8c
KB
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.
710322bb 17 */
d185cb11 18
d0432129
KB
19#include <errno.h>
20#include <sendmail.h>
6b6d57eb 21# include <sys/mx.h>
ef34cbda 22
710322bb
KB
23#ifndef lint
24#ifdef DAEMON
ab4889ea 25static char sccsid[] = "@(#)daemon.c 5.28 (Berkeley) %G% (with daemon mode)";
710322bb 26#else
ab4889ea 27static char sccsid[] = "@(#)daemon.c 5.28 (Berkeley) %G% (without daemon mode)";
710322bb
KB
28#endif
29#endif /* not lint */
30
31#ifdef DAEMON
17a67c62 32
17a67c62 33# include <netdb.h>
199d34eb 34# include <sys/signal.h>
17a67c62
EA
35# include <sys/wait.h>
36# include <sys/time.h>
37# include <sys/resource.h>
38
ef34cbda
EA
39/*
40** DAEMON.C -- routines to use when running as a daemon.
2a16bae3
EA
41**
42** This entire file is highly dependent on the 4.2 BSD
43** interprocess communication primitives. No attempt has
44** been made to make this file portable to Version 7,
45** Version 6, MPX files, etc. If you should try such a
46** thing yourself, I recommend chucking the entire file
47** and starting from scratch. Basic semantics are:
48**
49** getrequests()
50** Opens a port and initiates a connection.
51** Returns in a child. Must set InChannel and
52** OutChannel appropriately.
eb8af3ce
EA
53** clrdaemon()
54** Close any open files associated with getting
55** the connection; this is used when running the queue,
56** etc., to avoid having extra file descriptors during
57** the queue run and to avoid confusing the network
58** code (if it cares).
2a16bae3
EA
59** makeconnection(host, port, outfile, infile)
60** Make a connection to the named host on the given
61** port. Set *outfile and *infile to the files
62** appropriate for communication. Returns zero on
63** success, else an exit status describing the
64** error.
8fd13041
EA
65** maphostname(hbuf, hbufsize)
66** Convert the entry in hbuf into a canonical form. It
67** may not be larger than hbufsize.
ef34cbda 68*/
6b6d57eb
EA
69
70static FILE *MailPort; /* port that mail comes in on */
ef34cbda
EA
71\f/*
72** GETREQUESTS -- open mail IPC port and get requests.
73**
74** Parameters:
75** none.
76**
77** Returns:
78** none.
79**
80** Side Effects:
81** Waits until some interesting activity occurs. When
82** it does, a child is created to process it, and the
83** parent waits for completion. Return from this
40d27fed
EA
84** routine is always in the child. The file pointers
85** "InChannel" and "OutChannel" should be set to point
86** to the communication channel.
ef34cbda
EA
87*/
88
eb8af3ce 89struct sockaddr_in SendmailAddress;/* internet address of sendmail */
c72f7eca
EA
90
91int DaemonSocket = -1; /* fd describing socket */
dc661374 92char *NetName; /* name of home (local?) network */
14a39063 93
7f108496 94getrequests()
14a39063 95{
7e3417e6 96 int t;
7f108496 97 register struct servent *sp;
4ff794a3 98 int on = 1;
199d34eb 99 extern reapchild();
14a39063
EA
100
101 /*
102 ** Set up the address for the mailer.
103 */
104
7f108496
EA
105 sp = getservbyname("smtp", "tcp");
106 if (sp == NULL)
107 {
108 syserr("server \"smtp\" unknown");
a1e665f3 109 goto severe;
7f108496
EA
110 }
111 SendmailAddress.sin_family = AF_INET;
112 SendmailAddress.sin_addr.s_addr = INADDR_ANY;
a0221fb9 113 SendmailAddress.sin_port = sp->s_port;
14a39063
EA
114
115 /*
116 ** Try to actually open the connection.
117 */
118
119# ifdef DEBUG
9678c96d 120 if (tTd(15, 1))
7f108496 121 printf("getrequests: port 0x%x\n", SendmailAddress.sin_port);
14a39063
EA
122# endif DEBUG
123
7f108496 124 /* get a socket for the SMTP connection */
17a67c62 125 DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
eb8af3ce 126 if (DaemonSocket < 0)
4b5cf74c 127 {
7f108496
EA
128 /* probably another daemon already */
129 syserr("getrequests: can't create socket");
130 severe:
131# ifdef LOG
132 if (LogLevel > 0)
7f108496
EA
133# endif LOG
134 finis();
135 }
78c9dc29
EA
136
137#ifdef DEBUG
138 /* turn on network debugging? */
139 if (tTd(15, 15))
bb812c0b 140 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
78c9dc29
EA
141#endif DEBUG
142
4ff794a3
EA
143 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
144 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
145
17a67c62 146 if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress) < 0)
7f108496
EA
147 {
148 syserr("getrequests: cannot bind");
eb8af3ce 149 (void) close(DaemonSocket);
7f108496
EA
150 goto severe;
151 }
17a67c62
EA
152 if (listen(DaemonSocket, 10) < 0)
153 {
154 syserr("getrequests: cannot listen");
155 (void) close(DaemonSocket);
156 goto severe;
157 }
14a39063 158
8ff78b51 159 (void) signal(SIGCHLD, reapchild);
199d34eb 160
14a39063 161# ifdef DEBUG
7f108496 162 if (tTd(15, 1))
eb8af3ce 163 printf("getrequests: %d\n", DaemonSocket);
14a39063 164# endif DEBUG
2a16bae3 165
7f108496
EA
166 struct wh wbuf;
167
168 wbuf.index = index;
169 wbuf.count = 0;
170 wbuf.ccount = cnt;
171 wbuf.data = buf;
172 write(MailPort, &wbuf, sizeof wbuf);
14a39063 173}
1ab402f2
EA
174\f/*
175** MAKECONNECTION -- make a connection to an SMTP socket on another machine.
176**
177** Parameters:
178** host -- the name of the host.
e2d7c32a 179** port -- the port number to connect to.
1ab402f2
EA
180** outfile -- a pointer to a place to put the outfile
181** descriptor.
182** infile -- ditto for infile.
183**
184** Returns:
185** An exit code telling whether the connection could be
186** made and if not why not.
187**
188** Side Effects:
189** none.
190*/
191
e2d7c32a 192makeconnection(host, port, outfile, infile)
1ab402f2 193 char *host;
f7eb07a3 194 u_short port;
1ab402f2
EA
195 FILE **outfile;
196 FILE **infile;
197{
9e881165
JB
198 register int i, s;
199 register struct hostent *hp = (struct hostent *)NULL;
200 extern char *inet_ntoa();
fa163d3c 201 int sav_errno;
35af2f06
EA
202#ifdef NAMED_BIND
203 extern int h_errno;
204#endif
1ab402f2
EA
205
206 /*
207 ** Set up the address for the mailer.
b3e29341 208 ** Accept "[a.b.c.d]" syntax for host name.
1ab402f2
EA
209 */
210
35af2f06 211#ifdef NAMED_BIND
459e21be 212 h_errno = 0;
35af2f06 213#endif
459e21be
MAN
214 errno = 0;
215
b3e29341
EA
216 if (host[0] == '[')
217 {
e56baaff
EA
218 long hid;
219 register char *p = index(host, ']');
b3e29341 220
e56baaff 221 if (p != NULL)
b3e29341 222 {
e56baaff
EA
223 *p = '\0';
224 hid = inet_addr(&host[1]);
225 *p = ']';
b3e29341 226 }
e56baaff 227 if (p == NULL || hid == -1)
b3e29341
EA
228 {
229 usrerr("Invalid numeric domain spec \"%s\"", host);
230 return (EX_NOHOST);
231 }
232 SendmailAddress.sin_addr.s_addr = hid;
233 }
7f108496
EA
234 else
235 {
9e881165 236 hp = gethostbyname(host);
e56baaff 237 if (hp == NULL)
459e21be 238 {
35af2f06 239#ifdef NAMED_BIND
459e21be 240 if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
459e21be 241 return (EX_TEMPFAIL);
8da74c93 242
35af2f06
EA
243 /* if name server is specified, assume temp fail */
244 if (errno == ECONNREFUSED && UseNameServer)
245 return (EX_TEMPFAIL);
246#endif
247
8da74c93
EA
248 /*
249 ** XXX Should look for mail forwarder record here
250 ** XXX if (h_errno == NO_ADDRESS).
251 */
252
7f108496 253 return (EX_NOHOST);
459e21be 254 }
83f674d8 255 bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length);
9e881165 256 i = 1;
7f108496
EA
257 }
258
259 /*
260 ** Determine the port number.
261 */
262
372c9e7f
EA
263 if (port != 0)
264 SendmailAddress.sin_port = htons(port);
265 else
7f108496
EA
266 {
267 register struct servent *sp = getservbyname("smtp", "tcp");
268
269 if (sp == NULL)
270 {
271 syserr("makeconnection: server \"smtp\" unknown");
272 return (EX_OSFILE);
273 }
372c9e7f 274 SendmailAddress.sin_port = sp->s_port;
7f108496 275 }
1ab402f2
EA
276
277 /*
278 ** Try to actually open the connection.
279 */
280
9e881165 281again:
1ab402f2 282# ifdef DEBUG
9678c96d 283 if (tTd(16, 1))
9e881165
JB
284 printf("makeconnection (%s [%s])\n", host,
285 inet_ntoa(SendmailAddress.sin_addr.s_addr));
1ab402f2
EA
286# endif DEBUG
287
7e3417e6
EA
288#ifdef NVMUNIX
289 s = socket(AF_INET, SOCK_STREAM, 0, 0);
290#else NVMUNIX
17a67c62 291 s = socket(AF_INET, SOCK_STREAM, 0);
7e3417e6 292#endif NVMUNIX
1ab402f2
EA
293 if (s < 0)
294 {
295 syserr("makeconnection: no socket");
fa163d3c 296 sav_errno = errno;
1ab402f2
EA
297 goto failure;
298 }
299
300# ifdef DEBUG
9678c96d 301 if (tTd(16, 1))
1ab402f2 302 printf("makeconnection: %d\n", s);
78c9dc29
EA
303
304 /* turn on network debugging? */
305 if (tTd(16, 14))
bb812c0b
MAN
306 {
307 int on = 1;
308 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
309 }
1ab402f2 310# endif DEBUG
912acb74 311 (void) fflush(CurEnv->e_xfp); /* for debugging */
54f71ceb 312 errno = 0; /* for debugging */
7e3417e6
EA
313#ifdef NVMUNIX
314 bind(s, &SendmailAddress, sizeof SendmailAddress, 0);
315 if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0)
316#else NVMUNIX
7f108496 317 SendmailAddress.sin_family = AF_INET;
17a67c62 318 if (connect(s, &SendmailAddress, sizeof SendmailAddress) < 0)
7e3417e6 319#endif NVMUNIX
1ab402f2 320 {
fa163d3c
JB
321 sav_errno = errno;
322 (void) close(s);
9e881165
JB
323 if (hp && hp->h_addr_list[i])
324 {
325 bcopy(hp->h_addr_list[i++],
326 (char *)&SendmailAddress.sin_addr, hp->h_length);
327 goto again;
328 }
329
1ab402f2
EA
330 /* failure, decide if temporary or not */
331 failure:
fa163d3c 332 switch (sav_errno)
1ab402f2
EA
333 {
334 case EISCONN:
335 case ETIMEDOUT:
a82f298c
EA
336 case EINPROGRESS:
337 case EALREADY:
338 case EADDRINUSE:
7934dd80 339 case EHOSTDOWN:
a82f298c
EA
340 case ENETDOWN:
341 case ENETRESET:
342 case ENOBUFS:
e31f6e62 343 case ECONNREFUSED:
e5b251f1 344 case ECONNRESET:
8b189b5a 345 case EHOSTUNREACH:
1aaa7dec 346 case ENETUNREACH:
1ab402f2
EA
347 /* there are others, I'm sure..... */
348 return (EX_TEMPFAIL);
349
e56baaff
EA
350 case EPERM:
351 /* why is this happening? */
352 syserr("makeconnection: funny failure, addr=%lx, port=%x",
353 SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
54f71ceb 354 return (EX_TEMPFAIL);
e56baaff 355
1ab402f2 356 default:
efeb11d5 357 message(Arpa_Info, "%s", errstring(sav_errno));
1ab402f2
EA
358 return (EX_UNAVAILABLE);
359 }
360 }
361
362 /* connection ok, put it into canonical form */
363 *outfile = fdopen(s, "w");
364 *infile = fdopen(s, "r");
365
1aaa7dec 366 return (EX_OK);
1ab402f2 367}
2ec2faaa
EA
368\f/*
369** MYHOSTNAME -- return the name of this host.
370**
371** Parameters:
372** hostbuf -- a place to return the name of this host.
05894fc6 373** size -- the size of hostbuf.
2ec2faaa
EA
374**
375** Returns:
376** A list of aliases for this host.
377**
378** Side Effects:
379** none.
380*/
381
382char **
05894fc6 383myhostname(hostbuf, size)
2ec2faaa 384 char hostbuf[];
05894fc6 385 int size;
2ec2faaa
EA
386{
387 extern struct hostent *gethostbyname();
e56baaff 388 struct hostent *hp;
2ec2faaa 389
17a67c62
EA
390 if (gethostname(hostbuf, size) < 0)
391 {
392 (void) strcpy(hostbuf, "localhost");
393 }
e56baaff
EA
394 hp = gethostbyname(hostbuf);
395 if (hp != NULL)
b9b481e2 396 {
03388044 397 (void) strcpy(hostbuf, hp->h_name);
e56baaff 398 return (hp->h_aliases);
b9b481e2 399 }
2ec2faaa
EA
400 else
401 return (NULL);
402}
217a0102 403
d0432129
KB
404/*
405 * MAPHOSTNAME -- turn a hostname into canonical form
406 *
407 * Parameters:
408 * hbuf -- a buffer containing a hostname.
409 * hbsize -- the size of hbuf.
410 *
411 * Returns:
412 * none.
413 *
414 * Side Effects:
415 * Looks up the host specified in hbuf. If it is not
416 * the canonical name for that host, replace it with
417 * the canonical name. If the name is unknown, or it
418 * is already the canonical name, leave it unchanged.
419 */
217a0102
EA
420maphostname(hbuf, hbsize)
421 char *hbuf;
422 int hbsize;
423{
424 register struct hostent *hp;
d0432129
KB
425 u_long in_addr;
426 char ptr[256];
427 struct hostent *gethostbyaddr();
217a0102 428
33e4da31 429 /*
d0432129
KB
430 * If first character is a bracket, then it is an address
431 * lookup. Address is copied into a temporary buffer to
432 * strip the brackets and to preserve hbuf if address is
433 * unknown.
434 */
435 if (*hbuf != '[') {
9d25081a
JB
436 getcanonname(hbuf, hbsize);
437 return;
217a0102 438 }
d0432129
KB
439 *index(strcpy(ptr, hbuf), ']') = '\0';
440 in_addr = inet_addr(&ptr[1]);
441 hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
442 if (hp == NULL)
443 return;
444 if (strlen(hp->h_name) >= hbsize)
445 hp->h_name[hbsize - 1] = '\0';
446 (void)strcpy(hbuf, hp->h_name);
217a0102 447}
d0432129 448
2ec2faaa 449# else DAEMON
217a0102 450/* code for systems without sophisticated networking */
2ec2faaa
EA
451
452/*
453** MYHOSTNAME -- stub version for case of no daemon code.
69f904e0
EA
454**
455** Can't convert to upper case here because might be a UUCP name.
05894fc6
EA
456**
457** Mark, you can change this to be anything you want......
2ec2faaa
EA
458*/
459
460char **
05894fc6 461myhostname(hostbuf, size)
2ec2faaa 462 char hostbuf[];
05894fc6 463 int size;
2ec2faaa
EA
464{
465 register FILE *f;
466
467 hostbuf[0] = '\0';
468 f = fopen("/usr/include/whoami", "r");
469 if (f != NULL)
470 {
05894fc6 471 (void) fgets(hostbuf, size, f);
2ec2faaa
EA
472 fixcrlf(hostbuf, TRUE);
473 (void) fclose(f);
474 }
475 return (NULL);
476}
217a0102
EA
477\f/*
478** MAPHOSTNAME -- turn a hostname into canonical form
479**
480** Parameters:
481** hbuf -- a buffer containing a hostname.
482** hbsize -- the size of hbuf.
483**
484** Returns:
485** none.
486**
487** Side Effects:
488** Looks up the host specified in hbuf. If it is not
489** the canonical name for that host, replace it with
490** the canonical name. If the name is unknown, or it
491** is already the canonical name, leave it unchanged.
492*/
493
494/*ARGSUSED*/
495maphostname(hbuf, hbsize)
496 char *hbuf;
497 int hbsize;
498{
499 return;
500}
501
14a39063 502#endif DAEMON