Deleted Added
full compact
listener.c (302408) listener.c (64562)
1/*
1/*
2 * Copyright (c) 1999-2007 Proofpoint, Inc. and its suppliers.
2 * Copyright (c) 1999-2000 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
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.127 2013-11-22 20:51:36 ca Exp $")
11#ifndef lint
12static char id[] = "@(#)$Id: listener.c,v 8.38.2.1.2.7 2000/05/25 21:44:26 gshapiro Exp $";
13#endif /* ! lint */
13
14
15#if _FFR_MILTER
14/*
15** listener.c -- threaded network listener
16*/
17
18#include "libmilter.h"
16/*
17** listener.c -- threaded network listener
18*/
19
20#include "libmilter.h"
19#include <sm/errstring.h>
20
21
21#include <sys/types.h>
22#include <sys/stat.h>
23
22
24
25# if NETINET || NETINET6
26# include <arpa/inet.h>
27# endif /* NETINET || NETINET6 */
23# if NETINET || NETINET6
24# include <arpa/inet.h>
25# endif /* NETINET || NETINET6 */
28# if SM_CONF_POLL
29# undef SM_FD_OK_SELECT
30# define SM_FD_OK_SELECT(fd) true
31# endif /* SM_CONF_POLL */
32
33static smutex_t L_Mutex;
34static int L_family;
35static SOCKADDR_LEN_T L_socksize;
36static socket_t listenfd = INVALID_SOCKET;
37
38static socket_t mi_milteropen __P((char *, int, bool, char *));
39#if !_FFR_WORKERS_POOL
40static void *mi_thread_handle_wrapper __P((void *));
41#endif /* !_FFR_WORKERS_POOL */
42
43/*
44** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet
45**
46** Parameters:
47** conn -- connection description
48** backlog -- listen backlog
49** dbg -- debug level
50** rmsocket -- if true, try to unlink() the socket first
51** (UNIX domain sockets only)
52** smfi -- filter structure to use
53**
54** Return value:
55** MI_SUCCESS/MI_FAILURE
56*/
57
58int
59mi_opensocket(conn, backlog, dbg, rmsocket, smfi)
60 char *conn;
61 int backlog;
62 int dbg;
63 bool rmsocket;
64 smfiDesc_ptr smfi;
65{
66 if (smfi == NULL || conn == NULL)
67 return MI_FAILURE;
68
69 if (ValidSocket(listenfd))
70 return MI_SUCCESS;
71
72 if (dbg > 0)
73 {
74 smi_log(SMI_LOG_DEBUG,
75 "%s: Opening listen socket on conn %s",
76 smfi->xxfi_name, conn);
77 }
78 (void) smutex_init(&L_Mutex);
79 (void) smutex_lock(&L_Mutex);
80 listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name);
81 if (!ValidSocket(listenfd))
82 {
83 smi_log(SMI_LOG_FATAL,
84 "%s: Unable to create listening socket on conn %s",
85 smfi->xxfi_name, conn);
86 (void) smutex_unlock(&L_Mutex);
87 return MI_FAILURE;
88 }
89 if (!SM_FD_OK_SELECT(listenfd))
90 {
91 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
92 smfi->xxfi_name, listenfd, FD_SETSIZE);
93 (void) smutex_unlock(&L_Mutex);
94 return MI_FAILURE;
95 }
96 (void) smutex_unlock(&L_Mutex);
97 return MI_SUCCESS;
98}
99
100/*
26 /*
101** MI_MILTEROPEN -- setup socket to listen on
102**
103** Parameters:
104** conn -- connection description
105** backlog -- listen backlog
27** MI_MILTEROPEN -- setup socket to listen on
28**
29** Parameters:
30** conn -- connection description
31** backlog -- listen backlog
106** rmsocket -- if true, try to unlink() the socket first
107** (UNIX domain sockets only)
108** name -- name for logging
32** socksize -- socksize of created socket
109**
110** Returns:
111** socket upon success, error code otherwise.
33**
34** Returns:
35** socket upon success, error code otherwise.
112**
113** Side effect:
114** sets sockpath if UNIX socket.
115*/
116
36*/
37
117#if NETUNIX
118static char *sockpath = NULL;
119#endif /* NETUNIX */
120
121static socket_t
122mi_milteropen(conn, backlog, rmsocket, name)
38static int
39mi_milteropen(conn, backlog, socksize, name)
123 char *conn;
124 int backlog;
40 char *conn;
41 int backlog;
125 bool rmsocket;
42 SOCKADDR_LEN_T *socksize;
126 char *name;
127{
43 char *name;
44{
128 socket_t sock;
45 int sock = 0;
129 int sockopt = 1;
46 int sockopt = 1;
130 int fdflags;
131 size_t len = 0;
132 char *p;
133 char *colon;
134 char *at;
47 char *p;
48 char *colon;
49 char *at;
50 struct hostent *hp = NULL;
135 SOCKADDR addr;
136
137 if (conn == NULL || conn[0] == '\0')
138 {
139 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
140 name);
51 SOCKADDR addr;
52
53 if (conn == NULL || conn[0] == '\0')
54 {
55 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information",
56 name);
141 return INVALID_SOCKET;
57 return MI_INVALID_SOCKET;
142 }
143 (void) memset(&addr, '\0', sizeof addr);
144
145 /* protocol:filename or protocol:port@host */
146 p = conn;
147 colon = strchr(p, ':');
148 if (colon != NULL)
149 {
150 *colon = '\0';
151
58 }
59 (void) memset(&addr, '\0', sizeof addr);
60
61 /* protocol:filename or protocol:port@host */
62 p = conn;
63 colon = strchr(p, ':');
64 if (colon != NULL)
65 {
66 *colon = '\0';
67
152 if (*p == '\0')
68 if (*p == '\0')
153 {
154#if NETUNIX
155 /* default to AF_UNIX */
69 {
70#if NETUNIX
71 /* default to AF_UNIX */
156 addr.sa.sa_family = AF_UNIX;
157 L_socksize = sizeof (struct sockaddr_un);
72 addr.sa.sa_family = AF_UNIX;
73 *socksize = sizeof (struct sockaddr_un);
158#else /* NETUNIX */
159# if NETINET
160 /* default to AF_INET */
161 addr.sa.sa_family = AF_INET;
74#else /* NETUNIX */
75# if NETINET
76 /* default to AF_INET */
77 addr.sa.sa_family = AF_INET;
162 L_socksize = sizeof addr.sin;
78 *socksize = sizeof addr.sin;
163# else /* NETINET */
164# if NETINET6
165 /* default to AF_INET6 */
166 addr.sa.sa_family = AF_INET6;
79# else /* NETINET */
80# if NETINET6
81 /* default to AF_INET6 */
82 addr.sa.sa_family = AF_INET6;
167 L_socksize = sizeof addr.sin6;
83 *socksize = sizeof addr.sin6;
168# else /* NETINET6 */
169 /* no protocols available */
170 smi_log(SMI_LOG_ERR,
171 "%s: no valid socket protocols available",
172 name);
84# else /* NETINET6 */
85 /* no protocols available */
86 smi_log(SMI_LOG_ERR,
87 "%s: no valid socket protocols available",
88 name);
173 return INVALID_SOCKET;
89 return MI_INVALID_SOCKET;
174# endif /* NETINET6 */
175# endif /* NETINET */
176#endif /* NETUNIX */
177 }
178#if NETUNIX
179 else if (strcasecmp(p, "unix") == 0 ||
180 strcasecmp(p, "local") == 0)
181 {
182 addr.sa.sa_family = AF_UNIX;
90# endif /* NETINET6 */
91# endif /* NETINET */
92#endif /* NETUNIX */
93 }
94#if NETUNIX
95 else if (strcasecmp(p, "unix") == 0 ||
96 strcasecmp(p, "local") == 0)
97 {
98 addr.sa.sa_family = AF_UNIX;
183 L_socksize = sizeof (struct sockaddr_un);
99 *socksize = sizeof (struct sockaddr_un);
184 }
185#endif /* NETUNIX */
186#if NETINET
187 else if (strcasecmp(p, "inet") == 0)
188 {
189 addr.sa.sa_family = AF_INET;
100 }
101#endif /* NETUNIX */
102#if NETINET
103 else if (strcasecmp(p, "inet") == 0)
104 {
105 addr.sa.sa_family = AF_INET;
190 L_socksize = sizeof addr.sin;
106 *socksize = sizeof addr.sin;
191 }
192#endif /* NETINET */
193#if NETINET6
194 else if (strcasecmp(p, "inet6") == 0)
195 {
196 addr.sa.sa_family = AF_INET6;
107 }
108#endif /* NETINET */
109#if NETINET6
110 else if (strcasecmp(p, "inet6") == 0)
111 {
112 addr.sa.sa_family = AF_INET6;
197 L_socksize = sizeof addr.sin6;
113 *socksize = sizeof addr.sin6;
198 }
199#endif /* NETINET6 */
200 else
201 {
202 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
203 name, p);
114 }
115#endif /* NETINET6 */
116 else
117 {
118 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
119 name, p);
204 return INVALID_SOCKET;
120 return MI_INVALID_SOCKET;
205 }
206 *colon++ = ':';
207 }
208 else
209 {
210 colon = p;
211#if NETUNIX
212 /* default to AF_UNIX */
121 }
122 *colon++ = ':';
123 }
124 else
125 {
126 colon = p;
127#if NETUNIX
128 /* default to AF_UNIX */
213 addr.sa.sa_family = AF_UNIX;
214 L_socksize = sizeof (struct sockaddr_un);
129 addr.sa.sa_family = AF_UNIX;
130 *socksize = sizeof (struct sockaddr_un);
215#else /* NETUNIX */
216# if NETINET
217 /* default to AF_INET */
218 addr.sa.sa_family = AF_INET;
131#else /* NETUNIX */
132# if NETINET
133 /* default to AF_INET */
134 addr.sa.sa_family = AF_INET;
219 L_socksize = sizeof addr.sin;
135 *socksize = sizeof addr.sin;
220# else /* NETINET */
221# if NETINET6
222 /* default to AF_INET6 */
223 addr.sa.sa_family = AF_INET6;
136# else /* NETINET */
137# if NETINET6
138 /* default to AF_INET6 */
139 addr.sa.sa_family = AF_INET6;
224 L_socksize = sizeof addr.sin6;
140 *socksize = sizeof addr.sin6;
225# else /* NETINET6 */
226 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
227 name, p);
141# else /* NETINET6 */
142 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s",
143 name, p);
228 return INVALID_SOCKET;
144 return MI_INVALID_SOCKET;
229# endif /* NETINET6 */
230# endif /* NETINET */
231#endif /* NETUNIX */
232 }
233
234#if NETUNIX
235 if (addr.sa.sa_family == AF_UNIX)
236 {
237# if 0
238 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
239# endif /* 0 */
240
241 at = colon;
145# endif /* NETINET6 */
146# endif /* NETINET */
147#endif /* NETUNIX */
148 }
149
150#if NETUNIX
151 if (addr.sa.sa_family == AF_UNIX)
152 {
153# if 0
154 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
155# endif /* 0 */
156
157 at = colon;
242 len = strlen(colon) + 1;
243 if (len >= sizeof addr.sunix.sun_path)
158 if (strlcpy(addr.sunix.sun_path, colon,
159 sizeof addr.sunix.sun_path) >=
160 sizeof addr.sunix.sun_path)
244 {
245 errno = EINVAL;
246 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
247 name, colon);
161 {
162 errno = EINVAL;
163 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long",
164 name, colon);
248 return INVALID_SOCKET;
165 return MI_INVALID_SOCKET;
249 }
166 }
250 (void) sm_strlcpy(addr.sunix.sun_path, colon,
251 sizeof addr.sunix.sun_path);
252# if 0
253 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
254 S_IRUSR|S_IWUSR, NULL);
255
256 /* if not safe, don't create */
257 if (errno != 0)
258 {
259 smi_log(SMI_LOG_ERR,
260 "%s: UNIX socket name %s unsafe",
261 name, colon);
167# if 0
168 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
169 S_IRUSR|S_IWUSR, NULL);
170
171 /* if not safe, don't create */
172 if (errno != 0)
173 {
174 smi_log(SMI_LOG_ERR,
175 "%s: UNIX socket name %s unsafe",
176 name, colon);
262 return INVALID_SOCKET;
177 return MI_INVALID_SOCKET;
263 }
264# endif /* 0 */
178 }
179# endif /* 0 */
180
265 }
266#endif /* NETUNIX */
267
268#if NETINET || NETINET6
269 if (
270# if NETINET
271 addr.sa.sa_family == AF_INET
272# endif /* NETINET */
273# if NETINET && NETINET6
274 ||
275# endif /* NETINET && NETINET6 */
276# if NETINET6
277 addr.sa.sa_family == AF_INET6
278# endif /* NETINET6 */
279 )
280 {
181 }
182#endif /* NETUNIX */
183
184#if NETINET || NETINET6
185 if (
186# if NETINET
187 addr.sa.sa_family == AF_INET
188# endif /* NETINET */
189# if NETINET && NETINET6
190 ||
191# endif /* NETINET && NETINET6 */
192# if NETINET6
193 addr.sa.sa_family == AF_INET6
194# endif /* NETINET6 */
195 )
196 {
281 unsigned short port;
197 u_short port;
282
283 /* Parse port@host */
284 at = strchr(colon, '@');
285 if (at == NULL)
286 {
287 switch (addr.sa.sa_family)
288 {
289# if NETINET

--- 8 unchanged lines hidden (view full) ---

298 break;
299# endif /* NETINET6 */
300 }
301 }
302 else
303 *at = '\0';
304
305 if (isascii(*colon) && isdigit(*colon))
198
199 /* Parse port@host */
200 at = strchr(colon, '@');
201 if (at == NULL)
202 {
203 switch (addr.sa.sa_family)
204 {
205# if NETINET

--- 8 unchanged lines hidden (view full) ---

214 break;
215# endif /* NETINET6 */
216 }
217 }
218 else
219 *at = '\0';
220
221 if (isascii(*colon) && isdigit(*colon))
306 port = htons((unsigned short) atoi(colon));
222 port = htons((u_short) atoi(colon));
307 else
308 {
309# ifdef NO_GETSERVBYNAME
310 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
311 name, colon);
223 else
224 {
225# ifdef NO_GETSERVBYNAME
226 smi_log(SMI_LOG_ERR, "%s: invalid port number %s",
227 name, colon);
312 return INVALID_SOCKET;
228 return MI_INVALID_SOCKET;
313# else /* NO_GETSERVBYNAME */
314 register struct servent *sp;
315
316 sp = getservbyname(colon, "tcp");
317 if (sp == NULL)
318 {
319 smi_log(SMI_LOG_ERR,
320 "%s: unknown port name %s",
321 name, colon);
229# else /* NO_GETSERVBYNAME */
230 register struct servent *sp;
231
232 sp = getservbyname(colon, "tcp");
233 if (sp == NULL)
234 {
235 smi_log(SMI_LOG_ERR,
236 "%s: unknown port name %s",
237 name, colon);
322 return INVALID_SOCKET;
238 return MI_INVALID_SOCKET;
323 }
324 port = sp->s_port;
325# endif /* NO_GETSERVBYNAME */
326 }
327 if (at != NULL)
328 {
329 *at++ = '@';
330 if (*at == '[')
331 {
332 char *end;
333
334 end = strchr(at, ']');
335 if (end != NULL)
336 {
239 }
240 port = sp->s_port;
241# endif /* NO_GETSERVBYNAME */
242 }
243 if (at != NULL)
244 {
245 *at++ = '@';
246 if (*at == '[')
247 {
248 char *end;
249
250 end = strchr(at, ']');
251 if (end != NULL)
252 {
337 bool found = false;
253 bool found = FALSE;
338# if NETINET
339 unsigned long hid = INADDR_NONE;
340# endif /* NETINET */
341# if NETINET6
342 struct sockaddr_in6 hid6;
343# endif /* NETINET6 */
344
345 *end = '\0';
346# if NETINET
347 if (addr.sa.sa_family == AF_INET &&
254# if NETINET
255 unsigned long hid = INADDR_NONE;
256# endif /* NETINET */
257# if NETINET6
258 struct sockaddr_in6 hid6;
259# endif /* NETINET6 */
260
261 *end = '\0';
262# if NETINET
263 if (addr.sa.sa_family == AF_INET &&
348 (hid = inet_addr(&at[1])) != INADDR_NONE)
264 (hid = inet_addr(&at[1])) !=
265 INADDR_NONE)
349 {
350 addr.sin.sin_addr.s_addr = hid;
351 addr.sin.sin_port = port;
266 {
267 addr.sin.sin_addr.s_addr = hid;
268 addr.sin.sin_port = port;
352 found = true;
269 found = TRUE;
353 }
354# endif /* NETINET */
355# if NETINET6
356 (void) memset(&hid6, '\0', sizeof hid6);
357 if (addr.sa.sa_family == AF_INET6 &&
270 }
271# endif /* NETINET */
272# if NETINET6
273 (void) memset(&hid6, '\0', sizeof hid6);
274 if (addr.sa.sa_family == AF_INET6 &&
358 mi_inet_pton(AF_INET6, &at[1],
359 &hid6.sin6_addr) == 1)
275 inet_pton(AF_INET6, &at[1],
276 &hid6.sin6_addr) == 1)
360 {
361 addr.sin6.sin6_addr = hid6.sin6_addr;
362 addr.sin6.sin6_port = port;
277 {
278 addr.sin6.sin6_addr = hid6.sin6_addr;
279 addr.sin6.sin6_port = port;
363 found = true;
280 found = TRUE;
364 }
365# endif /* NETINET6 */
366 *end = ']';
367 if (!found)
368 {
369 smi_log(SMI_LOG_ERR,
370 "%s: Invalid numeric domain spec \"%s\"",
371 name, at);
281 }
282# endif /* NETINET6 */
283 *end = ']';
284 if (!found)
285 {
286 smi_log(SMI_LOG_ERR,
287 "%s: Invalid numeric domain spec \"%s\"",
288 name, at);
372 return INVALID_SOCKET;
289 return MI_INVALID_SOCKET;
373 }
374 }
375 else
376 {
377 smi_log(SMI_LOG_ERR,
378 "%s: Invalid numeric domain spec \"%s\"",
379 name, at);
290 }
291 }
292 else
293 {
294 smi_log(SMI_LOG_ERR,
295 "%s: Invalid numeric domain spec \"%s\"",
296 name, at);
380 return INVALID_SOCKET;
297 return MI_INVALID_SOCKET;
381 }
382 }
383 else
384 {
298 }
299 }
300 else
301 {
385 struct hostent *hp = NULL;
386
387 hp = mi_gethostbyname(at, addr.sa.sa_family);
388 if (hp == NULL)
389 {
390 smi_log(SMI_LOG_ERR,
391 "%s: Unknown host name %s",
392 name, at);
302 hp = mi_gethostbyname(at, addr.sa.sa_family);
303 if (hp == NULL)
304 {
305 smi_log(SMI_LOG_ERR,
306 "%s: Unknown host name %s",
307 name, at);
393 return INVALID_SOCKET;
308 return MI_INVALID_SOCKET;
394 }
395 addr.sa.sa_family = hp->h_addrtype;
396 switch (hp->h_addrtype)
397 {
398# if NETINET
399 case AF_INET:
309 }
310 addr.sa.sa_family = hp->h_addrtype;
311 switch (hp->h_addrtype)
312 {
313# if NETINET
314 case AF_INET:
400 (void) memmove(&addr.sin.sin_addr,
401 hp->h_addr,
402 INADDRSZ);
315 memmove(&addr.sin.sin_addr,
316 hp->h_addr,
317 INADDRSZ);
403 addr.sin.sin_port = port;
404 break;
405# endif /* NETINET */
406
407# if NETINET6
408 case AF_INET6:
318 addr.sin.sin_port = port;
319 break;
320# endif /* NETINET */
321
322# if NETINET6
323 case AF_INET6:
409 (void) memmove(&addr.sin6.sin6_addr,
410 hp->h_addr,
411 IN6ADDRSZ);
324 memmove(&addr.sin6.sin6_addr,
325 hp->h_addr,
326 IN6ADDRSZ);
412 addr.sin6.sin6_port = port;
413 break;
414# endif /* NETINET6 */
415
416 default:
417 smi_log(SMI_LOG_ERR,
418 "%s: Unknown protocol for %s (%d)",
419 name, at, hp->h_addrtype);
327 addr.sin6.sin6_port = port;
328 break;
329# endif /* NETINET6 */
330
331 default:
332 smi_log(SMI_LOG_ERR,
333 "%s: Unknown protocol for %s (%d)",
334 name, at, hp->h_addrtype);
420 return INVALID_SOCKET;
335 return MI_INVALID_SOCKET;
421 }
336 }
422# if NETINET6
423 freehostent(hp);
424# endif /* NETINET6 */
425 }
426 }
427 else
428 {
429 switch (addr.sa.sa_family)
430 {
431# if NETINET
432 case AF_INET:

--- 10 unchanged lines hidden (view full) ---

443 }
444#endif /* NETINET || NETINET6 */
445
446 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
447 if (!ValidSocket(sock))
448 {
449 smi_log(SMI_LOG_ERR,
450 "%s: Unable to create new socket: %s",
337 }
338 }
339 else
340 {
341 switch (addr.sa.sa_family)
342 {
343# if NETINET
344 case AF_INET:

--- 10 unchanged lines hidden (view full) ---

355 }
356#endif /* NETINET || NETINET6 */
357
358 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
359 if (!ValidSocket(sock))
360 {
361 smi_log(SMI_LOG_ERR,
362 "%s: Unable to create new socket: %s",
451 name, sm_errstring(errno));
452 return INVALID_SOCKET;
363 name, strerror(errno));
364 return MI_INVALID_SOCKET;
453 }
454
365 }
366
455 if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 ||
456 fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1)
457 {
458 smi_log(SMI_LOG_ERR,
459 "%s: Unable to set close-on-exec: %s", name,
460 sm_errstring(errno));
461 (void) closesocket(sock);
462 return INVALID_SOCKET;
463 }
464
465 if (
466#if NETUNIX
467 addr.sa.sa_family != AF_UNIX &&
468#endif /* NETUNIX */
469 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
367 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt,
470 sizeof(sockopt)) == -1)
471 {
472 smi_log(SMI_LOG_ERR,
368 sizeof(sockopt)) == -1)
369 {
370 smi_log(SMI_LOG_ERR,
473 "%s: set reuseaddr failed (%s)", name,
474 sm_errstring(errno));
475 (void) closesocket(sock);
476 return INVALID_SOCKET;
371 "%s: Unable to setsockopt: %s", name, strerror(errno));
372 (void) close(sock);
373 return MI_INVALID_SOCKET;
477 }
478
374 }
375
479#if NETUNIX
480 if (addr.sa.sa_family == AF_UNIX && rmsocket)
376 if (bind(sock, &addr.sa, *socksize) < 0)
481 {
377 {
482 struct stat s;
483
484 if (stat(colon, &s) != 0)
485 {
486 if (errno != ENOENT)
487 {
488 smi_log(SMI_LOG_ERR,
489 "%s: Unable to stat() %s: %s",
490 name, colon, sm_errstring(errno));
491 (void) closesocket(sock);
492 return INVALID_SOCKET;
493 }
494 }
495 else if (!S_ISSOCK(s.st_mode))
496 {
497 smi_log(SMI_LOG_ERR,
498 "%s: %s is not a UNIX domain socket",
499 name, colon);
500 (void) closesocket(sock);
501 return INVALID_SOCKET;
502 }
503 else if (unlink(colon) != 0)
504 {
505 smi_log(SMI_LOG_ERR,
506 "%s: Unable to remove %s: %s",
507 name, colon, sm_errstring(errno));
508 (void) closesocket(sock);
509 return INVALID_SOCKET;
510 }
511 }
512#endif /* NETUNIX */
513
514 if (bind(sock, &addr.sa, L_socksize) < 0)
515 {
516 smi_log(SMI_LOG_ERR,
517 "%s: Unable to bind to port %s: %s",
378 smi_log(SMI_LOG_ERR,
379 "%s: Unable to bind to port %s: %s",
518 name, conn, sm_errstring(errno));
519 (void) closesocket(sock);
520 return INVALID_SOCKET;
380 name, conn, strerror(errno));
381 (void) close(sock);
382 return MI_INVALID_SOCKET;
521 }
522
523 if (listen(sock, backlog) < 0)
524 {
525 smi_log(SMI_LOG_ERR,
383 }
384
385 if (listen(sock, backlog) < 0)
386 {
387 smi_log(SMI_LOG_ERR,
526 "%s: listen call failed: %s", name,
527 sm_errstring(errno));
528 (void) closesocket(sock);
529 return INVALID_SOCKET;
388 "%s: listen call failed: %s", name, strerror(errno));
389 (void) close(sock);
390 return MI_INVALID_SOCKET;
530 }
531
391 }
392
532#if NETUNIX
533 if (addr.sa.sa_family == AF_UNIX && len > 0)
534 {
535 /*
536 ** Set global variable sockpath so the UNIX socket can be
537 ** unlink()ed at exit.
538 */
539
540 sockpath = (char *) malloc(len);
541 if (sockpath != NULL)
542 (void) sm_strlcpy(sockpath, colon, len);
543 else
544 {
545 smi_log(SMI_LOG_ERR,
546 "%s: can't malloc(%d) for sockpath: %s",
547 name, (int) len, sm_errstring(errno));
548 (void) closesocket(sock);
549 return INVALID_SOCKET;
550 }
551 }
552#endif /* NETUNIX */
553 L_family = addr.sa.sa_family;
554 return sock;
555}
393 return sock;
394}
556
557#if !_FFR_WORKERS_POOL
558/*
395 /*
559** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
560**
561** Parameters:
562** arg -- argument to pass to mi_handle_session()
563**
564** Returns:
565** results from mi_handle_session()
566*/
567
396** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session
397**
398** Parameters:
399** arg -- argument to pass to mi_handle_session()
400**
401** Returns:
402** results from mi_handle_session()
403*/
404
568static void *
405void *
569mi_thread_handle_wrapper(arg)
570 void *arg;
571{
406mi_thread_handle_wrapper(arg)
407 void *arg;
408{
572 /*
573 ** Note: on some systems this generates a compiler warning:
574 ** cast to pointer from integer of different size
575 ** You can safely ignore this warning as the result of this function
576 ** is not used anywhere.
577 */
578
579 return (void *) mi_handle_session(arg);
580}
409 return (void *) mi_handle_session(arg);
410}
581#endif /* _FFR_WORKERS_POOL */
582
411
583/*
584** MI_CLOSENER -- close listen socket
412 /*
413** MI_MILTER_LISTENER -- Generic listener harness
585**
414**
586** Parameters:
587** none.
588**
589** Returns:
590** none.
591*/
592
593void
594mi_closener()
595{
596 (void) smutex_lock(&L_Mutex);
597 if (ValidSocket(listenfd))
598 {
599#if NETUNIX
600 bool removable;
601 struct stat sockinfo;
602 struct stat fileinfo;
603
604 removable = sockpath != NULL &&
605 geteuid() != 0 &&
606 fstat(listenfd, &sockinfo) == 0 &&
607 (S_ISFIFO(sockinfo.st_mode)
608# ifdef S_ISSOCK
609 || S_ISSOCK(sockinfo.st_mode)
610# endif /* S_ISSOCK */
611 );
612#endif /* NETUNIX */
613
614 (void) closesocket(listenfd);
615 listenfd = INVALID_SOCKET;
616
617#if NETUNIX
618 /* XXX sleep() some time before doing this? */
619 if (sockpath != NULL)
620 {
621 if (removable &&
622 stat(sockpath, &fileinfo) == 0 &&
623 ((fileinfo.st_dev == sockinfo.st_dev &&
624 fileinfo.st_ino == sockinfo.st_ino)
625# ifdef S_ISSOCK
626 || S_ISSOCK(fileinfo.st_mode)
627# endif /* S_ISSOCK */
628 )
629 &&
630 (S_ISFIFO(fileinfo.st_mode)
631# ifdef S_ISSOCK
632 || S_ISSOCK(fileinfo.st_mode)
633# endif /* S_ISSOCK */
634 ))
635 (void) unlink(sockpath);
636 free(sockpath);
637 sockpath = NULL;
638 }
639#endif /* NETUNIX */
640 }
641 (void) smutex_unlock(&L_Mutex);
642}
643
644/*
645** MI_LISTENER -- Generic listener harness
646**
647** Open up listen port
648** Wait for connections
649**
650** Parameters:
651** conn -- connection description
652** dbg -- debug level
653** smfi -- filter structure to use
654** timeout -- timeout for reads/writes
415** Open up listen port
416** Wait for connections
417**
418** Parameters:
419** conn -- connection description
420** dbg -- debug level
421** smfi -- filter structure to use
422** timeout -- timeout for reads/writes
655** backlog -- listen queue backlog size
656**
657** Returns:
658** MI_SUCCESS -- Exited normally
659** (session finished or we were told to exit)
660** MI_FAILURE -- Network initialization failed.
661*/
662
423**
424** Returns:
425** MI_SUCCESS -- Exited normally
426** (session finished or we were told to exit)
427** MI_FAILURE -- Network initialization failed.
428*/
429
663#if BROKEN_PTHREAD_SLEEP
664
665/*
666** Solaris 2.6, perhaps others, gets an internal threads library panic
667** when sleep() is used:
668**
669** thread_create() failed, returned 11 (EINVAL)
670** co_enable, thr_create() returned error = 24
671** libthread panic: co_enable failed (PID: 17793 LWP 1)
672** stacktrace:
673** ef526b10
674** ef52646c
675** ef534cbc
676** 156a4
677** 14644
678** 1413c
679** 135e0
680** 0
681*/
682
683# define MI_SLEEP(s) \
684{ \
685 int rs = 0; \
686 struct timeval st; \
687 \
688 st.tv_sec = (s); \
689 st.tv_usec = 0; \
690 if (st.tv_sec > 0) \
691 { \
692 for (;;) \
693 { \
694 rs = select(0, NULL, NULL, NULL, &st); \
695 if (rs < 0 && errno == EINTR) \
696 continue; \
697 if (rs != 0) \
698 { \
699 smi_log(SMI_LOG_ERR, \
700 "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \
701 rs, errno); \
702 } \
703 break; \
704 } \
705 } \
706}
707#else /* BROKEN_PTHREAD_SLEEP */
708# define MI_SLEEP(s) sleep((s))
709#endif /* BROKEN_PTHREAD_SLEEP */
710
711int
430int
712mi_listener(conn, dbg, smfi, timeout, backlog)
431mi_listener(conn, dbg, smfi, timeout)
713 char *conn;
714 int dbg;
715 smfiDesc_ptr smfi;
716 time_t timeout;
432 char *conn;
433 int dbg;
434 smfiDesc_ptr smfi;
435 time_t timeout;
717 int backlog;
718{
436{
719 socket_t connfd = INVALID_SOCKET;
720#if _FFR_DUP_FD
721 socket_t dupfd = INVALID_SOCKET;
722#endif /* _FFR_DUP_FD */
437 int connfd = -1;
438 int listenfd = -1;
723 int sockopt = 1;
439 int sockopt = 1;
724 int r, mistop;
440 int r;
725 int ret = MI_SUCCESS;
441 int ret = MI_SUCCESS;
726 int mcnt = 0; /* error count for malloc() failures */
727 int tcnt = 0; /* error count for thread_create() failures */
728 int acnt = 0; /* error count for accept() failures */
729 int scnt = 0; /* error count for select() failures */
730 int save_errno = 0;
731 int fdflags;
732#if !_FFR_WORKERS_POOL
442 int cnt_m = 0;
443 int cnt_t = 0;
733 sthread_t thread_id;
444 sthread_t thread_id;
734#endif /* !_FFR_WORKERS_POOL */
735 _SOCK_ADDR cliaddr;
445 _SOCK_ADDR cliaddr;
446 SOCKADDR_LEN_T socksize;
736 SOCKADDR_LEN_T clilen;
737 SMFICTX_PTR ctx;
447 SOCKADDR_LEN_T clilen;
448 SMFICTX_PTR ctx;
738 FD_RD_VAR(rds, excs);
449 fd_set readset, excset;
739 struct timeval chktime;
740
450 struct timeval chktime;
451
741 if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE)
452 if (dbg > 0)
453 smi_log(SMI_LOG_DEBUG,
454 "%s: Opening listen socket on conn %s",
455 smfi->xxfi_name, conn);
456 if ((listenfd = mi_milteropen(conn, SOMAXCONN, &socksize,
457 smfi->xxfi_name)) < 0)
458 {
459 smi_log(SMI_LOG_FATAL,
460 "%s: Unable to create listening socket on conn %s",
461 smfi->xxfi_name, conn);
742 return MI_FAILURE;
462 return MI_FAILURE;
743
744#if _FFR_WORKERS_POOL
745 if (mi_pool_controller_init() == MI_FAILURE)
463 }
464 clilen = socksize;
465 if (listenfd >= FD_SETSIZE)
466 {
467 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
468 smfi->xxfi_name, listenfd, FD_SETSIZE);
746 return MI_FAILURE;
469 return MI_FAILURE;
747#endif /* _FFR_WORKERS_POOL */
470 }
748
471
749 clilen = L_socksize;
750 while ((mistop = mi_stop()) == MILTER_CONT)
472 while (mi_stop() == MILTER_CONT)
751 {
473 {
752 (void) smutex_lock(&L_Mutex);
753 if (!ValidSocket(listenfd))
754 {
755 ret = MI_FAILURE;
756 smi_log(SMI_LOG_ERR,
757 "%s: listenfd=%d corrupted, terminating, errno=%d",
758 smfi->xxfi_name, listenfd, errno);
759 (void) smutex_unlock(&L_Mutex);
760 break;
761 }
762
763 /* select on interface ports */
474 /* select on interface ports */
764 FD_RD_INIT(listenfd, rds, excs);
475 FD_ZERO(&readset);
476 FD_SET((u_int) listenfd, &readset);
477 FD_ZERO(&excset);
478 FD_SET((u_int) listenfd, &excset);
765 chktime.tv_sec = MI_CHK_TIME;
766 chktime.tv_usec = 0;
479 chktime.tv_sec = MI_CHK_TIME;
480 chktime.tv_usec = 0;
767 r = FD_RD_READY(listenfd, rds, excs, &chktime);
481 r = select(listenfd + 1, &readset, NULL, &excset, &chktime);
768 if (r == 0) /* timeout */
482 if (r == 0) /* timeout */
769 {
770 (void) smutex_unlock(&L_Mutex);
771 continue; /* just check mi_stop() */
483 continue; /* just check mi_stop() */
772 }
773 if (r < 0)
774 {
484 if (r < 0)
485 {
775 save_errno = errno;
776 (void) smutex_unlock(&L_Mutex);
777 if (save_errno == EINTR)
486 if (errno == EINTR)
778 continue;
487 continue;
779 scnt++;
780 smi_log(SMI_LOG_ERR,
781 "%s: %s() failed (%s), %s",
782 smfi->xxfi_name, MI_POLLSELECT,
783 sm_errstring(save_errno),
784 scnt >= MAX_FAILS_S ? "abort" : "try again");
785 MI_SLEEP(scnt);
786 if (scnt >= MAX_FAILS_S)
787 {
788 ret = MI_FAILURE;
789 break;
790 }
791 continue;
488 ret = MI_FAILURE;
489 break;
792 }
490 }
793 if (!FD_IS_RD_RDY(listenfd, rds, excs))
491 if (!FD_ISSET(listenfd, &readset))
794 {
795 /* some error: just stop for now... */
796 ret = MI_FAILURE;
492 {
493 /* some error: just stop for now... */
494 ret = MI_FAILURE;
797 (void) smutex_unlock(&L_Mutex);
798 smi_log(SMI_LOG_ERR,
799 "%s: %s() returned exception for socket, abort",
800 smfi->xxfi_name, MI_POLLSELECT);
801 break;
802 }
495 break;
496 }
803 scnt = 0; /* reset error counter for select() */
804
497
805 (void) memset(&cliaddr, '\0', sizeof cliaddr);
806 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
807 &clilen);
498 connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
499 &clilen);
808 save_errno = errno;
809 (void) smutex_unlock(&L_Mutex);
810
500
811 /*
812 ** If remote side closes before accept() finishes,
813 ** sockaddr might not be fully filled in.
814 */
815
816 if (ValidSocket(connfd) &&
817 (clilen == 0 ||
818# ifdef BSD4_4_SOCKADDR
819 cliaddr.sa.sa_len == 0 ||
820# endif /* BSD4_4_SOCKADDR */
821 cliaddr.sa.sa_family != L_family))
501 if (connfd < 0)
822 {
502 {
823 (void) closesocket(connfd);
824 connfd = INVALID_SOCKET;
825 save_errno = EINVAL;
826 }
827
828 /* check if acceptable for select() */
829 if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd))
830 {
831 (void) closesocket(connfd);
832 connfd = INVALID_SOCKET;
833 save_errno = ERANGE;
834 }
835
836 if (!ValidSocket(connfd))
837 {
838 if (save_errno == EINTR
839#ifdef EAGAIN
840 || save_errno == EAGAIN
841#endif /* EAGAIN */
842#ifdef ECONNABORTED
843 || save_errno == ECONNABORTED
844#endif /* ECONNABORTED */
845#ifdef EMFILE
846 || save_errno == EMFILE
847#endif /* EMFILE */
848#ifdef ENFILE
849 || save_errno == ENFILE
850#endif /* ENFILE */
851#ifdef ENOBUFS
852 || save_errno == ENOBUFS
853#endif /* ENOBUFS */
854#ifdef ENOMEM
855 || save_errno == ENOMEM
856#endif /* ENOMEM */
857#ifdef ENOSR
858 || save_errno == ENOSR
859#endif /* ENOSR */
860#ifdef EWOULDBLOCK
861 || save_errno == EWOULDBLOCK
862#endif /* EWOULDBLOCK */
863 )
864 continue;
865 acnt++;
866 smi_log(SMI_LOG_ERR,
503 smi_log(SMI_LOG_ERR,
867 "%s: accept() returned invalid socket (%s), %s",
868 smfi->xxfi_name, sm_errstring(save_errno),
869 acnt >= MAX_FAILS_A ? "abort" : "try again");
870 MI_SLEEP(acnt);
871 if (acnt >= MAX_FAILS_A)
872 {
873 ret = MI_FAILURE;
874 break;
875 }
504 "%s: accept() returned invalid socket",
505 smfi->xxfi_name);
876 continue;
877 }
506 continue;
507 }
878 acnt = 0; /* reset error counter for accept() */
879#if _FFR_DUP_FD
880 dupfd = fcntl(connfd, F_DUPFD, 256);
881 if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd))
882 {
883 close(connfd);
884 connfd = dupfd;
885 dupfd = INVALID_SOCKET;
886 }
887#endif /* _FFR_DUP_FD */
888
508
889 /*
890 ** Need to set close-on-exec for connfd in case a user's
891 ** filter starts other applications.
892 ** Note: errors will not stop processing (for now).
893 */
894
895 if ((fdflags = fcntl(connfd, F_GETFD, 0)) == -1 ||
896 fcntl(connfd, F_SETFD, fdflags | FD_CLOEXEC) == -1)
897 {
898 smi_log(SMI_LOG_ERR,
899 "%s: Unable to set close-on-exec: %s",
900 smfi->xxfi_name, sm_errstring(errno));
901 }
902
903 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
904 (void *) &sockopt, sizeof sockopt) < 0)
905 {
509 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE,
510 (void *) &sockopt, sizeof sockopt) < 0)
511 {
906 smi_log(SMI_LOG_WARN,
907 "%s: set keepalive failed (%s)",
908 smfi->xxfi_name, sm_errstring(errno));
512 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed",
513 smfi->xxfi_name);
909 /* XXX: continue? */
910 }
911 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
912 {
514 /* XXX: continue? */
515 }
516 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL)
517 {
913 (void) closesocket(connfd);
914 mcnt++;
915 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s",
916 smfi->xxfi_name, sm_errstring(save_errno),
917 mcnt >= MAX_FAILS_M ? "abort" : "try again");
918 MI_SLEEP(mcnt);
919 if (mcnt >= MAX_FAILS_M)
518 (void) close(connfd);
519 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed",
520 smfi->xxfi_name);
521 sleep(++cnt_m);
522 if (cnt_m >= MAX_FAILS_M)
920 {
921 ret = MI_FAILURE;
922 break;
923 }
924 continue;
925 }
523 {
524 ret = MI_FAILURE;
525 break;
526 }
527 continue;
528 }
926 mcnt = 0; /* reset error counter for malloc() */
927 (void) memset(ctx, '\0', sizeof *ctx);
529 cnt_m = 0;
530 memset(ctx, '\0', sizeof *ctx);
928 ctx->ctx_sd = connfd;
929 ctx->ctx_dbg = dbg;
930 ctx->ctx_timeout = timeout;
931 ctx->ctx_smfi = smfi;
531 ctx->ctx_sd = connfd;
532 ctx->ctx_dbg = dbg;
533 ctx->ctx_timeout = timeout;
534 ctx->ctx_smfi = smfi;
535#if 0
536 if (smfi->xxfi_eoh == NULL)
537 if (smfi->xxfi_eom == NULL)
538 if (smfi->xxfi_abort == NULL)
539 if (smfi->xxfi_close == NULL)
540#endif /* 0 */
932 if (smfi->xxfi_connect == NULL)
933 ctx->ctx_pflags |= SMFIP_NOCONNECT;
934 if (smfi->xxfi_helo == NULL)
935 ctx->ctx_pflags |= SMFIP_NOHELO;
936 if (smfi->xxfi_envfrom == NULL)
937 ctx->ctx_pflags |= SMFIP_NOMAIL;
938 if (smfi->xxfi_envrcpt == NULL)
939 ctx->ctx_pflags |= SMFIP_NORCPT;
940 if (smfi->xxfi_header == NULL)
941 ctx->ctx_pflags |= SMFIP_NOHDRS;
942 if (smfi->xxfi_eoh == NULL)
943 ctx->ctx_pflags |= SMFIP_NOEOH;
944 if (smfi->xxfi_body == NULL)
945 ctx->ctx_pflags |= SMFIP_NOBODY;
541 if (smfi->xxfi_connect == NULL)
542 ctx->ctx_pflags |= SMFIP_NOCONNECT;
543 if (smfi->xxfi_helo == NULL)
544 ctx->ctx_pflags |= SMFIP_NOHELO;
545 if (smfi->xxfi_envfrom == NULL)
546 ctx->ctx_pflags |= SMFIP_NOMAIL;
547 if (smfi->xxfi_envrcpt == NULL)
548 ctx->ctx_pflags |= SMFIP_NORCPT;
549 if (smfi->xxfi_header == NULL)
550 ctx->ctx_pflags |= SMFIP_NOHDRS;
551 if (smfi->xxfi_eoh == NULL)
552 ctx->ctx_pflags |= SMFIP_NOEOH;
553 if (smfi->xxfi_body == NULL)
554 ctx->ctx_pflags |= SMFIP_NOBODY;
946 if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL)
947 ctx->ctx_pflags |= SMFIP_NODATA;
948 if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL)
949 ctx->ctx_pflags |= SMFIP_NOUNKNOWN;
950
555
951#if _FFR_WORKERS_POOL
952# define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s"
953 if ((r = mi_start_session(ctx)) != MI_SUCCESS)
954#else /* _FFR_WORKERS_POOL */
955# define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s"
956 if ((r = thread_create(&thread_id,
957 mi_thread_handle_wrapper,
556 if ((r = thread_create(&thread_id,
557 mi_thread_handle_wrapper,
958 (void *) ctx)) != 0)
959#endif /* _FFR_WORKERS_POOL */
558 (void *) ctx)) != MI_SUCCESS)
960 {
559 {
961 tcnt++;
962 smi_log(SMI_LOG_ERR,
560 smi_log(SMI_LOG_ERR,
963 LOG_CRT_FAIL,
964 smfi->xxfi_name, r,
965 tcnt >= MAX_FAILS_T ? "abort" : "try again");
966 MI_SLEEP(tcnt);
967 (void) closesocket(connfd);
561 "%s: thread_create() failed: %d",
562 smfi->xxfi_name, r);
563 sleep(++cnt_t);
564 (void) close(connfd);
968 free(ctx);
565 free(ctx);
969 if (tcnt >= MAX_FAILS_T)
566 if (cnt_t >= MAX_FAILS_T)
970 {
971 ret = MI_FAILURE;
972 break;
973 }
974 continue;
975 }
567 {
568 ret = MI_FAILURE;
569 break;
570 }
571 continue;
572 }
976 tcnt = 0;
573 cnt_t = 0;
977 }
978 if (ret != MI_SUCCESS)
979 mi_stop_milters(MILTER_ABRT);
574 }
575 if (ret != MI_SUCCESS)
576 mi_stop_milters(MILTER_ABRT);
980 else
981 {
982 if (mistop != MILTER_CONT)
983 smi_log(SMI_LOG_INFO, "%s: mi_stop=%d",
984 smfi->xxfi_name, mistop);
985 mi_closener();
986 }
987 (void) smutex_destroy(&L_Mutex);
577 if (listenfd >= 0)
578 (void) close(listenfd);
988 return ret;
989}
579 return ret;
580}
581#endif /* _FFR_MILTER */