Deleted Added
full compact
listener.c (102528) listener.c (110560)
1/*
2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11#include <sm/gen.h>
1/*
2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11#include <sm/gen.h>
12SM_RCSID("@(#)$Id: listener.c,v 8.85.2.1 2002/08/09 22:13:36 gshapiro Exp $")
12SM_RCSID("@(#)$Id: listener.c,v 8.85.2.7 2002/12/10 04:02:25 ca Exp $")
13
14/*
15** listener.c -- threaded network listener
16*/
17
18#include "libmilter.h"
19#include <sm/errstring.h>
13
14/*
15** listener.c -- threaded network listener
16*/
17
18#include "libmilter.h"
19#include <sm/errstring.h>
20#include <sm/fdset.h>
20
21
22# if NETINET || NETINET6
23# include <arpa/inet.h>
24# endif /* NETINET || NETINET6 */
25
26static smutex_t L_Mutex;
27static int L_family;
28static SOCKADDR_LEN_T L_socksize;
29static socket_t listenfd = INVALID_SOCKET;
30
31static socket_t mi_milteropen __P((char *, int, char *));
32
33/*
34** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
35**
36** Parameters:
37** conn -- connection description
38** backlog -- listen backlog
39** dbg -- debug level
40** smfi -- filter structure to use
41**
42** Return value:
43** MI_SUCCESS/MI_FAILURE
44*/
45
46int
47mi_opensocket(conn, backlog, dbg, smfi)
48 char *conn;
49 int backlog;
50 int dbg;
51 smfiDesc_ptr smfi;
52{
53 if (smfi == NULL || conn == NULL)
54 return MI_FAILURE;
55
56 if (ValidSocket(listenfd))
57 return MI_SUCCESS;
58
59 if (dbg > 0)
60 {
61 smi_log(SMI_LOG_DEBUG,
62 "%s: Opening listen socket on conn %s",
63 smfi->xxfi_name, conn);
64 }
65 (void) smutex_init(&L_Mutex);
66 (void) smutex_lock(&L_Mutex);
67 listenfd = mi_milteropen(conn, backlog, smfi->xxfi_name);
68 if (!ValidSocket(listenfd))
69 {
70 smi_log(SMI_LOG_FATAL,
71 "%s: Unable to create listening socket on conn %s",
72 smfi->xxfi_name, conn);
73 (void) smutex_unlock(&L_Mutex);
74 return MI_FAILURE;
75 }
21
22
23# if NETINET || NETINET6
24# include <arpa/inet.h>
25# endif /* NETINET || NETINET6 */
26
27static smutex_t L_Mutex;
28static int L_family;
29static SOCKADDR_LEN_T L_socksize;
30static socket_t listenfd = INVALID_SOCKET;
31
32static socket_t mi_milteropen __P((char *, int, char *));
33
34/*
35** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
36**
37** Parameters:
38** conn -- connection description
39** backlog -- listen backlog
40** dbg -- debug level
41** smfi -- filter structure to use
42**
43** Return value:
44** MI_SUCCESS/MI_FAILURE
45*/
46
47int
48mi_opensocket(conn, backlog, dbg, smfi)
49 char *conn;
50 int backlog;
51 int dbg;
52 smfiDesc_ptr smfi;
53{
54 if (smfi == NULL || conn == NULL)
55 return MI_FAILURE;
56
57 if (ValidSocket(listenfd))
58 return MI_SUCCESS;
59
60 if (dbg > 0)
61 {
62 smi_log(SMI_LOG_DEBUG,
63 "%s: Opening listen socket on conn %s",
64 smfi->xxfi_name, conn);
65 }
66 (void) smutex_init(&L_Mutex);
67 (void) smutex_lock(&L_Mutex);
68 listenfd = mi_milteropen(conn, backlog, smfi->xxfi_name);
69 if (!ValidSocket(listenfd))
70 {
71 smi_log(SMI_LOG_FATAL,
72 "%s: Unable to create listening socket on conn %s",
73 smfi->xxfi_name, conn);
74 (void) smutex_unlock(&L_Mutex);
75 return MI_FAILURE;
76 }
76
77 if (!SM_FD_OK_SELECT(listenfd))
78 {
79 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
80 smfi->xxfi_name, listenfd, FD_SETSIZE);
81 (void) smutex_unlock(&L_Mutex);
82 return MI_FAILURE;
83 }
77 return MI_SUCCESS;
78}
79
80/*
81** MI_MILTEROPEN -- setup socket to listen on
82**
83** Parameters:
84** conn -- connection description
85** backlog -- listen backlog
86** name -- name for logging
87**
88** Returns:
89** socket upon success, error code otherwise.
90**
91** Side effect:
92** sets sockpath if UNIX socket.
93*/
94
95#if NETUNIX
96static char *sockpath = NULL;
97#endif /* NETUNIX */
98
99static socket_t
100mi_milteropen(conn, backlog, name)
101 char *conn;
102 int backlog;
103 char *name;
104{
105 socket_t sock;
106 int sockopt = 1;
107 int fdflags;
108 size_t len = 0;
109 char *p;
110 char *colon;
111 char *at;
112 SOCKADDR addr;
113
114 if (conn == NULL || conn[0] == '\0')
115 {
116 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
117 name);
118 return INVALID_SOCKET;
119 }
120 (void) memset(&addr, '\0', sizeof addr);
121
122 /* protocol:filename or protocol:port@host */
123 p = conn;
124 colon = strchr(p, ':');
125 if (colon != NULL)
126 {
127 *colon = '\0';
128
129 if (*p == '\0')
130 {
131#if NETUNIX
132 /* default to AF_UNIX */
133 addr.sa.sa_family = AF_UNIX;
134 L_socksize = sizeof (struct sockaddr_un);
135#else /* NETUNIX */
136# if NETINET
137 /* default to AF_INET */
138 addr.sa.sa_family = AF_INET;
139 L_socksize = sizeof addr.sin;
140# else /* NETINET */
141# if NETINET6
142 /* default to AF_INET6 */
143 addr.sa.sa_family = AF_INET6;
144 L_socksize = sizeof addr.sin6;
145# else /* NETINET6 */
146 /* no protocols available */
147 smi_log(SMI_LOG_ERR,
148 "%s: no valid socket protocols available",
149 name);
150 return INVALID_SOCKET;
151# endif /* NETINET6 */
152# endif /* NETINET */
153#endif /* NETUNIX */
154 }
155#if NETUNIX
156 else if (strcasecmp(p, "unix") == 0 ||
157 strcasecmp(p, "local") == 0)
158 {
159 addr.sa.sa_family = AF_UNIX;
160 L_socksize = sizeof (struct sockaddr_un);
161 }
162#endif /* NETUNIX */
163#if NETINET
164 else if (strcasecmp(p, "inet") == 0)
165 {
166 addr.sa.sa_family = AF_INET;
167 L_socksize = sizeof addr.sin;
168 }
169#endif /* NETINET */
170#if NETINET6
171 else if (strcasecmp(p, "inet6") == 0)
172 {
173 addr.sa.sa_family = AF_INET6;
174 L_socksize = sizeof addr.sin6;
175 }
176#endif /* NETINET6 */
177 else
178 {
179 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
180 name, p);
181 return INVALID_SOCKET;
182 }
183 *colon++ = ':';
184 }
185 else
186 {
187 colon = p;
188#if NETUNIX
189 /* default to AF_UNIX */
190 addr.sa.sa_family = AF_UNIX;
191 L_socksize = sizeof (struct sockaddr_un);
192#else /* NETUNIX */
193# if NETINET
194 /* default to AF_INET */
195 addr.sa.sa_family = AF_INET;
196 L_socksize = sizeof addr.sin;
197# else /* NETINET */
198# if NETINET6
199 /* default to AF_INET6 */
200 addr.sa.sa_family = AF_INET6;
201 L_socksize = sizeof addr.sin6;
202# else /* NETINET6 */
203 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
204 name, p);
205 return INVALID_SOCKET;
206# endif /* NETINET6 */
207# endif /* NETINET */
208#endif /* NETUNIX */
209 }
210
211#if NETUNIX
212 if (addr.sa.sa_family == AF_UNIX)
213 {
214# if 0
215 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
216# endif /* 0 */
217
218 at = colon;
219 len = strlen(colon) + 1;
220 if (len >= sizeof addr.sunix.sun_path)
221 {
222 errno = EINVAL;
223 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
224 name, colon);
225 return INVALID_SOCKET;
226 }
227 (void) sm_strlcpy(addr.sunix.sun_path, colon,
228 sizeof addr.sunix.sun_path);
229# if 0
230 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
231 S_IRUSR|S_IWUSR, NULL);
232
233 /* if not safe, don't create */
234 if (errno != 0)
235 {
236 smi_log(SMI_LOG_ERR,
237 "%s: UNIX socket name %s unsafe",
238 name, colon);
239 return INVALID_SOCKET;
240 }
241# endif /* 0 */
242 }
243#endif /* NETUNIX */
244
245#if NETINET || NETINET6
246 if (
247# if NETINET
248 addr.sa.sa_family == AF_INET
249# endif /* NETINET */
250# if NETINET && NETINET6
251 ||
252# endif /* NETINET && NETINET6 */
253# if NETINET6
254 addr.sa.sa_family == AF_INET6
255# endif /* NETINET6 */
256 )
257 {
258 unsigned short port;
259
260 /* Parse port@host */
261 at = strchr(colon, '@');
262 if (at == NULL)
263 {
264 switch (addr.sa.sa_family)
265 {
266# if NETINET
267 case AF_INET:
268 addr.sin.sin_addr.s_addr = INADDR_ANY;
269 break;
270# endif /* NETINET */
271
272# if NETINET6
273 case AF_INET6:
274 addr.sin6.sin6_addr = in6addr_any;
275 break;
276# endif /* NETINET6 */
277 }
278 }
279 else
280 *at = '\0';
281
282 if (isascii(*colon) && isdigit(*colon))
283 port = htons((unsigned short) atoi(colon));
284 else
285 {
286# ifdef NO_GETSERVBYNAME
287 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
288 name, colon);
289 return INVALID_SOCKET;
290# else /* NO_GETSERVBYNAME */
291 register struct servent *sp;
292
293 sp = getservbyname(colon, "tcp");
294 if (sp == NULL)
295 {
296 smi_log(SMI_LOG_ERR,
297 "%s: unknown port name %s",
298 name, colon);
299 return INVALID_SOCKET;
300 }
301 port = sp->s_port;
302# endif /* NO_GETSERVBYNAME */
303 }
304 if (at != NULL)
305 {
306 *at++ = '@';
307 if (*at == '[')
308 {
309 char *end;
310
311 end = strchr(at, ']');
312 if (end != NULL)
313 {
314 bool found = false;
315# if NETINET
316 unsigned long hid = INADDR_NONE;
317# endif /* NETINET */
318# if NETINET6
319 struct sockaddr_in6 hid6;
320# endif /* NETINET6 */
321
322 *end = '\0';
323# if NETINET
324 if (addr.sa.sa_family == AF_INET &&
325 (hid = inet_addr(&at[1])) != INADDR_NONE)
326 {
327 addr.sin.sin_addr.s_addr = hid;
328 addr.sin.sin_port = port;
329 found = true;
330 }
331# endif /* NETINET */
332# if NETINET6
333 (void) memset(&hid6, '\0', sizeof hid6);
334 if (addr.sa.sa_family == AF_INET6 &&
335 mi_inet_pton(AF_INET6, &at[1],
336 &hid6.sin6_addr) == 1)
337 {
338 addr.sin6.sin6_addr = hid6.sin6_addr;
339 addr.sin6.sin6_port = port;
340 found = true;
341 }
342# endif /* NETINET6 */
343 *end = ']';
344 if (!found)
345 {
346 smi_log(SMI_LOG_ERR,
347 "%s: Invalid numeric domain spec \"%s\"",
348 name, at);
349 return INVALID_SOCKET;
350 }
351 }
352 else
353 {
354 smi_log(SMI_LOG_ERR,
355 "%s: Invalid numeric domain spec \"%s\"",
356 name, at);
357 return INVALID_SOCKET;
358 }
359 }
360 else
361 {
362 struct hostent *hp = NULL;
363
364 hp = mi_gethostbyname(at, addr.sa.sa_family);
365 if (hp == NULL)
366 {
367 smi_log(SMI_LOG_ERR,
368 "%s: Unknown host name %s",
369 name, at);
370 return INVALID_SOCKET;
371 }
372 addr.sa.sa_family = hp->h_addrtype;
373 switch (hp->h_addrtype)
374 {
375# if NETINET
376 case AF_INET:
377 memmove(&addr.sin.sin_addr,
378 hp->h_addr,
379 INADDRSZ);
380 addr.sin.sin_port = port;
381 break;
382# endif /* NETINET */
383
384# if NETINET6
385 case AF_INET6:
386 memmove(&addr.sin6.sin6_addr,
387 hp->h_addr,
388 IN6ADDRSZ);
389 addr.sin6.sin6_port = port;
390 break;
391# endif /* NETINET6 */
392
393 default:
394 smi_log(SMI_LOG_ERR,
395 "%s: Unknown protocol for %s (%d)",
396 name, at, hp->h_addrtype);
397 return INVALID_SOCKET;
398 }
399# if NETINET6
400 freehostent(hp);
401# endif /* NETINET6 */
402 }
403 }
404 else
405 {
406 switch (addr.sa.sa_family)
407 {
408# if NETINET
409 case AF_INET:
410 addr.sin.sin_port = port;
411 break;
412# endif /* NETINET */
413# if NETINET6
414 case AF_INET6:
415 addr.sin6.sin6_port = port;
416 break;
417# endif /* NETINET6 */
418 }
419 }
420 }
421#endif /* NETINET || NETINET6 */
422
423 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
424 if (!ValidSocket(sock))
425 {
426 smi_log(SMI_LOG_ERR,
427 "%s: Unable to create new socket: %s",
428 name, sm_errstring(errno));
429 return INVALID_SOCKET;
430 }
431
432 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
433 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
434 {
435 smi_log(SMI_LOG_ERR,
436 "%s: Unable to set close-on-exec: %s", name,
437 sm_errstring(errno));
438 (void) closesocket(sock);
439 return INVALID_SOCKET;
440 }
441
442 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
443 sizeof(sockopt)) == -1)
444 {
445 smi_log(SMI_LOG_ERR,
446 "%s: Unable to setsockopt: %s", name,
447 sm_errstring(errno));
448 (void) closesocket(sock);
449 return INVALID_SOCKET;
450 }
451
452 if (bind(sock, &addr.sa, L_socksize) < 0)
453 {
454 smi_log(SMI_LOG_ERR,
455 "%s: Unable to bind to port %s: %s",
456 name, conn, sm_errstring(errno));
457 (void) closesocket(sock);
458 return INVALID_SOCKET;
459 }
460
461 if (listen(sock, backlog) < 0)
462 {
463 smi_log(SMI_LOG_ERR,
464 "%s: listen call failed: %s", name,
465 sm_errstring(errno));
466 (void) closesocket(sock);
467 return INVALID_SOCKET;
468 }
469
470#if NETUNIX
471 if (addr.sa.sa_family == AF_UNIX && len > 0)
472 {
473 /*
474 ** Set global variable sockpath so the UNIX socket can be
475 ** unlink()ed at exit.
476 */
477
478 sockpath = (char *) malloc(len);
479 if (sockpath != NULL)
480 (void) sm_strlcpy(sockpath, colon, len);
481 else
482 {
483 smi_log(SMI_LOG_ERR,
484 "%s: can't malloc(%d) for sockpath: %s",
84 return MI_SUCCESS;
85}
86
87/*
88** MI_MILTEROPEN -- setup socket to listen on
89**
90** Parameters:
91** conn -- connection description
92** backlog -- listen backlog
93** name -- name for logging
94**
95** Returns:
96** socket upon success, error code otherwise.
97**
98** Side effect:
99** sets sockpath if UNIX socket.
100*/
101
102#if NETUNIX
103static char *sockpath = NULL;
104#endif /* NETUNIX */
105
106static socket_t
107mi_milteropen(conn, backlog, name)
108 char *conn;
109 int backlog;
110 char *name;
111{
112 socket_t sock;
113 int sockopt = 1;
114 int fdflags;
115 size_t len = 0;
116 char *p;
117 char *colon;
118 char *at;
119 SOCKADDR addr;
120
121 if (conn == NULL || conn[0] == '\0')
122 {
123 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
124 name);
125 return INVALID_SOCKET;
126 }
127 (void) memset(&addr, '\0', sizeof addr);
128
129 /* protocol:filename or protocol:port@host */
130 p = conn;
131 colon = strchr(p, ':');
132 if (colon != NULL)
133 {
134 *colon = '\0';
135
136 if (*p == '\0')
137 {
138#if NETUNIX
139 /* default to AF_UNIX */
140 addr.sa.sa_family = AF_UNIX;
141 L_socksize = sizeof (struct sockaddr_un);
142#else /* NETUNIX */
143# if NETINET
144 /* default to AF_INET */
145 addr.sa.sa_family = AF_INET;
146 L_socksize = sizeof addr.sin;
147# else /* NETINET */
148# if NETINET6
149 /* default to AF_INET6 */
150 addr.sa.sa_family = AF_INET6;
151 L_socksize = sizeof addr.sin6;
152# else /* NETINET6 */
153 /* no protocols available */
154 smi_log(SMI_LOG_ERR,
155 "%s: no valid socket protocols available",
156 name);
157 return INVALID_SOCKET;
158# endif /* NETINET6 */
159# endif /* NETINET */
160#endif /* NETUNIX */
161 }
162#if NETUNIX
163 else if (strcasecmp(p, "unix") == 0 ||
164 strcasecmp(p, "local") == 0)
165 {
166 addr.sa.sa_family = AF_UNIX;
167 L_socksize = sizeof (struct sockaddr_un);
168 }
169#endif /* NETUNIX */
170#if NETINET
171 else if (strcasecmp(p, "inet") == 0)
172 {
173 addr.sa.sa_family = AF_INET;
174 L_socksize = sizeof addr.sin;
175 }
176#endif /* NETINET */
177#if NETINET6
178 else if (strcasecmp(p, "inet6") == 0)
179 {
180 addr.sa.sa_family = AF_INET6;
181 L_socksize = sizeof addr.sin6;
182 }
183#endif /* NETINET6 */
184 else
185 {
186 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
187 name, p);
188 return INVALID_SOCKET;
189 }
190 *colon++ = ':';
191 }
192 else
193 {
194 colon = p;
195#if NETUNIX
196 /* default to AF_UNIX */
197 addr.sa.sa_family = AF_UNIX;
198 L_socksize = sizeof (struct sockaddr_un);
199#else /* NETUNIX */
200# if NETINET
201 /* default to AF_INET */
202 addr.sa.sa_family = AF_INET;
203 L_socksize = sizeof addr.sin;
204# else /* NETINET */
205# if NETINET6
206 /* default to AF_INET6 */
207 addr.sa.sa_family = AF_INET6;
208 L_socksize = sizeof addr.sin6;
209# else /* NETINET6 */
210 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
211 name, p);
212 return INVALID_SOCKET;
213# endif /* NETINET6 */
214# endif /* NETINET */
215#endif /* NETUNIX */
216 }
217
218#if NETUNIX
219 if (addr.sa.sa_family == AF_UNIX)
220 {
221# if 0
222 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
223# endif /* 0 */
224
225 at = colon;
226 len = strlen(colon) + 1;
227 if (len >= sizeof addr.sunix.sun_path)
228 {
229 errno = EINVAL;
230 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
231 name, colon);
232 return INVALID_SOCKET;
233 }
234 (void) sm_strlcpy(addr.sunix.sun_path, colon,
235 sizeof addr.sunix.sun_path);
236# if 0
237 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
238 S_IRUSR|S_IWUSR, NULL);
239
240 /* if not safe, don't create */
241 if (errno != 0)
242 {
243 smi_log(SMI_LOG_ERR,
244 "%s: UNIX socket name %s unsafe",
245 name, colon);
246 return INVALID_SOCKET;
247 }
248# endif /* 0 */
249 }
250#endif /* NETUNIX */
251
252#if NETINET || NETINET6
253 if (
254# if NETINET
255 addr.sa.sa_family == AF_INET
256# endif /* NETINET */
257# if NETINET && NETINET6
258 ||
259# endif /* NETINET && NETINET6 */
260# if NETINET6
261 addr.sa.sa_family == AF_INET6
262# endif /* NETINET6 */
263 )
264 {
265 unsigned short port;
266
267 /* Parse port@host */
268 at = strchr(colon, '@');
269 if (at == NULL)
270 {
271 switch (addr.sa.sa_family)
272 {
273# if NETINET
274 case AF_INET:
275 addr.sin.sin_addr.s_addr = INADDR_ANY;
276 break;
277# endif /* NETINET */
278
279# if NETINET6
280 case AF_INET6:
281 addr.sin6.sin6_addr = in6addr_any;
282 break;
283# endif /* NETINET6 */
284 }
285 }
286 else
287 *at = '\0';
288
289 if (isascii(*colon) && isdigit(*colon))
290 port = htons((unsigned short) atoi(colon));
291 else
292 {
293# ifdef NO_GETSERVBYNAME
294 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
295 name, colon);
296 return INVALID_SOCKET;
297# else /* NO_GETSERVBYNAME */
298 register struct servent *sp;
299
300 sp = getservbyname(colon, "tcp");
301 if (sp == NULL)
302 {
303 smi_log(SMI_LOG_ERR,
304 "%s: unknown port name %s",
305 name, colon);
306 return INVALID_SOCKET;
307 }
308 port = sp->s_port;
309# endif /* NO_GETSERVBYNAME */
310 }
311 if (at != NULL)
312 {
313 *at++ = '@';
314 if (*at == '[')
315 {
316 char *end;
317
318 end = strchr(at, ']');
319 if (end != NULL)
320 {
321 bool found = false;
322# if NETINET
323 unsigned long hid = INADDR_NONE;
324# endif /* NETINET */
325# if NETINET6
326 struct sockaddr_in6 hid6;
327# endif /* NETINET6 */
328
329 *end = '\0';
330# if NETINET
331 if (addr.sa.sa_family == AF_INET &&
332 (hid = inet_addr(&at[1])) != INADDR_NONE)
333 {
334 addr.sin.sin_addr.s_addr = hid;
335 addr.sin.sin_port = port;
336 found = true;
337 }
338# endif /* NETINET */
339# if NETINET6
340 (void) memset(&hid6, '\0', sizeof hid6);
341 if (addr.sa.sa_family == AF_INET6 &&
342 mi_inet_pton(AF_INET6, &at[1],
343 &hid6.sin6_addr) == 1)
344 {
345 addr.sin6.sin6_addr = hid6.sin6_addr;
346 addr.sin6.sin6_port = port;
347 found = true;
348 }
349# endif /* NETINET6 */
350 *end = ']';
351 if (!found)
352 {
353 smi_log(SMI_LOG_ERR,
354 "%s: Invalid numeric domain spec \"%s\"",
355 name, at);
356 return INVALID_SOCKET;
357 }
358 }
359 else
360 {
361 smi_log(SMI_LOG_ERR,
362 "%s: Invalid numeric domain spec \"%s\"",
363 name, at);
364 return INVALID_SOCKET;
365 }
366 }
367 else
368 {
369 struct hostent *hp = NULL;
370
371 hp = mi_gethostbyname(at, addr.sa.sa_family);
372 if (hp == NULL)
373 {
374 smi_log(SMI_LOG_ERR,
375 "%s: Unknown host name %s",
376 name, at);
377 return INVALID_SOCKET;
378 }
379 addr.sa.sa_family = hp->h_addrtype;
380 switch (hp->h_addrtype)
381 {
382# if NETINET
383 case AF_INET:
384 memmove(&addr.sin.sin_addr,
385 hp->h_addr,
386 INADDRSZ);
387 addr.sin.sin_port = port;
388 break;
389# endif /* NETINET */
390
391# if NETINET6
392 case AF_INET6:
393 memmove(&addr.sin6.sin6_addr,
394 hp->h_addr,
395 IN6ADDRSZ);
396 addr.sin6.sin6_port = port;
397 break;
398# endif /* NETINET6 */
399
400 default:
401 smi_log(SMI_LOG_ERR,
402 "%s: Unknown protocol for %s (%d)",
403 name, at, hp->h_addrtype);
404 return INVALID_SOCKET;
405 }
406# if NETINET6
407 freehostent(hp);
408# endif /* NETINET6 */
409 }
410 }
411 else
412 {
413 switch (addr.sa.sa_family)
414 {
415# if NETINET
416 case AF_INET:
417 addr.sin.sin_port = port;
418 break;
419# endif /* NETINET */
420# if NETINET6
421 case AF_INET6:
422 addr.sin6.sin6_port = port;
423 break;
424# endif /* NETINET6 */
425 }
426 }
427 }
428#endif /* NETINET || NETINET6 */
429
430 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
431 if (!ValidSocket(sock))
432 {
433 smi_log(SMI_LOG_ERR,
434 "%s: Unable to create new socket: %s",
435 name, sm_errstring(errno));
436 return INVALID_SOCKET;
437 }
438
439 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
440 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
441 {
442 smi_log(SMI_LOG_ERR,
443 "%s: Unable to set close-on-exec: %s", name,
444 sm_errstring(errno));
445 (void) closesocket(sock);
446 return INVALID_SOCKET;
447 }
448
449 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
450 sizeof(sockopt)) == -1)
451 {
452 smi_log(SMI_LOG_ERR,
453 "%s: Unable to setsockopt: %s", name,
454 sm_errstring(errno));
455 (void) closesocket(sock);
456 return INVALID_SOCKET;
457 }
458
459 if (bind(sock, &addr.sa, L_socksize) < 0)
460 {
461 smi_log(SMI_LOG_ERR,
462 "%s: Unable to bind to port %s: %s",
463 name, conn, sm_errstring(errno));
464 (void) closesocket(sock);
465 return INVALID_SOCKET;
466 }
467
468 if (listen(sock, backlog) < 0)
469 {
470 smi_log(SMI_LOG_ERR,
471 "%s: listen call failed: %s", name,
472 sm_errstring(errno));
473 (void) closesocket(sock);
474 return INVALID_SOCKET;
475 }
476
477#if NETUNIX
478 if (addr.sa.sa_family == AF_UNIX && len > 0)
479 {
480 /*
481 ** Set global variable sockpath so the UNIX socket can be
482 ** unlink()ed at exit.
483 */
484
485 sockpath = (char *) malloc(len);
486 if (sockpath != NULL)
487 (void) sm_strlcpy(sockpath, colon, len);
488 else
489 {
490 smi_log(SMI_LOG_ERR,
491 "%s: can't malloc(%d) for sockpath: %s",
485 name, len, sm_errstring(errno));
492 name, (int) len, sm_errstring(errno));
486 (void) closesocket(sock);
487 return INVALID_SOCKET;
488 }
489 }
490#endif /* NETUNIX */
491 L_family = addr.sa.sa_family;
492 return sock;
493}
494/*
495** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
496**
497** Parameters:
498** arg -- argument to pass to mi_handle_session()
499**
500** Returns:
501** results from mi_handle_session()
502*/
503
504void *
505mi_thread_handle_wrapper(arg)
506 void *arg;
507{
508 return (void *) mi_handle_session(arg);
509}
510
511/*
512** MI_CLOSENER -- close listen socket
513**
514** NOTE: It is assumed that this function is called from a
515** function that has a mutex lock (currently mi_stop_milters()).
516**
517** Parameters:
518** none.
519**
520** Returns:
521** none.
522*/
523
524void
525mi_closener()
526{
527 (void) smutex_lock(&L_Mutex);
528 if (ValidSocket(listenfd))
529 {
530#if NETUNIX
531 bool removable;
532 struct stat sockinfo;
533 struct stat fileinfo;
534
535 removable = sockpath != NULL &&
536#if _FFR_MILTER_ROOT_UNSAFE
537 geteuid() != 0 &&
538#endif /* _FFR_MILTER_ROOT_UNSAFE */
539 fstat(listenfd, &sockinfo) == 0 &&
540 (S_ISFIFO(sockinfo.st_mode)
541# ifdef S_ISSOCK
542 || S_ISSOCK(sockinfo.st_mode)
543# endif /* S_ISSOCK */
544 );
545#endif /* NETUNIX */
546
547 (void) closesocket(listenfd);
548 listenfd = INVALID_SOCKET;
549
550#if NETUNIX
551 /* XXX sleep() some time before doing this? */
552 if (sockpath != NULL)
553 {
554 if (removable &&
555 stat(sockpath, &fileinfo) == 0 &&
556 ((fileinfo.st_dev == sockinfo.st_dev &&
557 fileinfo.st_ino == sockinfo.st_ino)
558# ifdef S_ISSOCK
559 || S_ISSOCK(fileinfo.st_mode)
560# endif /* S_ISSOCK */
561 )
562 &&
563 (S_ISFIFO(fileinfo.st_mode)
564# ifdef S_ISSOCK
565 || S_ISSOCK(fileinfo.st_mode)
566# endif /* S_ISSOCK */
567 ))
568 (void) unlink(sockpath);
569 free(sockpath);
570 sockpath = NULL;
571 }
572#endif /* NETUNIX */
573 }
574 (void) smutex_unlock(&L_Mutex);
575}
576
577/*
578** MI_LISTENER -- Generic listener harness
579**
580** Open up listen port
581** Wait for connections
582**
583** Parameters:
584** conn -- connection description
585** dbg -- debug level
586** smfi -- filter structure to use
587** timeout -- timeout for reads/writes
588** backlog -- listen queue backlog size
589**
590** Returns:
591** MI_SUCCESS -- Exited normally
592** (session finished or we were told to exit)
593** MI_FAILURE -- Network initialization failed.
594*/
595
596#if BROKEN_PTHREAD_SLEEP
597
598/*
599** Solaris 2.6, perhaps others, gets an internal threads library panic
600** when sleep() is used:
601**
602** thread_create() failed, returned 11 (EINVAL)
603** co_enable, thr_create() returned error = 24
604** libthread panic: co_enable failed (PID: 17793 LWP 1)
605** stacktrace:
606** ef526b10
607** ef52646c
608** ef534cbc
609** 156a4
610** 14644
611** 1413c
612** 135e0
613** 0
614*/
615
616# define MI_SLEEP(s) \
617{ \
618 int rs = 0; \
619 struct timeval st; \
620 \
621 st.tv_sec = (s); \
622 st.tv_usec = 0; \
623 if (st.tv_sec > 0) \
624 { \
625 for (;;) \
626 { \
627 rs = select(0, NULL, NULL, NULL, &st); \
628 if (rs < 0 && errno == EINTR) \
629 continue; \
630 if (rs != 0) \
631 { \
632 smi_log(SMI_LOG_ERR, \
493 (void) closesocket(sock);
494 return INVALID_SOCKET;
495 }
496 }
497#endif /* NETUNIX */
498 L_family = addr.sa.sa_family;
499 return sock;
500}
501/*
502** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
503**
504** Parameters:
505** arg -- argument to pass to mi_handle_session()
506**
507** Returns:
508** results from mi_handle_session()
509*/
510
511void *
512mi_thread_handle_wrapper(arg)
513 void *arg;
514{
515 return (void *) mi_handle_session(arg);
516}
517
518/*
519** MI_CLOSENER -- close listen socket
520**
521** NOTE: It is assumed that this function is called from a
522** function that has a mutex lock (currently mi_stop_milters()).
523**
524** Parameters:
525** none.
526**
527** Returns:
528** none.
529*/
530
531void
532mi_closener()
533{
534 (void) smutex_lock(&L_Mutex);
535 if (ValidSocket(listenfd))
536 {
537#if NETUNIX
538 bool removable;
539 struct stat sockinfo;
540 struct stat fileinfo;
541
542 removable = sockpath != NULL &&
543#if _FFR_MILTER_ROOT_UNSAFE
544 geteuid() != 0 &&
545#endif /* _FFR_MILTER_ROOT_UNSAFE */
546 fstat(listenfd, &sockinfo) == 0 &&
547 (S_ISFIFO(sockinfo.st_mode)
548# ifdef S_ISSOCK
549 || S_ISSOCK(sockinfo.st_mode)
550# endif /* S_ISSOCK */
551 );
552#endif /* NETUNIX */
553
554 (void) closesocket(listenfd);
555 listenfd = INVALID_SOCKET;
556
557#if NETUNIX
558 /* XXX sleep() some time before doing this? */
559 if (sockpath != NULL)
560 {
561 if (removable &&
562 stat(sockpath, &fileinfo) == 0 &&
563 ((fileinfo.st_dev == sockinfo.st_dev &&
564 fileinfo.st_ino == sockinfo.st_ino)
565# ifdef S_ISSOCK
566 || S_ISSOCK(fileinfo.st_mode)
567# endif /* S_ISSOCK */
568 )
569 &&
570 (S_ISFIFO(fileinfo.st_mode)
571# ifdef S_ISSOCK
572 || S_ISSOCK(fileinfo.st_mode)
573# endif /* S_ISSOCK */
574 ))
575 (void) unlink(sockpath);
576 free(sockpath);
577 sockpath = NULL;
578 }
579#endif /* NETUNIX */
580 }
581 (void) smutex_unlock(&L_Mutex);
582}
583
584/*
585** MI_LISTENER -- Generic listener harness
586**
587** Open up listen port
588** Wait for connections
589**
590** Parameters:
591** conn -- connection description
592** dbg -- debug level
593** smfi -- filter structure to use
594** timeout -- timeout for reads/writes
595** backlog -- listen queue backlog size
596**
597** Returns:
598** MI_SUCCESS -- Exited normally
599** (session finished or we were told to exit)
600** MI_FAILURE -- Network initialization failed.
601*/
602
603#if BROKEN_PTHREAD_SLEEP
604
605/*
606** Solaris 2.6, perhaps others, gets an internal threads library panic
607** when sleep() is used:
608**
609** thread_create() failed, returned 11 (EINVAL)
610** co_enable, thr_create() returned error = 24
611** libthread panic: co_enable failed (PID: 17793 LWP 1)
612** stacktrace:
613** ef526b10
614** ef52646c
615** ef534cbc
616** 156a4
617** 14644
618** 1413c
619** 135e0
620** 0
621*/
622
623# define MI_SLEEP(s) \
624{ \
625 int rs = 0; \
626 struct timeval st; \
627 \
628 st.tv_sec = (s); \
629 st.tv_usec = 0; \
630 if (st.tv_sec > 0) \
631 { \
632 for (;;) \
633 { \
634 rs = select(0, NULL, NULL, NULL, &st); \
635 if (rs < 0 && errno == EINTR) \
636 continue; \
637 if (rs != 0) \
638 { \
639 smi_log(SMI_LOG_ERR, \
633 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
640 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
634 rs, errno); \
635 } \
641 rs, errno); \
642 } \
643 break; \
636 } \
637 } \
638}
639#else /* BROKEN_PTHREAD_SLEEP */
640# define MI_SLEEP(s) sleep((s))
641#endif /* BROKEN_PTHREAD_SLEEP */
642
643int
644mi_listener(conn, dbg, smfi, timeout, backlog)
645 char *conn;
646 int dbg;
647 smfiDesc_ptr smfi;
648 time_t timeout;
649 int backlog;
650{
651 socket_t connfd = INVALID_SOCKET;
652 int sockopt = 1;
653 int r;
654 int ret = MI_SUCCESS;
655 int mcnt = 0; /* error count for malloc() failures */
656 int tcnt = 0; /* error count for thread_create() failures */
657 int acnt = 0; /* error count for accept() failures */
658 int scnt = 0; /* error count for select() failures */
659 int save_errno = 0;
660 sthread_t thread_id;
661 _SOCK_ADDR cliaddr;
662 SOCKADDR_LEN_T clilen;
663 SMFICTX_PTR ctx;
664 fd_set readset, excset;
665 struct timeval chktime;
666
667 if (mi_opensocket(conn, backlog, dbg, smfi) == MI_FAILURE)
668 return MI_FAILURE;
669
670 clilen = L_socksize;
644 } \
645 } \
646}
647#else /* BROKEN_PTHREAD_SLEEP */
648# define MI_SLEEP(s) sleep((s))
649#endif /* BROKEN_PTHREAD_SLEEP */
650
651int
652mi_listener(conn, dbg, smfi, timeout, backlog)
653 char *conn;
654 int dbg;
655 smfiDesc_ptr smfi;
656 time_t timeout;
657 int backlog;
658{
659 socket_t connfd = INVALID_SOCKET;
660 int sockopt = 1;
661 int r;
662 int ret = MI_SUCCESS;
663 int mcnt = 0; /* error count for malloc() failures */
664 int tcnt = 0; /* error count for thread_create() failures */
665 int acnt = 0; /* error count for accept() failures */
666 int scnt = 0; /* error count for select() failures */
667 int save_errno = 0;
668 sthread_t thread_id;
669 _SOCK_ADDR cliaddr;
670 SOCKADDR_LEN_T clilen;
671 SMFICTX_PTR ctx;
672 fd_set readset, excset;
673 struct timeval chktime;
674
675 if (mi_opensocket(conn, backlog, dbg, smfi) == MI_FAILURE)
676 return MI_FAILURE;
677
678 clilen = L_socksize;
671
672 if (listenfd >= FD_SETSIZE)
673 {
674 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
675 smfi->xxfi_name, listenfd, FD_SETSIZE);
676 (void) smutex_unlock(&L_Mutex);
677 return MI_FAILURE;
678 }
679 (void) smutex_unlock(&L_Mutex);
679 (void) smutex_unlock(&L_Mutex);
680
681 while (mi_stop() == MILTER_CONT)
682 {
683 (void) smutex_lock(&L_Mutex);
684 if (!ValidSocket(listenfd))
685 {
686 (void) smutex_unlock(&L_Mutex);
687 break;
688 }
689
690 /* select on interface ports */
691 FD_ZERO(&readset);
692 FD_ZERO(&excset);
693 FD_SET((unsigned int) listenfd, &readset);
694 FD_SET((unsigned int) listenfd, &excset);
695 chktime.tv_sec = MI_CHK_TIME;
696 chktime.tv_usec = 0;
697 r = select(listenfd + 1, &readset, NULL, &excset, &chktime);
698 if (r == 0) /* timeout */
699 {
700 (void) smutex_unlock(&L_Mutex);
701 continue; /* just check mi_stop() */
702 }
703 if (r < 0)
704 {
705 save_errno = errno;
706 (void) smutex_unlock(&L_Mutex);
707 if (save_errno == EINTR)
708 continue;
709 scnt++;
710 smi_log(SMI_LOG_ERR,
711 "%s: select() failed (%s), %s",
712 smfi->xxfi_name, sm_errstring(save_errno),
713 scnt >= MAX_FAILS_S ? "abort" : "try again");
714 MI_SLEEP(scnt);
715 if (scnt >= MAX_FAILS_S)
716 {
717 ret = MI_FAILURE;
718 break;
719 }
720 continue;
721 }
722 if (!FD_ISSET(listenfd, &readset))
723 {
724 /* some error: just stop for now... */
725 ret = MI_FAILURE;
726 (void) smutex_unlock(&L_Mutex);
727 smi_log(SMI_LOG_ERR,
728 "%s: select() returned exception for socket, abort",
729 smfi->xxfi_name);
730 break;
731 }
732 scnt = 0; /* reset error counter for select() */
733
734 memset(&cliaddr, '\0', sizeof cliaddr);
735 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
736 &clilen);
737 save_errno = errno;
738 (void) smutex_unlock(&L_Mutex);
739
740 /*
741 ** If remote side closes before
742 ** accept() finishes, sockaddr
743 ** might not be fully filled in.
744 */
745
746 if (ValidSocket(connfd) &&
747 (clilen == 0 ||
748# ifdef BSD4_4_SOCKADDR
749 cliaddr.sa.sa_len == 0 ||
750# endif /* BSD4_4_SOCKADDR */
751 cliaddr.sa.sa_family != L_family))
752 {
753 (void) closesocket(connfd);
754 connfd = INVALID_SOCKET;
755 save_errno = EINVAL;
756 }
757
680 while (mi_stop() == MILTER_CONT)
681 {
682 (void) smutex_lock(&L_Mutex);
683 if (!ValidSocket(listenfd))
684 {
685 (void) smutex_unlock(&L_Mutex);
686 break;
687 }
688
689 /* select on interface ports */
690 FD_ZERO(&readset);
691 FD_ZERO(&excset);
692 FD_SET((unsigned int) listenfd, &readset);
693 FD_SET((unsigned int) listenfd, &excset);
694 chktime.tv_sec = MI_CHK_TIME;
695 chktime.tv_usec = 0;
696 r = select(listenfd + 1, &readset, NULL, &excset, &chktime);
697 if (r == 0) /* timeout */
698 {
699 (void) smutex_unlock(&L_Mutex);
700 continue; /* just check mi_stop() */
701 }
702 if (r < 0)
703 {
704 save_errno = errno;
705 (void) smutex_unlock(&L_Mutex);
706 if (save_errno == EINTR)
707 continue;
708 scnt++;
709 smi_log(SMI_LOG_ERR,
710 "%s: select() failed (%s), %s",
711 smfi->xxfi_name, sm_errstring(save_errno),
712 scnt >= MAX_FAILS_S ? "abort" : "try again");
713 MI_SLEEP(scnt);
714 if (scnt >= MAX_FAILS_S)
715 {
716 ret = MI_FAILURE;
717 break;
718 }
719 continue;
720 }
721 if (!FD_ISSET(listenfd, &readset))
722 {
723 /* some error: just stop for now... */
724 ret = MI_FAILURE;
725 (void) smutex_unlock(&L_Mutex);
726 smi_log(SMI_LOG_ERR,
727 "%s: select() returned exception for socket, abort",
728 smfi->xxfi_name);
729 break;
730 }
731 scnt = 0; /* reset error counter for select() */
732
733 memset(&cliaddr, '\0', sizeof cliaddr);
734 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
735 &clilen);
736 save_errno = errno;
737 (void) smutex_unlock(&L_Mutex);
738
739 /*
740 ** If remote side closes before
741 ** accept() finishes, sockaddr
742 ** might not be fully filled in.
743 */
744
745 if (ValidSocket(connfd) &&
746 (clilen == 0 ||
747# ifdef BSD4_4_SOCKADDR
748 cliaddr.sa.sa_len == 0 ||
749# endif /* BSD4_4_SOCKADDR */
750 cliaddr.sa.sa_family != L_family))
751 {
752 (void) closesocket(connfd);
753 connfd = INVALID_SOCKET;
754 save_errno = EINVAL;
755 }
756
757 /* check if acceptable for select() */
758 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
759 {
760 (void) closesocket(connfd);
761 connfd = INVALID_SOCKET;
762 save_errno = ERANGE;
763 }
764
758 if (!ValidSocket(connfd))
759 {
760 if (save_errno == EINTR)
761 continue;
762 acnt++;
763 smi_log(SMI_LOG_ERR,
764 "%s: accept() returned invalid socket (%s), %s",
765 smfi->xxfi_name, sm_errstring(save_errno),
766 acnt >= MAX_FAILS_A ? "abort" : "try again");
767 MI_SLEEP(acnt);
768 if (acnt >= MAX_FAILS_A)
769 {
770 ret = MI_FAILURE;
771 break;
772 }
773 continue;
774 }
775 acnt = 0; /* reset error counter for accept() */
776
777 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
778 (void *) &sockopt, sizeof sockopt) < 0)
779 {
780 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
781 smfi->xxfi_name, sm_errstring(errno));
782 /* XXX: continue? */
783 }
784 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
785 {
786 (void) closesocket(connfd);
787 mcnt++;
788 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
789 smfi->xxfi_name, sm_errstring(save_errno),
790 mcnt >= MAX_FAILS_M ? "abort" : "try again");
791 MI_SLEEP(mcnt);
792 if (mcnt >= MAX_FAILS_M)
793 {
794 ret = MI_FAILURE;
795 break;
796 }
797 continue;
798 }
799 mcnt = 0; /* reset error counter for malloc() */
800 memset(ctx, '\0', sizeof *ctx);
801 ctx->ctx_sd = connfd;
802 ctx->ctx_dbg = dbg;
803 ctx->ctx_timeout = timeout;
804 ctx->ctx_smfi = smfi;
805#if 0
806 if (smfi->xxfi_eoh == NULL)
807 if (smfi->xxfi_eom == NULL)
808 if (smfi->xxfi_abort == NULL)
809 if (smfi->xxfi_close == NULL)
810#endif /* 0 */
811 if (smfi->xxfi_connect == NULL)
812 ctx->ctx_pflags |= SMFIP_NOCONNECT;
813 if (smfi->xxfi_helo == NULL)
814 ctx->ctx_pflags |= SMFIP_NOHELO;
815 if (smfi->xxfi_envfrom == NULL)
816 ctx->ctx_pflags |= SMFIP_NOMAIL;
817 if (smfi->xxfi_envrcpt == NULL)
818 ctx->ctx_pflags |= SMFIP_NORCPT;
819 if (smfi->xxfi_header == NULL)
820 ctx->ctx_pflags |= SMFIP_NOHDRS;
821 if (smfi->xxfi_eoh == NULL)
822 ctx->ctx_pflags |= SMFIP_NOEOH;
823 if (smfi->xxfi_body == NULL)
824 ctx->ctx_pflags |= SMFIP_NOBODY;
825
826 if ((r = thread_create(&thread_id,
827 mi_thread_handle_wrapper,
828 (void *) ctx)) != 0)
829 {
830 tcnt++;
831 smi_log(SMI_LOG_ERR,
832 "%s: thread_create() failed: %d, %s",
833 smfi->xxfi_name, r,
834 tcnt >= MAX_FAILS_T ? "abort" : "try again");
835 MI_SLEEP(tcnt);
836 (void) closesocket(connfd);
837 free(ctx);
838 if (tcnt >= MAX_FAILS_T)
839 {
840 ret = MI_FAILURE;
841 break;
842 }
843 continue;
844 }
845 tcnt = 0;
846 }
847 if (ret != MI_SUCCESS)
848 mi_stop_milters(MILTER_ABRT);
849 else
850 mi_closener();
851 (void) smutex_destroy(&L_Mutex);
852 return ret;
853}
765 if (!ValidSocket(connfd))
766 {
767 if (save_errno == EINTR)
768 continue;
769 acnt++;
770 smi_log(SMI_LOG_ERR,
771 "%s: accept() returned invalid socket (%s), %s",
772 smfi->xxfi_name, sm_errstring(save_errno),
773 acnt >= MAX_FAILS_A ? "abort" : "try again");
774 MI_SLEEP(acnt);
775 if (acnt >= MAX_FAILS_A)
776 {
777 ret = MI_FAILURE;
778 break;
779 }
780 continue;
781 }
782 acnt = 0; /* reset error counter for accept() */
783
784 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
785 (void *) &sockopt, sizeof sockopt) < 0)
786 {
787 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed (%s)",
788 smfi->xxfi_name, sm_errstring(errno));
789 /* XXX: continue? */
790 }
791 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
792 {
793 (void) closesocket(connfd);
794 mcnt++;
795 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
796 smfi->xxfi_name, sm_errstring(save_errno),
797 mcnt >= MAX_FAILS_M ? "abort" : "try again");
798 MI_SLEEP(mcnt);
799 if (mcnt >= MAX_FAILS_M)
800 {
801 ret = MI_FAILURE;
802 break;
803 }
804 continue;
805 }
806 mcnt = 0; /* reset error counter for malloc() */
807 memset(ctx, '\0', sizeof *ctx);
808 ctx->ctx_sd = connfd;
809 ctx->ctx_dbg = dbg;
810 ctx->ctx_timeout = timeout;
811 ctx->ctx_smfi = smfi;
812#if 0
813 if (smfi->xxfi_eoh == NULL)
814 if (smfi->xxfi_eom == NULL)
815 if (smfi->xxfi_abort == NULL)
816 if (smfi->xxfi_close == NULL)
817#endif /* 0 */
818 if (smfi->xxfi_connect == NULL)
819 ctx->ctx_pflags |= SMFIP_NOCONNECT;
820 if (smfi->xxfi_helo == NULL)
821 ctx->ctx_pflags |= SMFIP_NOHELO;
822 if (smfi->xxfi_envfrom == NULL)
823 ctx->ctx_pflags |= SMFIP_NOMAIL;
824 if (smfi->xxfi_envrcpt == NULL)
825 ctx->ctx_pflags |= SMFIP_NORCPT;
826 if (smfi->xxfi_header == NULL)
827 ctx->ctx_pflags |= SMFIP_NOHDRS;
828 if (smfi->xxfi_eoh == NULL)
829 ctx->ctx_pflags |= SMFIP_NOEOH;
830 if (smfi->xxfi_body == NULL)
831 ctx->ctx_pflags |= SMFIP_NOBODY;
832
833 if ((r = thread_create(&thread_id,
834 mi_thread_handle_wrapper,
835 (void *) ctx)) != 0)
836 {
837 tcnt++;
838 smi_log(SMI_LOG_ERR,
839 "%s: thread_create() failed: %d, %s",
840 smfi->xxfi_name, r,
841 tcnt >= MAX_FAILS_T ? "abort" : "try again");
842 MI_SLEEP(tcnt);
843 (void) closesocket(connfd);
844 free(ctx);
845 if (tcnt >= MAX_FAILS_T)
846 {
847 ret = MI_FAILURE;
848 break;
849 }
850 continue;
851 }
852 tcnt = 0;
853 }
854 if (ret != MI_SUCCESS)
855 mi_stop_milters(MILTER_ABRT);
856 else
857 mi_closener();
858 (void) smutex_destroy(&L_Mutex);
859 return ret;
860}