1 /* -*- mode: c; c-file-style: "gnu" -*-
3 * Copyright (C) 2003, 2004 Gergely Nagy <algernon@bonehunter.rulez.org>
4 * Copyright (C) 2011 Nikos Mavrogiannopoulos
6 * This file is part of CryWrap.
8 * CryWrap is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * CryWrap is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 * License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "compat/compat.h"
33 #include <arpa/inet.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/x509.h>
41 #include <netinet/in.h>
47 #include <stringprep.h>
48 #include <sys/select.h>
49 #include <sys/socket.h>
50 #include <sys/types.h>
58 static int bhc_log(const char* fmt
, ...)
63 vsyslog(LOG_NOTICE
, fmt
, args
);
69 static int bhc_error(const char* fmt
, ...)
74 vsyslog(LOG_ERR
, fmt
, args
);
80 static int debug_log(const char* fmt
, ...)
92 typedef int (*cry_log_func
)(const char *format
, ...);
93 static cry_log_func cry_log
= bhc_log
;
94 static cry_log_func cry_error
= bhc_error
;
96 /** @defgroup globals Global variables.
99 /** Status flag to toggle on SIGCHLD.
101 static sig_atomic_t sigchld
= 0;
102 /** An array of pids.
103 * This array holds the PIDs of all of our children, indexed by the
104 * socket the associated client connected to us.
106 static pid_t crywrap_children
[_CRYWRAP_MAXCONN
+ 2];
107 static pid_t main_pid
= -1; /**< Pid of the main process */
108 static char *pidfile
= _CRYWRAP_PIDFILE
; /**< File to log our PID
110 /** GNUTLS server credentials.
112 static gnutls_certificate_server_credentials cred
;
113 static gnutls_dh_params dh_params
; /**< GNUTLS DH parameters. */
114 static const int dh_bits
= 1024; /**< GNUTLS DH bits. */
116 /** Bugreport address.
117 * Used by the argp suite.
119 const char *argp_program_bug_address
= "<bugs-gnutls@gnu.org>";
121 * Used by the argp suite.
123 const char *argp_program_version
= __CRYWRAP__
" " _CRYWRAP_VERSION
;
125 /** The options CryWrap takes.
126 * Used by the argp suite.
128 static const struct argp_option _crywrap_options
[] = {
129 {NULL
, 0, NULL
, 0, "Mandatory options:", 1},
130 {"destination", 'd', "IP/PORT", 0, "IP and port to connect to", 1},
131 {NULL
, 0, NULL
, 0, "TLS certificates:", 2},
132 {"pem", 'p', "TYPE=PATH", 0, "Server key and certificate", 2},
133 {"anon", 'a', NULL
, 0, "Enable Anon-DH (don't use a certificate)", 2},
134 {"verify", 'v', "LEVEL", OPTION_ARG_OPTIONAL
,
135 "Verify clients certificate", 2},
136 {NULL
, 0, NULL
, 0, "Other options:", 3},
137 {"user", 'u', "UID", 0, "User ID to run as", 3},
138 {"pidfile", 'P', "PATH", 0, "File to log the PID into", 3},
139 {"inetd", 'i', NULL
, 0, "Enable inetd mode", 3},
140 {"listen", 'l', "IP/PORT", 0, "IP and port to listen on", 3},
141 {"debug", 'D', NULL
, 0, "Do not fork", 2},
142 {0, 0, 0, 0, NULL
, 0}
145 static error_t
_crywrap_config_parse_opt (int key
, char *arg
,
146 struct argp_state
*state
);
147 /** The main argp structure for Crywrap.
149 static const struct argp _crywrap_argp
=
150 {_crywrap_options
, _crywrap_config_parse_opt
, 0,
151 __CRYWRAP__
" -- Security for the masses\v"
152 "The --destination option is mandatory, as is --listen if --inetd "
159 CRYWRAP_P_SUBOPT_CERT
,
160 CRYWRAP_P_SUBOPT_KEY
,
165 /** Helper structure for parsing --pem subopts.
167 static char *_crywrap_p_subopts
[] = {
168 [CRYWRAP_P_SUBOPT_CERT
] = "cert",
169 [CRYWRAP_P_SUBOPT_KEY
] = "key",
170 [CRYWRAP_P_SUBOPT_END
] = NULL
173 /** Helper variable to set if a certificate was explictly set.
175 static int cert_seen
= 0;
179 /* Forward declaration */
180 static int _crywrap_dh_params_generate (void);
182 /** @defgroup signal Signal handlers & co.
189 _crywrap_sigchld_handler (int sig
)
192 signal (sig
, _crywrap_sigchld_handler
);
196 * Regenerates DH and RSA paramaters. Takes a bit long...
199 _crywrap_sighup_handler (int sig
)
201 _crywrap_dh_params_generate ();
203 gnutls_certificate_set_dh_params (cred
, dh_params
);
205 signal (sig
, _crywrap_sighup_handler
);
208 /** Generic signal handler.
209 * This one removes the #pidfile, if necessary.
212 _crywrap_sighandler (int sig
)
214 if (getpid () == main_pid
)
216 cry_log ("Exiting on signal %d", sig
);
217 if (pidfile
&& *pidfile
)
225 /** @defgroup parsing Option parsing
229 /** Service resolver.
230 * Resolves a service - be it a name or a number.
232 * @param serv is the port to resolve.
234 * @returns The purt number, or -1 on error.
237 _crywrap_port_get (const char *serv
)
245 se
= getservbyname (serv
, "tcp");
249 port
= ntohs (se
->s_port
);
254 /** Address resolver.
255 * Resolves an address - be it numeric or a hostname, IPv4 or IPv6.
257 * @param hostname is the host to resolve.
258 * @param addr is the structure to put the result into.
260 * @returns Zero on success, -1 on error.
263 _crywrap_addr_get (const char *hostname
, struct sockaddr_storage
**addr
)
265 struct addrinfo
*res
;
266 struct addrinfo hints
;
270 if (idna_to_ascii_lz (hostname
, &lz
, 0) != IDNA_SUCCESS
)
273 memset (&hints
, 0, sizeof (hints
));
274 hints
.ai_family
= PF_UNSPEC
;
275 hints
.ai_socktype
= SOCK_STREAM
;
276 hints
.ai_protocol
= IPPROTO_IP
;
277 *addr
= bhc_calloc (1, sizeof (struct sockaddr_storage
));
279 if (getaddrinfo (lz
, NULL
, &hints
, &res
) != 0)
287 switch (res
->ai_addr
->sa_family
)
290 len
= sizeof (struct sockaddr_in
);
293 len
= sizeof (struct sockaddr_in6
);
300 if (len
< (ssize_t
)res
->ai_addrlen
)
306 memcpy (*addr
, res
->ai_addr
, res
->ai_addrlen
);
312 /** Parse a HOST/IP pair.
313 * Splits up a given HOST/IP pair, and converts them into structures
314 * directly usable by libc routines.
316 * @param ip is the HOST/IP pair to parse.
317 * @param port is a pointer to an integer where the port number should
319 * @param addr is the destination of the resolved and parsed IP.
321 * @returns Zero on success, -1 on error.
324 _crywrap_parse_ip (const char *ip
, in_port_t
*port
,
325 struct sockaddr_storage
**addr
, char **host
)
330 tmp
= strchr (ip
, '/');
337 s_ip
= bhc_strdup ("0.0.0.0");
338 *port
= (in_port_t
)_crywrap_port_get (&ip
[1]);
342 *port
= (in_port_t
)_crywrap_port_get (&tmp
[1]);
343 s_ip
= bhc_strndup (ip
, tmp
- ip
);
350 *host
= strdup (s_ip
);
352 return _crywrap_addr_get (s_ip
, addr
);
355 /** Argument parsing routine.
356 * Used by the argp suite.
359 _crywrap_config_parse_opt (int key
, char *arg
, struct argp_state
*state
)
361 crywrap_config_t
*cfg
= (crywrap_config_t
*)state
->input
;
362 char *pem_cert
, *pem_key
, *subopts
, *value
;
369 cry_error
= debug_log
;
372 if (_crywrap_parse_ip (arg
, &cfg
->dest
.port
, &cfg
->dest
.addr
,
373 &cfg
->dest
.host
) < 0)
374 argp_error (state
, "Could not resolve address: `%s'", arg
);
377 if (_crywrap_parse_ip (arg
, &cfg
->listen
.port
,
378 &cfg
->listen
.addr
, NULL
) < 0)
379 argp_error (state
, "Could not resolve address: `%s'", arg
);
382 cfg
->uid
= atoi (arg
);
386 cfg
->pidfile
= bhc_strdup (arg
);
394 while (*subopts
!= '\0')
395 switch (bhc_getsubopt (&subopts
, _crywrap_p_subopts
, &value
))
397 case CRYWRAP_P_SUBOPT_CERT
:
398 pem_cert
= bhc_strdup (value
);
400 case CRYWRAP_P_SUBOPT_KEY
:
401 pem_key
= bhc_strdup (value
);
404 pem_cert
= bhc_strdup (value
);
408 pem_key
= bhc_strdup (pem_cert
);
410 pem_cert
= bhc_strdup (pem_key
);
411 if (gnutls_certificate_set_x509_key_file (cred
, pem_cert
, pem_key
,
412 GNUTLS_X509_FMT_PEM
) < 0)
413 argp_error (state
, "error reading X.509 key or certificate file.");
424 cfg
->verify
= (arg
) ? atoi (arg
) : 1;
429 if (!cfg
->listen
.addr
|| !cfg
->dest
.addr
)
432 "a listening and a destination address must be set!");
436 argp_error (state
, "a destination address must be set!");
441 if (gnutls_certificate_set_x509_key_file (cred
, _CRYWRAP_PEMFILE
,
443 GNUTLS_X509_FMT_PEM
) < 0)
444 argp_error (state
, "error reading X.509 key or certificate file.");
447 return ARGP_ERR_UNKNOWN
;
452 /** Configuration parsing.
453 * Sets up the default values, and parses the command-line options
456 * @note Does not return if an error occurred.
458 static crywrap_config_t
*
459 _crywrap_config_parse (int argc
, char **argv
)
461 crywrap_config_t
*config
=
462 (crywrap_config_t
*)bhc_malloc (sizeof (crywrap_config_t
));
464 config
->listen
.port
= 0;
465 config
->listen
.addr
= NULL
;
466 config
->dest
.port
= 0;
467 config
->dest
.addr
= NULL
;
469 config
->uid
= _CRYWRAP_UID
;
470 config
->pidfile
= _CRYWRAP_PIDFILE
;
475 argp_parse (&_crywrap_argp
, argc
, argv
, 0, 0, config
);
481 /** @defgroup tls Lower-level TLS routines.
485 /** Create a GNUTLS session.
486 * Initialises the cyphers and the session database for a new TLS
489 * @returns The newly created TLS session.
491 static gnutls_session
492 _crywrap_tls_session_create (const crywrap_config_t
*config
)
494 gnutls_session session
;
496 gnutls_init (&session
, GNUTLS_SERVER
);
500 gnutls_priority_set_direct(session
, "NORMAL:+ANON-ECDH:+ANON-DH", NULL
);
501 gnutls_credentials_set (session
, GNUTLS_CRD_ANON
, cred
);
503 gnutls_priority_set_direct(session
, "NORMAL", NULL
);
504 gnutls_credentials_set (session
, GNUTLS_CRD_CERTIFICATE
, cred
);
507 gnutls_dh_set_prime_bits (session
, dh_bits
);
509 gnutls_handshake_set_private_extensions (session
, 1);
512 gnutls_certificate_server_set_request (session
, GNUTLS_CERT_REQUEST
);
517 /** (Re)Initialise Diffie Hellman parameters.
521 _crywrap_dh_params_generate (void)
523 if (gnutls_dh_params_init (&dh_params
) < 0)
525 cry_error ("%s", "Error in dh parameter initialisation.");
529 if (gnutls_dh_params_generate2 (dh_params
, dh_bits
) < 0)
531 cry_error ("%s", "Error in prime generation.");
535 gnutls_certificate_set_dh_params (cred
, dh_params
);
540 /** Generate initial DH and RSA params.
541 * Loads the pre-generated DH primes.
544 _crywrap_tls_init (void)
546 gnutls_datum dh
= { _crywrap_prime_dh_1024
, sizeof(_crywrap_prime_dh_1024
) };
548 gnutls_dh_params_init (&dh_params
);
549 gnutls_dh_params_import_pkcs3 (dh_params
, &dh
, GNUTLS_X509_FMT_PEM
);
551 gnutls_certificate_set_dh_params (cred
, dh_params
);
555 /** @defgroup networking Networking
559 /** Bind to an address.
560 * This one binds to an address, handles errors and anything that may
563 * @param ai is the address information.
564 * @param listen_port is the port to bind to, and listen on.
566 * @returns The bound filedescriptor, or -1 on error.
569 _crywrap_bind (const struct addrinfo
*ai
, int listen_port
)
574 char sock_name
[NI_MAXHOST
];
576 listenfd
= socket (ai
->ai_family
, SOCK_STREAM
, IPPROTO_IP
);
579 cry_error ("socket: %s", strerror (errno
));
583 memset (sock_name
, 0, sizeof (sock_name
));
584 getnameinfo ((struct sockaddr
*)ai
->ai_addr
, ai
->ai_addrlen
, sock_name
,
585 sizeof (sock_name
), NULL
, 0, NI_NUMERICHOST
);
587 switch (ai
->ai_family
)
590 ((struct sockaddr_in6
*)(ai
->ai_addr
))->sin6_port
= listen_port
;
593 ((struct sockaddr_in
*)(ai
->ai_addr
))->sin_port
= listen_port
;
597 ret
= setsockopt (listenfd
, SOL_SOCKET
, SO_REUSEADDR
,
601 cry_error ("setsockopt: %s (%s)", strerror (errno
), sock_name
);
605 ret
= bind (listenfd
, ai
->ai_addr
, ai
->ai_addrlen
);
608 cry_error ("bind to %s failed: %s", sock_name
, strerror (errno
));
612 if (listen (listenfd
, _CRYWRAP_MAXCONN
) != 0)
614 cry_error ("listen on %s failed: %s", sock_name
, strerror (errno
));
618 cry_log ("Socket bound to port %d on %s.", ntohs (listen_port
), sock_name
);
623 /** Set up a listening socket.
624 * Sets up a listening socket on all the required addresses.
626 * @param config holds the CryWrap configuration, from where the
627 * listen address and port will be extracted.
629 * @returns The listening FD on success, -1 on error.
632 _crywrap_listen (const crywrap_config_t
*config
)
634 struct addrinfo
*cur
;
637 cur
= bhc_calloc (1, sizeof (struct addrinfo
));
638 cur
->ai_family
= config
->listen
.addr
->ss_family
;
640 switch (cur
->ai_family
)
643 cur
->ai_addrlen
= sizeof (struct sockaddr_in6
);
646 cur
->ai_addrlen
= sizeof (struct sockaddr_in
);
650 cur
->ai_addr
= bhc_malloc (cur
->ai_addrlen
);
651 memcpy (cur
->ai_addr
, config
->listen
.addr
, cur
->ai_addrlen
);
653 ret
= _crywrap_bind (cur
, htons (config
->listen
.port
));
660 /** Connect to a remote server.
661 * Estabilishes a connection to a remote server, and handles all
662 * errors and anything that may arise during this process.
664 * @param addr is the address of the remote server.
665 * @param port is the port to connect to.
667 * @returns the connected socket on success, otherwise it exits.
670 _crywrap_remote_connect (const struct sockaddr_storage
*addr
, int port
)
672 struct addrinfo
*cur
;
675 cur
= bhc_calloc (1, sizeof (struct addrinfo
));
676 cur
->ai_family
= addr
->ss_family
;
678 switch (cur
->ai_family
)
681 cur
->ai_addrlen
= sizeof (struct sockaddr_in6
);
684 cur
->ai_addrlen
= sizeof (struct sockaddr_in
);
688 cur
->ai_addr
= bhc_malloc (cur
->ai_addrlen
);
689 memcpy (cur
->ai_addr
, addr
, cur
->ai_addrlen
);
691 switch (cur
->ai_family
)
694 ((struct sockaddr_in6
*)(cur
->ai_addr
))->sin6_port
= port
;
697 ((struct sockaddr_in
*)(cur
->ai_addr
))->sin_port
= port
;
701 sock
= socket (cur
->ai_family
, SOCK_STREAM
, IPPROTO_IP
);
704 cry_error ("socket(): %s", strerror (errno
));
708 if (connect (sock
, cur
->ai_addr
, cur
->ai_addrlen
) < 0)
710 cry_error ("connect(): %s", strerror (errno
));
722 /** @defgroup crywrap Main CryWrap code.
727 * Drop privileges, if running as root.
728 * Upon failure, it will make CryWrap exit.
731 _crywrap_privs_drop (const crywrap_config_t
*config
)
737 cry_log ("%s", "Not running as root, not dropping privileges.");
741 if ((pwd
= getpwuid (config
->uid
)) == NULL
)
743 cry_error ("getpwuid(): %s", strerror (errno
));
747 if (initgroups (pwd
->pw_name
, pwd
->pw_gid
) == -1)
749 cry_error ("initgroups(): %s", strerror (errno
));
753 if (setgid (pwd
->pw_gid
) == -1)
755 cry_error ("setgid(): %s", strerror (errno
));
759 if (setuid (config
->uid
))
761 cry_error ("setuid(): %s", strerror (errno
));
766 /** Set up the PID file.
767 * Checks if a #pidfile already exists, and create one - containing the
768 * current PID - if one does not.
770 * @note Exits upon error.
773 _crywrap_setup_pidfile (const crywrap_config_t
*config
)
778 if (!config
->pidfile
|| !*(config
->pidfile
))
781 if (!access (config
->pidfile
, F_OK
))
783 cry_error ("Pidfile (%s) already exists. Exiting.", config
->pidfile
);
786 if ((pidfilefd
= open (config
->pidfile
,
787 O_WRONLY
| O_CREAT
| O_TRUNC
, 0644)) == -1)
789 cry_error ("Cannot create pidfile (%s): %s.\n", config
->pidfile
,
793 fchown (pidfilefd
, config
->uid
, (gid_t
)-1);
795 main_pid
= getpid ();
796 snprintf (mypid
, sizeof (mypid
), "%d\n", main_pid
);
797 write (pidfilefd
, mypid
, strlen (mypid
));
799 pidfile
= config
->pidfile
;
802 /** Child cleanup routine.
803 * Called after a SIGCHLD is received. Walks through #crywrap_children
804 * and closes the socket of the one that exited.
807 _crywrap_reap_children (void)
812 while ((child
= waitpid (-1, &status
, WNOHANG
)) > (pid_t
) 0)
814 for (i
= 0; i
< _CRYWRAP_MAXCONN
; i
++)
816 if (!crywrap_children
[i
])
818 if (child
== crywrap_children
[i
])
820 shutdown (i
, SHUT_RDWR
);
822 crywrap_children
[i
] = 0;
829 /** Handles one client.
830 * This one connects to the remote server, and proxies every traffic
831 * between our client and the server.
833 * @param config is the main CryWrap configuration structure.
834 * @param insock is the socket through which the client sends input.
835 * @param outsock is the socket through which we send output.
837 * @note Exits on error.
840 _crywrap_do_one (const crywrap_config_t
*config
, int insock
, int outsock
)
843 gnutls_session session
;
844 char buffer
[_CRYWRAP_MAXBUF
+ 2];
846 unsigned int status
= 0;
847 struct sockaddr_storage faddr
;
848 socklen_t socklen
= sizeof (struct sockaddr_storage
);
849 char peer_name
[NI_MAXHOST
];
851 /* Log the connection */
852 if (getpeername (insock
, (struct sockaddr
*)&faddr
, &socklen
) != 0)
853 cry_error ("getpeername(): %s", strerror (errno
));
856 getnameinfo ((struct sockaddr
*)&faddr
,
857 sizeof (struct sockaddr_storage
), peer_name
,
858 sizeof (peer_name
), NULL
, 0, NI_NUMERICHOST
);
859 cry_log ("Accepted connection from %s on %d to %s/%d",
860 peer_name
, insock
, config
->dest
.host
,
864 /* Do the handshake with our peer */
865 session
= _crywrap_tls_session_create (config
);
866 gnutls_transport_set_ptr2 (session
,
867 (gnutls_transport_ptr_t
)insock
,
868 (gnutls_transport_ptr_t
)outsock
);
872 ret
= gnutls_handshake(session
);
874 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
878 cry_error ("Handshake failed: %s", gnutls_strerror (ret
));
879 gnutls_alert_send_appropriate(session
, ret
);
883 /* Verify the client's certificate, if any. */
886 ret
= gnutls_certificate_verify_peers2 (session
, &status
);
888 cry_log ("Error getting certificate from client: %s",
889 gnutls_strerror (ret
));
891 if (ret
== 0 && status
!= 0)
894 case GNUTLS_CERT_INVALID
:
895 cry_log ("%s", "Client certificate not trusted or invalid");
898 cry_log ("%s", "Unknown error while getting the certificate");
902 if (config
->verify
> 1 && (ret
< 0 || status
!= 0))
909 /* Connect to the remote host */
910 sock
= _crywrap_remote_connect (config
->dest
.addr
,
911 htons (config
->dest
.port
));
916 FD_SET (insock
, &fdset
);
917 FD_SET (sock
, &fdset
);
919 bzero (buffer
, _CRYWRAP_MAXBUF
+ 1);
920 select (sock
+ 1, &fdset
, NULL
, NULL
, NULL
);
923 if (FD_ISSET (insock
, &fdset
))
925 ret
= gnutls_record_recv (session
, buffer
, _CRYWRAP_MAXBUF
);
928 cry_log ("%s", "Peer has closed the GNUTLS connection");
933 cry_log ("Received corrupted data: %s.",
934 gnutls_strerror (ret
));
938 send (sock
, buffer
, ret
, 0);
942 if (FD_ISSET (sock
, &fdset
))
944 ret
= recv (sock
, buffer
, _CRYWRAP_MAXBUF
, 0);
947 cry_log ("%s", "Server has closed the connection");
952 cry_log ("Received corrupted data: %s.", strerror (errno
));
961 r
= gnutls_record_send (session
, &buffer
[o
], ret
- o
);
963 } while (r
> 0 && ret
> o
);
966 cry_log ("Received corrupted data: %s", gnutls_strerror (r
));
972 gnutls_bye (session
, GNUTLS_SHUT_WR
);
973 gnutls_deinit (session
);
977 return (ret
== 0) ? 0 : 1;
980 /** CryWrap entry point.
981 * This is the main entry point - controls the whole program and so
985 main (int argc
, char **argv
, char **envp
)
987 crywrap_config_t
*config
;
990 openlog (__CRYWRAP__
, LOG_PID
, LOG_DAEMON
);
992 if (gnutls_global_init () < 0)
994 cry_error ("%s", "Global TLS state initialisation failed.");
997 if (gnutls_certificate_allocate_credentials (&cred
) < 0)
999 cry_error ("%s", "Couldn't allocate credentials.");
1003 stringprep_locale_charset ();
1005 bhc_setproctitle_init (argc
, argv
, envp
);
1006 config
= _crywrap_config_parse (argc
, argv
);
1007 bhc_setproctitle (__CRYWRAP__
);
1009 _crywrap_tls_init ();
1013 _crywrap_privs_drop (config
);
1014 exit (_crywrap_do_one (config
, 0, 1));
1017 #if CRYWRAP_OPTION_FORK
1021 cry_error ("daemon: %s", strerror (errno
));
1026 cry_log ("%s", "Crywrap starting...");
1028 server_socket
= _crywrap_listen (config
);
1029 if (server_socket
< 0)
1032 if (!config
->debug
) _crywrap_setup_pidfile (config
);
1033 _crywrap_privs_drop (config
);
1035 signal (SIGTERM
, _crywrap_sighandler
);
1036 signal (SIGQUIT
, _crywrap_sighandler
);
1037 signal (SIGSEGV
, _crywrap_sighandler
);
1038 signal (SIGPIPE
, SIG_IGN
);
1039 signal (SIGHUP
, _crywrap_sighup_handler
);
1041 cry_log ("%s", "Accepting connections");
1043 memset (crywrap_children
, 0, sizeof (crywrap_children
));
1044 signal (SIGCHLD
, _crywrap_sigchld_handler
);
1049 #if !BHC_OPTION_DEBUG
1054 _crywrap_reap_children ();
1056 csock
= accept (server_socket
, NULL
, NULL
);
1060 #if !BHC_OPTION_DEBUG
1065 exit (_crywrap_do_one (config
, csock
, csock
));
1068 cry_error ("%s", "Forking error.");
1072 crywrap_children
[csock
] = child
;
1076 _crywrap_do_one (config
, csock
, csock
);
1086 /** arch-tag: 3d45d946-5d09-493d-ae6e-26effb71eb6b */