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