1 /*
2 * Copyright (c) 2002 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #include <config.h>
34
35 #include "ftmacros.h"
36 #include "diag-control.h"
37
38 #include <errno.h> // for the errno variable
39 #include <string.h> // for strtok, etc
40 #include <stdlib.h> // for malloc(), free(), ...
41 #include <stdio.h> // for fprintf(), stderr, FILE etc
42 #include <pcap.h> // for PCAP_ERRBUF_SIZE
43 #include <signal.h> // for signal()
44
45 #include "fmtutils.h"
46 #include "sockutils.h" // for socket calls
47 #include "varattrs.h" // for _U_
48 #include "portability.h"
49 #include "rpcapd.h"
50 #include "config_params.h" // configuration file parameters
51 #include "fileconf.h" // for the configuration file management
52 #include "rpcap-protocol.h"
53 #include "daemon.h" // the true main() method of this daemon
54 #include "log.h"
55
56 #ifdef HAVE_OPENSSL
57 #include "sslutils.h"
58 #endif
59
60 #ifdef _WIN32
61 #include <process.h> // for thread stuff
62 #include "win32-svc.h" // for Win32 service stuff
63 #include "getopt.h" // for getopt()-for-Windows
64 #else
65 #include <fcntl.h> // for open()
66 #include <unistd.h> // for exit()
67 #include <sys/wait.h> // waitpid()
68 #endif
69
70 //
71 // Element in list of sockets on which we're listening for connections.
72 //
73 struct listen_sock {
74 struct listen_sock *next;
75 PCAP_SOCKET sock;
76 };
77
78 // Global variables
79 char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
80 struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
81 int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
82 static struct listen_sock *listen_socks; //!< sockets on which we listen
83 char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration
84 static int passivemode = 1; //!< '1' if we want to run in passive mode as well
85 static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket
86 static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to
87 static char port[MAX_LINE + 1]; //!< keeps the network port to bind to
88 #ifdef _WIN32
89 static HANDLE state_change_event; //!< event to signal that a state change should take place
90 #endif
91 static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
92 static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
93 static int uses_ssl; //!< '1' to use TLS over TCP
94
95 extern char *optarg; // for getopt()
96
97 // Function definition
98 #ifdef _WIN32
99 static unsigned __stdcall main_active(void *ptr);
100 static BOOL WINAPI main_ctrl_event(DWORD);
101 #else
102 static void *main_active(void *ptr);
103 static void main_terminate(int sign);
104 static void main_reread_config(int sign);
105 #endif
106 static void accept_connections(void);
107 static void accept_connection(PCAP_SOCKET listen_sock);
108 #ifndef _WIN32
109 static void main_reap_children(int sign);
110 #endif
111 #ifdef _WIN32
112 static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
113 #endif
114
115 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
116
117 /*!
118 \brief Prints the usage screen if it is launched in console mode.
119 */
printusage(FILE * f)120 static void printusage(FILE * f)
121 {
122 const char *usagetext =
123 "USAGE:"
124 " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
125 " [-n] [-v] [-d] "
126 #ifndef _WIN32
127 "[-i] "
128 #endif
129 "[-D] [-s <config_file>] [-f <config_file>]\n\n"
130 " -b <address> the address to bind to (either numeric or literal).\n"
131 " Default: binds to all local IPv4 and IPv6 addresses\n\n"
132 " -p <port> the port to bind to.\n"
133 " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
134 " -4 use only IPv4.\n"
135 " Default: use both IPv4 and IPv6 waiting sockets\n\n"
136 " -l <host_list> a file that contains a list of hosts that are allowed\n"
137 " to connect to this server (if more than one, list them one\n"
138 " per line).\n"
139 " We suggest to use literal names (instead of numeric ones)\n"
140 " in order to avoid problems with different address families.\n\n"
141 " -n permit NULL authentication (usually used with '-l')\n\n"
142 " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
143 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
144 " -v run in active mode only (default: if '-a' is specified, it\n"
145 " accepts passive connections as well)\n\n"
146 " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
147 " Warning (Win32): this switch is provided automatically when\n"
148 " the service is started from the control panel\n\n"
149 #ifndef _WIN32
150 " -i run in inetd mode (UNIX only)\n\n"
151 #endif
152 " -D log debugging messages\n\n"
153 #ifdef HAVE_OPENSSL
154 " -S encrypt all communication with SSL (implements rpcaps://)\n"
155 " -C enable compression\n"
156 " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n"
157 " -X <pem_file> uses the certificate from this file (default: cert.pem)\n"
158 #endif
159 " -s <config_file> save the current configuration to file\n\n"
160 " -f <config_file> load the current configuration from file; all switches\n"
161 " specified from the command line are ignored\n\n"
162 " -h print this help screen\n\n";
163
164 (void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
165 "Compiled with %s\n", pcap_lib_version());
166 #if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
167 (void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
168 #endif
169 (void)fprintf(f, "\n%s", usagetext);
170 }
171
172
173
174 //! Program main
main(int argc,char * argv[])175 int main(int argc, char *argv[])
176 {
177 char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration
178 int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error
179 int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon
180 #ifndef _WIN32
181 int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like
182 #endif
183 int log_debug_messages = 0; // Non-zero if the user wants debug messages logged
184 int retval; // keeps the returning value from several functions
185 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
186 #ifndef _WIN32
187 struct sigaction action;
188 #endif
189 #ifdef HAVE_OPENSSL
190 int enable_compression = 0;
191 #endif
192
193 savefile[0] = 0;
194 loadfile[0] = 0;
195 hostlist[0] = 0;
196
197 // Initialize errbuf
198 memset(errbuf, 0, sizeof(errbuf));
199
200 pcapint_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
201 pcapint_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
202
203 // Prepare to open a new server socket
204 memset(&mainhints, 0, sizeof(struct addrinfo));
205
206 mainhints.ai_family = PF_UNSPEC;
207 mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
208 mainhints.ai_socktype = SOCK_STREAM;
209
210 // Getting the proper command line options
211 # ifdef HAVE_OPENSSL
212 # define SSL_CLOPTS "SK:X:C"
213 # else
214 # define SSL_CLOPTS ""
215 # endif
216
217 # define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
218
219 while ((retval = getopt(argc, argv, CLOPTS)) != -1)
220 {
221 switch (retval)
222 {
223 case 'D':
224 log_debug_messages = 1;
225 rpcapd_log_set(log_to_systemlog, log_debug_messages);
226 break;
227 case 'b':
228 pcapint_strlcpy(address, optarg, sizeof (address));
229 break;
230 case 'p':
231 pcapint_strlcpy(port, optarg, sizeof (port));
232 break;
233 case '4':
234 mainhints.ai_family = PF_INET; // IPv4 server only
235 break;
236 case 'd':
237 isdaemon = 1;
238 log_to_systemlog = 1;
239 rpcapd_log_set(log_to_systemlog, log_debug_messages);
240 break;
241 case 'i':
242 #ifdef _WIN32
243 printusage(stderr);
244 exit(1);
245 #else
246 isrunbyinetd = 1;
247 log_to_systemlog = 1;
248 rpcapd_log_set(log_to_systemlog, log_debug_messages);
249 #endif
250 break;
251 case 'n':
252 nullAuthAllowed = 1;
253 break;
254 case 'v':
255 passivemode = 0;
256 break;
257 case 'l':
258 {
259 pcapint_strlcpy(hostlist, optarg, sizeof(hostlist));
260 break;
261 }
262 case 'a':
263 {
264 char *tmpaddress, *tmpport;
265 char *lasts;
266 int i = 0;
267
268 tmpaddress = pcapint_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
269
270 while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
271 {
272 tmpport = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
273
274 pcapint_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
275
276 if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
277 pcapint_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
278 else
279 pcapint_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
280
281 tmpaddress = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
282
283 i++;
284 }
285
286 if (i > MAX_ACTIVE_LIST)
287 rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
288
289 // I don't initialize the remaining part of the structure, since
290 // it is already zeroed (it is a global var)
291 break;
292 }
293 case 'f':
294 pcapint_strlcpy(loadfile, optarg, sizeof (loadfile));
295 break;
296 case 's':
297 pcapint_strlcpy(savefile, optarg, sizeof (savefile));
298 break;
299 #ifdef HAVE_OPENSSL
300 case 'S':
301 uses_ssl = 1;
302 break;
303 case 'C':
304 enable_compression = 1;
305 break;
306 case 'K':
307 ssl_set_keyfile(optarg);
308 break;
309 case 'X':
310 ssl_set_certfile(optarg);
311 break;
312 #endif
313 case 'h':
314 printusage(stdout);
315 exit(0);
316 /*NOTREACHED*/
317 default:
318 exit(1);
319 /*NOTREACHED*/
320 }
321 }
322
323 #ifndef _WIN32
324 if (isdaemon && isrunbyinetd)
325 {
326 rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
327 exit(1);
328 }
329 #endif
330
331 //
332 // We want UTF-8 error messages.
333 //
334 if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
335 {
336 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
337 exit(-1);
338 }
339 pcapint_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
340
341 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
342 {
343 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
344 exit(-1);
345 }
346
347 if (savefile[0] && fileconf_save(savefile))
348 rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
349
350 // If the file does not exist, it keeps the settings provided by the command line
351 if (loadfile[0])
352 fileconf_read();
353
354 #ifdef _WIN32
355 //
356 // Create a handle to signal the main loop to tell it to do
357 // something.
358 //
359 state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
360 if (state_change_event == NULL)
361 {
362 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
363 "Can't create state change event");
364 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
365 exit(2);
366 }
367
368 //
369 // Catch control signals.
370 //
371 if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
372 {
373 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
374 "Can't set control handler");
375 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
376 exit(2);
377 }
378 #else
379 memset(&action, 0, sizeof (action));
380 action.sa_handler = main_terminate;
381 action.sa_flags = 0;
382 sigemptyset(&action.sa_mask);
383 sigaction(SIGTERM, &action, NULL);
384 memset(&action, 0, sizeof (action));
385 action.sa_handler = main_reap_children;
386 action.sa_flags = 0;
387 sigemptyset(&action.sa_mask);
388 sigaction(SIGCHLD, &action, NULL);
389 // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
390 // connection, we don't want to get killed by a signal in that case
391 #ifdef __illumos__
392 DIAG_OFF_STRICT_PROTOTYPES
393 #endif /* __illumos__ */
394 signal(SIGPIPE, SIG_IGN);
395 #ifdef __illumos__
396 DIAG_ON_STRICT_PROTOTYPES
397 #endif /* __illumos__ */
398 #endif
399
400 # ifdef HAVE_OPENSSL
401 if (uses_ssl) {
402 if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
403 {
404 rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
405 errbuf);
406 exit(2);
407 }
408 }
409 # endif
410
411 #ifndef _WIN32
412 if (isrunbyinetd)
413 {
414 //
415 // -i was specified, indicating that this is being run
416 // by inetd or something that can run network daemons
417 // as if it were inetd (xinetd, launchd, systemd, etc.).
418 //
419 // We assume that the program that launched us just
420 // duplicated a single socket for the connection
421 // to our standard input, output, and error, so we
422 // can just use the standard input as our control
423 // socket.
424 //
425 int sockctrl;
426 int devnull_fd;
427
428 //
429 // Duplicate the standard input as the control socket.
430 //
431 sockctrl = dup(0);
432 if (sockctrl == -1)
433 {
434 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
435 "Can't dup standard input");
436 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
437 exit(2);
438 }
439
440 //
441 // Try to set the standard input, output, and error
442 // to /dev/null.
443 //
444 devnull_fd = open("/dev/null", O_RDWR);
445 if (devnull_fd != -1)
446 {
447 //
448 // If this fails, just drive on.
449 //
450 (void)dup2(devnull_fd, 0);
451 (void)dup2(devnull_fd, 1);
452 (void)dup2(devnull_fd, 2);
453 close(devnull_fd);
454 }
455
456 //
457 // Handle this client.
458 // This is passive mode, so we don't care whether we were
459 // told by the client to close.
460 //
461 char *hostlist_copy = strdup(hostlist);
462 if (hostlist_copy == NULL)
463 {
464 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
465 exit(0);
466 }
467 (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
468 nullAuthAllowed, uses_ssl);
469
470 //
471 // Nothing more to do.
472 //
473 exit(0);
474 }
475 #endif
476
477 if (isdaemon)
478 {
479 //
480 // This is being run as a daemon.
481 // On UN*X, it might be manually run, or run from an
482 // rc file.
483 //
484 #ifndef _WIN32
485 int pid;
486
487 //
488 // Daemonize ourselves.
489 //
490 // Unix Network Programming, pg 336
491 //
492 if ((pid = fork()) != 0)
493 exit(0); // Parent terminates
494
495 // First child continues
496 // Set daemon mode
497 setsid();
498
499 // generated under unix with 'kill -HUP', needed to reload the configuration
500 memset(&action, 0, sizeof (action));
501 action.sa_handler = main_reread_config;
502 action.sa_flags = 0;
503 sigemptyset(&action.sa_mask);
504 sigaction(SIGHUP, &action, NULL);
505
506 if ((pid = fork()) != 0)
507 exit(0); // First child terminates
508
509 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
510 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
511 // created. From this point on, the number of threads active are always one more compared
512 // to the number you're expecting
513
514 // Second child continues
515 // umask(0);
516 // chdir("/");
517 #else
518 //
519 // This is being run as a service on Windows.
520 //
521 // If this call succeeds, it is blocking on Win32
522 //
523 if (!svc_start())
524 rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
525
526 // When the previous call returns, the entire application has to be stopped.
527 exit(0);
528 #endif
529 }
530 else // Console mode
531 {
532 #ifndef _WIN32
533 // Enable the catching of Ctrl+C
534 memset(&action, 0, sizeof (action));
535 action.sa_handler = main_terminate;
536 action.sa_flags = 0;
537 sigemptyset(&action.sa_mask);
538 sigaction(SIGINT, &action, NULL);
539
540 // generated under unix with 'kill -HUP', needed to reload the configuration
541 // We do not have this kind of signal in Win32
542 memset(&action, 0, sizeof (action));
543 action.sa_handler = main_reread_config;
544 action.sa_flags = 0;
545 sigemptyset(&action.sa_mask);
546 sigaction(SIGHUP, &action, NULL);
547 #endif
548
549 printf("Press CTRL + C to stop the server...\n");
550 }
551
552 // If we're a Win32 service, we have already called this function in the service_main
553 main_startup();
554
555 // The code should never arrive here (since the main_startup is blocking)
556 // however this avoids a compiler warning
557 exit(0);
558 }
559
main_startup(void)560 void main_startup(void)
561 {
562 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
563 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
564 int i;
565 #ifdef _WIN32
566 HANDLE threadId; // handle for the subthread
567 #else
568 pid_t pid;
569 #endif
570
571 i = 0;
572 addrinfo = NULL;
573 memset(errbuf, 0, sizeof(errbuf));
574
575 // Starts all the active threads
576 while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
577 {
578 activelist[i].ai_family = mainhints.ai_family;
579
580 #ifdef _WIN32
581 threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
582 (void *)&activelist[i], 0, NULL);
583 if (threadId == 0)
584 {
585 rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
586 continue;
587 }
588 CloseHandle(threadId);
589 #else
590 if ((pid = fork()) == 0) // I am the child
591 {
592 main_active((void *) &activelist[i]);
593 exit(0);
594 }
595 #endif
596 i++;
597 }
598
599 /*
600 * The code that manages the active connections is not blocking;
601 * the code that manages the passive connection is blocking.
602 * So, if the user does not want to run in passive mode, we have
603 * to block the main thread here, otherwise the program ends and
604 * all threads are stopped.
605 *
606 * WARNING: this means that in case we have only active mode,
607 * the program does not terminate even if all the child thread
608 * terminates. The user has always to press Ctrl+C (or send a
609 * SIGTERM) to terminate the program.
610 */
611 if (passivemode)
612 {
613 struct addrinfo *tempaddrinfo;
614
615 //
616 // Get a list of sockets on which to listen.
617 //
618 addrinfo = sock_initaddress((address[0]) ? address : NULL,
619 port, &mainhints, errbuf, PCAP_ERRBUF_SIZE);
620 if (addrinfo == NULL)
621 {
622 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
623 return;
624 }
625
626 for (tempaddrinfo = addrinfo; tempaddrinfo;
627 tempaddrinfo = tempaddrinfo->ai_next)
628 {
629 PCAP_SOCKET sock;
630 struct listen_sock *sock_info;
631
632 if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
633 {
634 switch (tempaddrinfo->ai_family)
635 {
636 case AF_INET:
637 {
638 struct sockaddr_in *in;
639 char addrbuf[INET_ADDRSTRLEN];
640
641 in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
642 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
643 inet_ntop(AF_INET, &in->sin_addr,
644 addrbuf, sizeof (addrbuf)),
645 ntohs(in->sin_port),
646 errbuf);
647 break;
648 }
649
650 case AF_INET6:
651 {
652 struct sockaddr_in6 *in6;
653 char addrbuf[INET6_ADDRSTRLEN];
654
655 in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
656 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
657 inet_ntop(AF_INET6, &in6->sin6_addr,
658 addrbuf, sizeof (addrbuf)),
659 ntohs(in6->sin6_port),
660 errbuf);
661 break;
662 }
663
664 default:
665 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
666 tempaddrinfo->ai_family,
667 errbuf);
668 break;
669 }
670 continue;
671 }
672
673 sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
674 if (sock_info == NULL)
675 {
676 rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
677 exit(2);
678 }
679 sock_info->sock = sock;
680 sock_info->next = listen_socks;
681 listen_socks = sock_info;
682 }
683
684 freeaddrinfo(addrinfo);
685
686 if (listen_socks == NULL)
687 {
688 rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
689 exit(2);
690 }
691
692 //
693 // Now listen on all of them, waiting for connections.
694 //
695 accept_connections();
696 }
697
698 //
699 // We're done; exit.
700 //
701 rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
702
703 #ifndef _WIN32
704 //
705 // Sends a KILL signal to all the processes in this process's
706 // process group; i.e., it kills all the child processes
707 // we've created.
708 //
709 // XXX - that also includes us, so we will be killed as well;
710 // that may cause a message to be printed or logged.
711 //
712 kill(0, SIGKILL);
713 #endif
714
715 //
716 // Just leave. We shouldn't need to clean up sockets or
717 // anything else, and if we try to do so, we'll could end
718 // up closing sockets, or shutting Winsock down, out from
719 // under service loops, causing all sorts of noisy error
720 // messages.
721 //
722 // We shouldn't need to worry about cleaning up any resources
723 // such as handles, sockets, threads, etc. - exit() should
724 // terminate the process, causing all those resources to be
725 // cleaned up (including the threads; Microsoft claims in the
726 // ExitProcess() documentation that, if ExitProcess() is called,
727 // "If a thread is waiting on a kernel object, it will not be
728 // terminated until the wait has completed.", but claims in the
729 // _beginthread()/_beginthreadex() documentation that "All threads
730 // are terminated if any thread calls abort, exit, _exit, or
731 // ExitProcess." - the latter appears to be the case, even for
732 // threads waiting on the event for a pcap_t).
733 //
734 exit(0);
735 }
736
737 #ifdef _WIN32
738 static void
send_state_change_event(void)739 send_state_change_event(void)
740 {
741 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
742
743 if (!SetEvent(state_change_event))
744 {
745 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
746 "SetEvent on shutdown event failed");
747 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
748 }
749 }
750
751 void
send_shutdown_notification(void)752 send_shutdown_notification(void)
753 {
754 //
755 // Indicate that the server should shut down.
756 //
757 shutdown_server = 1;
758
759 //
760 // Send a state change event, to wake up WSAWaitForMultipleEvents().
761 //
762 send_state_change_event();
763 }
764
765 void
send_reread_configuration_notification(void)766 send_reread_configuration_notification(void)
767 {
768 //
769 // Indicate that the server should re-read its configuration file.
770 //
771 reread_config = 1;
772
773 //
774 // Send a state change event, to wake up WSAWaitForMultipleEvents().
775 //
776 send_state_change_event();
777 }
778
main_ctrl_event(DWORD ctrltype)779 static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
780 {
781 //
782 // ctrltype is one of:
783 //
784 // CTRL_C_EVENT - we got a ^C; this is like SIGINT
785 // CTRL_BREAK_EVENT - we got Ctrl+Break
786 // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
787 // CTRL_LOGOFF_EVENT - a user is logging off; this is received
788 // only by services
789 // CTRL_SHUTDOWN_EVENT - the system is shutting down; this is
790 // received only by services
791 //
792 // For now, we treat all but CTRL_LOGOFF_EVENT as indications
793 // that we should shut down.
794 //
795 switch (ctrltype)
796 {
797 case CTRL_C_EVENT:
798 case CTRL_BREAK_EVENT:
799 case CTRL_CLOSE_EVENT:
800 case CTRL_SHUTDOWN_EVENT:
801 //
802 // Set a shutdown notification.
803 //
804 send_shutdown_notification();
805 break;
806
807 default:
808 break;
809 }
810
811 //
812 // We handled this.
813 //
814 return TRUE;
815 }
816 #else
main_terminate(int sign _U_)817 static void main_terminate(int sign _U_)
818 {
819 //
820 // Note that the server should shut down.
821 // select() should get an EINTR error when we return,
822 // so it will wake up and know it needs to check the flag.
823 //
824 shutdown_server = 1;
825 }
826
main_reread_config(int sign _U_)827 static void main_reread_config(int sign _U_)
828 {
829 //
830 // Note that the server should re-read its configuration file.
831 // select() should get an EINTR error when we return,
832 // so it will wake up and know it needs to check the flag.
833 //
834 reread_config = 1;
835 }
836
main_reap_children(int sign _U_)837 static void main_reap_children(int sign _U_)
838 {
839 pid_t pid;
840 int exitstat;
841
842 // Reap all child processes that have exited.
843 // For reference, Stevens, pg 128
844
845 while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
846 rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
847
848 return;
849 }
850 #endif
851
852 //
853 // Loop waiting for incoming connections and accepting them.
854 //
855 static void
accept_connections(void)856 accept_connections(void)
857 {
858 #ifdef _WIN32
859 struct listen_sock *sock_info;
860 DWORD num_events;
861 WSAEVENT *events;
862 int i;
863 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
864
865 //
866 // How big does the set of events need to be?
867 // One for the shutdown event, plus one for every socket on which
868 // we'll be listening.
869 //
870 num_events = 1; // shutdown event
871 for (sock_info = listen_socks; sock_info;
872 sock_info = sock_info->next)
873 {
874 if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
875 {
876 //
877 // WSAWaitForMultipleEvents() doesn't support
878 // more than WSA_MAXIMUM_WAIT_EVENTS events
879 // on which to wait.
880 //
881 rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
882 exit(2);
883 }
884 num_events++;
885 }
886
887 //
888 // Allocate the array of events.
889 //
890 events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
891 if (events == NULL)
892 {
893 rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
894 exit(2);
895 }
896
897 //
898 // Fill it in.
899 //
900 events[0] = state_change_event; // state change event first
901 for (sock_info = listen_socks, i = 1; sock_info;
902 sock_info = sock_info->next, i++)
903 {
904 WSAEVENT event;
905
906 //
907 // Create an event that is signaled if there's a connection
908 // to accept on the socket in question.
909 //
910 event = WSACreateEvent();
911 if (event == WSA_INVALID_EVENT)
912 {
913 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
914 "Can't create socket event");
915 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
916 exit(2);
917 }
918 if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
919 {
920 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
921 "Can't setup socket event");
922 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
923 exit(2);
924 }
925 events[i] = event;
926 }
927
928 for (;;)
929 {
930 //
931 // Wait for incoming connections.
932 //
933 DWORD ret;
934
935 ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
936 WSA_INFINITE, FALSE);
937 if (ret == WSA_WAIT_FAILED)
938 {
939 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
940 "WSAWaitForMultipleEvents failed");
941 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
942 exit(2);
943 }
944
945 if (ret == WSA_WAIT_EVENT_0)
946 {
947 //
948 // The state change event was set.
949 //
950 if (shutdown_server)
951 {
952 //
953 // Time to quit. Exit the loop.
954 //
955 break;
956 }
957 if (reread_config)
958 {
959 //
960 // We should re-read the configuration
961 // file.
962 //
963 reread_config = 0; // clear the indicator
964 fileconf_read();
965 }
966 }
967
968 //
969 // Check each socket.
970 //
971 for (sock_info = listen_socks, i = 1; sock_info;
972 sock_info = sock_info->next, i++)
973 {
974 WSANETWORKEVENTS network_events;
975
976 if (WSAEnumNetworkEvents(sock_info->sock,
977 events[i], &network_events) == SOCKET_ERROR)
978 {
979 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
980 "WSAEnumNetworkEvents failed");
981 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
982 exit(2);
983 }
984 if (network_events.lNetworkEvents & FD_ACCEPT)
985 {
986 //
987 // Did an error occur?
988 //
989 if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
990 {
991 //
992 // Yes - report it and keep going.
993 //
994 sock_fmterrmsg(errbuf,
995 PCAP_ERRBUF_SIZE,
996 network_events.iErrorCode[FD_ACCEPT_BIT],
997 "Socket error");
998 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
999 continue;
1000 }
1001
1002 //
1003 // Accept the connection.
1004 //
1005 accept_connection(sock_info->sock);
1006 }
1007 }
1008 }
1009 #else
1010 struct listen_sock *sock_info;
1011 int num_sock_fds;
1012
1013 //
1014 // How big does the bitset of sockets on which to select() have
1015 // to be?
1016 //
1017 num_sock_fds = 0;
1018 for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
1019 {
1020 if (sock_info->sock + 1 > num_sock_fds)
1021 {
1022 if ((unsigned int)(sock_info->sock + 1) >
1023 (unsigned int)FD_SETSIZE)
1024 {
1025 rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
1026 exit(2);
1027 }
1028 num_sock_fds = sock_info->sock + 1;
1029 }
1030 }
1031
1032 for (;;)
1033 {
1034 fd_set sock_fds;
1035 int ret;
1036
1037 //
1038 // Set up an fd_set for all the sockets on which we're
1039 // listening.
1040 //
1041 // This set is modified by select(), so we have to
1042 // construct it anew each time.
1043 //
1044 FD_ZERO(&sock_fds);
1045 for (sock_info = listen_socks; sock_info;
1046 sock_info = sock_info->next)
1047 {
1048 FD_SET(sock_info->sock, &sock_fds);
1049 }
1050
1051 //
1052 // Wait for incoming connections.
1053 //
1054 ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
1055 if (ret == -1)
1056 {
1057 if (errno == EINTR)
1058 {
1059 //
1060 // If this is a "terminate the
1061 // server" signal, exit the loop,
1062 // otherwise just keep trying.
1063 //
1064 if (shutdown_server)
1065 {
1066 //
1067 // Time to quit. Exit the loop.
1068 //
1069 break;
1070 }
1071 if (reread_config)
1072 {
1073 //
1074 // We should re-read the configuration
1075 // file.
1076 //
1077 reread_config = 0; // clear the indicator
1078 fileconf_read();
1079 }
1080
1081 //
1082 // Go back and wait again.
1083 //
1084 continue;
1085 }
1086 else
1087 {
1088 rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
1089 strerror(errno));
1090 exit(2);
1091 }
1092 }
1093
1094 //
1095 // Check each socket.
1096 //
1097 for (sock_info = listen_socks; sock_info;
1098 sock_info = sock_info->next)
1099 {
1100 if (FD_ISSET(sock_info->sock, &sock_fds))
1101 {
1102 //
1103 // Accept the connection.
1104 //
1105 accept_connection(sock_info->sock);
1106 }
1107 }
1108 }
1109 #endif
1110
1111 //
1112 // Close all the listen sockets.
1113 //
1114 for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
1115 {
1116 closesocket(sock_info->sock);
1117 }
1118 sock_cleanup();
1119 }
1120
1121 #ifdef _WIN32
1122 //
1123 // A structure to hold the parameters to the daemon service loop
1124 // thread on Windows.
1125 //
1126 // (On UN*X, there is no need for this explicit copy since the
1127 // fork "inherits" the parent stack.)
1128 //
1129 struct params_copy {
1130 PCAP_SOCKET sockctrl;
1131 char *hostlist;
1132 };
1133 #endif
1134
1135 //
1136 // Accept a connection and start a worker thread, on Windows, or a
1137 // worker process, on UN*X, to handle the connection.
1138 //
1139 static void
accept_connection(PCAP_SOCKET listen_sock)1140 accept_connection(PCAP_SOCKET listen_sock)
1141 {
1142 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1143 PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
1144 struct sockaddr_storage from; // generic sockaddr_storage variable
1145 socklen_t fromlen; // keeps the length of the sockaddr_storage variable
1146
1147 #ifdef _WIN32
1148 HANDLE threadId; // handle for the subthread
1149 u_long off = 0;
1150 struct params_copy *params_copy = NULL;
1151 #else
1152 pid_t pid;
1153 #endif
1154
1155 // Initialize errbuf
1156 memset(errbuf, 0, sizeof(errbuf));
1157
1158 for (;;)
1159 {
1160 // Accept the connection
1161 fromlen = sizeof(struct sockaddr_storage);
1162
1163 sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
1164
1165 if (sockctrl != INVALID_SOCKET)
1166 {
1167 // Success.
1168 break;
1169 }
1170
1171 // The accept() call can return this error when a signal is caught
1172 // In this case, we have simply to ignore this error code
1173 // Stevens, pg 124
1174 #ifdef _WIN32
1175 if (WSAGetLastError() == WSAEINTR)
1176 #else
1177 if (errno == EINTR)
1178 #endif
1179 continue;
1180
1181 // Don't check for errors here, since the error can be due to the fact that the thread
1182 // has been killed
1183 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed");
1184 rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
1185 errbuf);
1186 return;
1187 }
1188
1189 #ifdef _WIN32
1190 //
1191 // Put the socket back into blocking mode; doing WSAEventSelect()
1192 // on the listen socket makes that socket non-blocking, and it
1193 // appears that sockets returned from an accept() on that socket
1194 // are also non-blocking.
1195 //
1196 // First, we have to un-WSAEventSelect() this socket, and then
1197 // we can turn non-blocking mode off.
1198 //
1199 // If this fails, we aren't guaranteed that, for example, any
1200 // of the error message will be sent - if it can't be put in
1201 // the socket queue, the send will just fail.
1202 //
1203 // So we just log the message and close the connection.
1204 //
1205 if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
1206 {
1207 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
1208 "WSAEventSelect() failed");
1209 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
1210 sock_close(sockctrl, NULL, 0);
1211 return;
1212 }
1213 if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
1214 {
1215 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
1216 "ioctlsocket(FIONBIO) failed");
1217 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
1218 sock_close(sockctrl, NULL, 0);
1219 return;
1220 }
1221
1222 //
1223 // Make a copy of the host list to pass to the new thread, so that
1224 // if we update it in the main thread, it won't catch us in the
1225 // middle of updating it.
1226 //
1227 // daemon_serviceloop() will free it once it's done with it.
1228 //
1229 char *hostlist_copy = strdup(hostlist);
1230 if (hostlist_copy == NULL)
1231 {
1232 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1233 sock_close(sockctrl, NULL, 0);
1234 return;
1235 }
1236
1237 //
1238 // Allocate a location to hold the values of sockctrl.
1239 // It will be freed in the newly-created thread once it's
1240 // finished with it.
1241 //
1242 params_copy = malloc(sizeof(*params_copy));
1243 if (params_copy == NULL)
1244 {
1245 rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
1246 free(hostlist_copy);
1247 sock_close(sockctrl, NULL, 0);
1248 return;
1249 }
1250 params_copy->sockctrl = sockctrl;
1251 params_copy->hostlist = hostlist_copy;
1252
1253 threadId = (HANDLE)_beginthreadex(NULL, 0,
1254 main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
1255 if (threadId == 0)
1256 {
1257 rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
1258 free(params_copy);
1259 free(hostlist_copy);
1260 sock_close(sockctrl, NULL, 0);
1261 return;
1262 }
1263 CloseHandle(threadId);
1264 #else /* _WIN32 */
1265 pid = fork();
1266 if (pid == -1)
1267 {
1268 rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
1269 strerror(errno));
1270 sock_close(sockctrl, NULL, 0);
1271 return;
1272 }
1273 if (pid == 0)
1274 {
1275 //
1276 // Child process.
1277 //
1278 // Close the socket on which we're listening (must
1279 // be open only in the parent).
1280 //
1281 closesocket(listen_sock);
1282
1283 #if 0
1284 //
1285 // Modify thread params so that it can be killed at any time
1286 // XXX - is this necessary? This is the main and, currently,
1287 // only thread in the child process, and nobody tries to
1288 // cancel us, although *we* may cancel the thread that's
1289 // handling the capture loop.
1290 //
1291 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
1292 goto end;
1293 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
1294 goto end;
1295 #endif
1296
1297 //
1298 // Run the service loop.
1299 // This is passive mode, so we don't care whether we were
1300 // told by the client to close.
1301 //
1302 char *hostlist_copy = strdup(hostlist);
1303 if (hostlist_copy == NULL)
1304 {
1305 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1306 exit(0);
1307 }
1308 (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
1309 nullAuthAllowed, uses_ssl);
1310
1311 exit(0);
1312 }
1313
1314 // I am the parent
1315 // Close the socket for this session (must be open only in the child)
1316 closesocket(sockctrl);
1317 #endif /* _WIN32 */
1318 }
1319
1320 /*!
1321 \brief 'true' main of the program in case the active mode is turned on.
1322
1323 This function loops forever trying to connect to the remote host, until the
1324 daemon is turned down.
1325
1326 \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
1327 just because the thread APIs want this format.
1328 */
1329 #ifdef _WIN32
1330 static unsigned __stdcall
1331 #else
1332 static void *
1333 #endif
main_active(void * ptr)1334 main_active(void *ptr)
1335 {
1336 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1337 PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
1338 struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
1339 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
1340 struct active_pars *activepars;
1341
1342 activepars = (struct active_pars *) ptr;
1343
1344 // Prepare to open a new server socket
1345 memset(&hints, 0, sizeof(struct addrinfo));
1346 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
1347 hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
1348 hints.ai_socktype = SOCK_STREAM;
1349 hints.ai_family = activepars->ai_family;
1350
1351 rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
1352 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
1353 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
1354
1355 // Initialize errbuf
1356 memset(errbuf, 0, sizeof(errbuf));
1357
1358 // Do the work
1359 addrinfo = sock_initaddress(activepars->address, activepars->port,
1360 &hints, errbuf, PCAP_ERRBUF_SIZE);
1361 if (addrinfo == NULL)
1362 {
1363 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1364 return 0;
1365 }
1366
1367 for (;;)
1368 {
1369 int activeclose;
1370
1371 if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
1372 {
1373 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1374
1375 DIAG_OFF_FORMAT_TRUNCATION
1376 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
1377 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
1378 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
1379 DIAG_ON_FORMAT_TRUNCATION
1380
1381 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1382
1383 sleep_secs(RPCAP_ACTIVE_WAIT);
1384
1385 continue;
1386 }
1387
1388 char *hostlist_copy = strdup(hostlist);
1389 if (hostlist_copy == NULL)
1390 {
1391 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1392 activeclose = 0;
1393 sock_close(sockctrl, NULL, 0);
1394 }
1395 else
1396 {
1397 //
1398 // daemon_serviceloop() will free the copy.
1399 //
1400 activeclose = daemon_serviceloop(sockctrl, 1,
1401 hostlist_copy, nullAuthAllowed, uses_ssl);
1402 }
1403
1404 // If the connection is closed by the user explicitly, don't try to connect to it again
1405 // just exit the program
1406 if (activeclose == 1)
1407 break;
1408 }
1409
1410 freeaddrinfo(addrinfo);
1411 return 0;
1412 }
1413
1414 #ifdef _WIN32
1415 //
1416 // Main routine of a passive-mode service thread.
1417 //
main_passive_serviceloop_thread(void * ptr)1418 unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
1419 {
1420 struct params_copy params = *(struct params_copy *)ptr;
1421 free(ptr);
1422
1423 //
1424 // Handle this client.
1425 // This is passive mode, so we don't care whether we were
1426 // told by the client to close.
1427 //
1428 (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
1429 nullAuthAllowed, uses_ssl);
1430
1431 return 0;
1432 }
1433 #endif
1434