Bug Summary

File:src/crywrap/crywrap.c
Location:line 193, column 11
Description:Although the value stored to 'child' is used in the enclosing expression, the value is never actually read from 'child'

Annotated Source Code

1/* -*- mode: c; c-file-style: "gnu" -*-
2 * crywrap.c -- CryWrap
3 * Copyright (C) 2003, 2004 Gergely Nagy <algernon@bonehunter.rulez.org>
4 * Copyright (C) 2011 Nikos Mavrogiannopoulos
5 *
6 * This file is part of CryWrap.
7 *
8 * CryWrap is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * CryWrap is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/** @file crywrap.c
23 * CryWrap itself.
24 */
25
26#include <config.h>
27
28#ifdef HAVE_ARGP_H
29#include <argp.h>
30#endif
31#include <arpa/inet.h>
32#include <errno(*__errno_location ()).h>
33#include <fcntl.h>
34#include <gnutls/gnutls.h>
35#include <gnutls/x509.h>
36#include <grp.h>
37#include <idna.h>
38#include <netdb.h>
39#include <netinet/in.h>
40#include <pwd.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <stringprep.h>
46#include <sys/select.h>
47#include <sys/socket.h>
48#include <sys/types.h>
49#include <sys/wait.h>
50#include <syslog.h>
51#include <stdarg.h>
52#include <unistd.h>
53
54/* Gnulib portability files. */
55#include "progname.h"
56#include "argp.h"
57#include <read-file.h>
58
59#include "crywrap.h"
60#include "primes.h"
61
62static int system_log(const char* fmt, ...)
63#ifdef __GNUC__4
64 __attribute__ ((format (printf, 1, 2)))
65#endif
66;
67
68static int system_log_error(const char* fmt, ...)
69#ifdef __GNUC__4
70 __attribute__ ((format (printf, 1, 2)))
71#endif
72;
73
74static int debug_log(const char* fmt, ...)
75#ifdef __GNUC__4
76 __attribute__ ((format (printf, 1, 2)))
77#endif
78;
79
80typedef int (*cry_log_func)(const char *format, ...)
81#ifdef __GNUC__4
82 __attribute__ ((format (printf, 1, 2)))
83#endif
84;
85
86static cry_log_func cry_log = system_log;
87static cry_log_func cry_error = system_log_error;
88
89static void
90tls_audit_log_func (gnutls_session_t session, const char *str)
91{
92 char peer_name[NI_MAXHOST1025] = "Unknown";
93 gnutls_transport_ptr_t r, s;
94 struct sockaddr_storage faddr;
95 socklen_t socklen = sizeof (struct sockaddr_storage);
96
97 if (session != NULL((void*)0))
98 {
99 gnutls_transport_get_ptr2(session, &r, &s);
100
101 /* Log the connection */
102 if (getpeername ((int)(long)r, (struct sockaddr *)&faddr, &socklen) != 0)
103 cry_error ("getpeername(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
104
105 cry_log ("Peer %s: %s", peer_name, str);
106 }
107 else
108 cry_log ("%s", str);
109
110}
111
112/** @defgroup globals Global variables.
113 * @{
114 */
115
116/** An array of pids.
117 * This array holds the PIDs of all of our children, indexed by the
118 * socket the associated client connected to us.
119 */
120static pid_t main_pid = -1; /**< Pid of the main process */
121static const char *pidfile = _CRYWRAP_PIDFILE"/var/run/crywrap.pid"; /**< File to log our PID
122 into. */
123
124/** GNUTLS server credentials.
125 */
126static gnutls_certificate_server_credentials cred;
127static gnutls_dh_paramsgnutls_dh_params_t dh_params; /**< GNUTLS DH parameters. */
128static gnutls_datumgnutls_datum_t dh_file = { _crywrap_prime_dh_1024, sizeof(_crywrap_prime_dh_1024) }; /**< Diffie Hellman parameters */
129
130/** Bugreport address.
131 * Used by the argp suite.
132 */
133const char *argp_program_bug_address = "<bugs-gnutls@gnu.org>";
134/** Porgram version.
135 * Used by the argp suite.
136 */
137const char *argp_program_version = __CRYWRAP__"crywrap" " " _CRYWRAP_VERSION"0.2." "3";
138
139/* The certificate and key files */
140static char *pem_cert = NULL((void*)0);
141static char *pem_key = NULL((void*)0);
142
143
144/** The options CryWrap takes.
145 * Used by the argp suite.
146 */
147static const struct argp_option _crywrap_options[] = {
148 {NULL((void*)0), 0, NULL((void*)0), 0, "Mandatory options:", 1},
149 {"destination", 'd', "IP/PORT", 0, "IP and port to connect to", 1},
150 {"listen", 'l', "IP/PORT", 0, "IP and port to listen on", 1},
151 {NULL((void*)0), 0, NULL((void*)0), 0, "TLS certificates:", 2},
152 {"key", 'k', "FILE", 0, "Server key", 2},
153 {"cert", 'c', "FILE", 0, "Server certificate", 2},
154 {"ca", 'z', "FILE", 0, "CA certificate", 2},
155 {"anon", 'a', NULL((void*)0), 0, "Enable anonymous authentication (no certificates)", 2},
156 {"verify", 'v', "LEVEL", OPTION_ARG_OPTIONAL0x1,
157 "Verify clients certificate (1: verify if exists, 2: require)", 2},
158 {NULL((void*)0), 0, NULL((void*)0), 0, "Other options:", 3},
159 {"dhparams", 'r', "FILE", 0, "Diffie Hellman (PKCS #3) parameters file", 3},
160 {"user", 'u', "UID", 0, "User ID to run as", 3},
161 {"pidfile", 'P', "PATH", 0, "File to log the PID into", 3},
162 {"priority", 'p', "STRING", 0, "GnuTLS ciphersuite priority string", 3},
163 {"inetd", 'i', NULL((void*)0), 0, "Enable inetd mode", 3},
164 {"debug", 'D', NULL((void*)0), 0, "Run the server into foreground", 3},
165 {0, 0, 0, 0, NULL((void*)0), 0}
166};
167
168static error_t _crywrap_config_parse_opt (int key, char *arg,
169 struct argp_state *state);
170/** The main argp structure for Crywrap.
171 */
172static const struct argp _crywrap_argp =
173 {_crywrap_options, _crywrap_config_parse_opt, 0,
174 __CRYWRAP__"crywrap" " -- Security for the masses\v"
175 "The --destination option is mandatory, as is --listen if --inetd "
176 "was not used.",
177 NULL((void*)0), NULL((void*)0), NULL((void*)0)};
178
179/** @} */
180
181/** @defgroup signal Signal handlers & co.
182 * @{
183 */
184
185/** SIGCHLD handler
186 */
187static void
188_crywrap_sigchld_handler (int sig)
189{
190pid_t child;
191int status;
192
193 while ((child = waitpid (-1, &status, WNOHANG1)) > (pid_t) 0)
Although the value stored to 'child' is used in the enclosing expression, the value is never actually read from 'child'
194 signal (sig, _crywrap_sigchld_handler);
195}
196
197/* Helper functions to load a certificate and key
198 * files into memory.
199 */
200static gnutls_datum_t
201load_file (const char *file)
202{
203 gnutls_datum_t loaded_file = { NULL((void*)0), 0 };
204 size_t length;
205
206 loaded_file.data = read_binary_file_gnutls_read_binary_file (file, &length);
207 if (loaded_file.data)
208 loaded_file.size = (unsigned int) length;
209
210 return loaded_file;
211}
212
213/** Generic signal handler.
214 * This one removes the #pidfile, if necessary.
215 */
216static void
217_crywrap_sighandler (int sig)
218{
219 if (getpid () == main_pid)
220 {
221 cry_log ("Exiting on signal %d", sig);
222 if (pidfile && *pidfile)
223 unlink (pidfile);
224 closelog ();
225 exit (0);
226 }
227}
228/** @} */
229
230/** @defgroup parsing Option parsing
231 * @{
232 */
233
234/** Service resolver.
235 * Resolves a service - be it a name or a number.
236 *
237 * @param serv is the port to resolve.
238 *
239 * @returns The purt number, or -1 on error.
240 */
241static int
242_crywrap_port_get (const char *serv)
243{
244 int port;
245 struct servent *se;
246
247 if (!serv)
248 return -1;
249
250 se = getservbyname (serv, "tcp");
251 if (!se)
252 port = atoi (serv);
253 else
254 port = ntohs (se->s_port);
255
256 return port;
257}
258
259/** Address resolver.
260 * Resolves an address - be it numeric or a hostname, IPv4 or IPv6.
261 *
262 * @param hostname is the host to resolve.
263 * @param addr is the structure to put the result into.
264 *
265 * @returns Zero on success, -1 on error.
266 */
267static int
268_crywrap_addr_get (const char *hostname, struct sockaddr_storage **addr)
269{
270 struct addrinfo *res;
271 struct addrinfo hints;
272 ssize_t len;
273 char *lz = NULL((void*)0);
274
275 if (idna_to_ascii_lz (hostname, &lz, 0) != IDNA_SUCCESS)
276 return -1;
277
278 memset (&hints, 0, sizeof (hints));
279 hints.ai_family = PF_UNSPEC0;
280 hints.ai_socktype = SOCK_STREAMSOCK_STREAM;
281 hints.ai_protocol = IPPROTO_IPIPPROTO_IP;
282 *addr = calloc (1, sizeof (struct sockaddr_storage));
283 if (*addr == NULL((void*)0))
284 {
285 free(lz);
286 return -1;
287 }
288
289 if (getaddrinfo (lz, NULL((void*)0), &hints, &res) != 0)
290 {
291 free (lz);
292 return -1;
293 }
294
295 free (lz);
296
297 switch (res->ai_addr->sa_family)
298 {
299 case AF_INET2:
300 len = sizeof (struct sockaddr_in);
301 break;
302 case AF_INET610:
303 len = sizeof (struct sockaddr_in6);
304 break;
305 default:
306 freeaddrinfo (res);
307 return -1;
308 }
309
310 if (len < (ssize_t)res->ai_addrlen)
311 {
312 freeaddrinfo (res);
313 return -1;
314 }
315
316 memcpy (*addr, res->ai_addr, res->ai_addrlen);
317 freeaddrinfo (res);
318
319 return 0;
320}
321
322/** Parse a HOST/IP pair.
323 * Splits up a given HOST/IP pair, and converts them into structures
324 * directly usable by libc routines.
325 *
326 * @param ip is the HOST/IP pair to parse.
327 * @param port is a pointer to an integer where the port number should
328 * go.
329 * @param addr is the destination of the resolved and parsed IP.
330 *
331 * @returns Zero on success, -1 on error.
332 */
333static int
334_crywrap_parse_ip (const char *ip, in_port_t *port,
335 struct sockaddr_storage **addr, char **host)
336{
337 char *s_ip;
338 char *tmp;
339
340 tmp = strchr (ip, '/');
341
342 if (!tmp)
343 return -1;
344
345 if (tmp == ip)
346 {
347 s_ip = strdup ("0.0.0.0");
348 *port = (in_port_t)_crywrap_port_get (&ip[1]);
349 }
350 else
351 {
352 *port = (in_port_t)_crywrap_port_get (&tmp[1]);
353 s_ip = strndup (ip, tmp - ip);
354 }
355
356 if (!*port)
357 return -1;
358
359 if (host)
360 *host = strdup (s_ip);
361
362 return _crywrap_addr_get (s_ip, addr);
363}
364
365/** Argument parsing routine.
366 * Used by the argp suite.
367 */
368static error_t
369_crywrap_config_parse_opt (int key, char *arg, struct argp_state *state)
370{
371 crywrap_config_t *cfg = (crywrap_config_t *)state->input;
372 int ret;
373
374 switch (key)
375 {
376 case 'D':
377 cfg->debug = 1;
378 cry_log = debug_log;
379 cry_error = debug_log;
380 break;
381 case 'd':
382 if (_crywrap_parse_ip (arg, &cfg->dest.port, &cfg->dest.addr,
383 &cfg->dest.host) < 0)
384 argp_error (state, "Could not resolve address: `%s'", arg);
385 break;
386 case 'l':
387 if (_crywrap_parse_ip (arg, &cfg->listen.port,
388 &cfg->listen.addr, NULL((void*)0)) < 0)
389 argp_error (state, "Could not resolve address: `%s'", arg);
390 break;
391 case 'u':
392 cfg->uid = atoi (arg);
393 break;
394 case 'P':
395 if (arg && *arg)
396 cfg->pidfile = strdup (arg);
397 else
398 cfg->pidfile = NULL((void*)0);
399 break;
400 case 'r':
401 if (arg && *arg)
402 {
403 dh_file = load_file(arg);
404 if (dh_file.data == NULL((void*)0))
405 argp_error (state, "error loading Diffie Hellman parameters file: %s.", arg);
406 }
407 break;
408 case 'p':
409 if (arg && *arg)
410 {
411 const char* pos;
412 ret = gnutls_priority_init(&cfg->priority, arg, &pos);
413 if (ret < 0)
414 argp_error (state, "error in priority string at: %s.", pos);
415 }
416 break;
417 case 'c':
418 if (arg && *arg)
419 pem_cert = strdup (arg);
420 break;
421 case 'k':
422 if (arg && *arg)
423 pem_key = strdup (arg);
424 break;
425
426 break;
427 case 'i':
428 cfg->inetd = 1;
429 break;
430 case 'a':
431 {
432 const char* pos;
433 ret = gnutls_priority_init(&cfg->priority, "NORMAL:+ANON-ECDH:+ANON-DH", &pos);
434 if (ret < 0)
435 argp_error (state, "error in priority string at: %s.", pos);
436 }
437 cfg->verify = 0;
438 cfg->anon = 1;
439 break;
440 case 'v':
441 cfg->verify = (arg) ? atoi (arg) : 1;
442 break;
443 case 'z':
444 ret = gnutls_certificate_set_x509_trust_file (cred, arg,
445 GNUTLS_X509_FMT_PEM);
446 if (ret < 0)
447 argp_error (state, "error reading X.509 CA file: %s.", gnutls_strerror(ret));
448 break;
449
450 case ARGP_KEY_END0x1000001:
451 if (!cfg->inetd)
452 {
453 if (!cfg->listen.addr || !cfg->dest.addr)
454 argp_error
455 (state,
456 "a listening and a destination address must be set!");
457 }
458 else
459 if (!cfg->dest.addr)
460 argp_error (state, "a destination address must be set!");
461 if (cfg->anon)
462 break;
463 if (pem_cert == NULL((void*)0) || pem_key == NULL((void*)0))
464 ret = gnutls_certificate_set_x509_key_file (cred, _CRYWRAP_PEMFILE"/usr/local/etc" "/crywrap" "/server.pem",
465 _CRYWRAP_PEMFILE"/usr/local/etc" "/crywrap" "/server.pem",
466 GNUTLS_X509_FMT_PEM);
467 else
468 ret = gnutls_certificate_set_x509_key_file (cred, pem_cert, pem_key,
469 GNUTLS_X509_FMT_PEM);
470
471 if (ret < 0)
472 argp_error (state, "Error reading X.509 key or certificate file: %s", gnutls_strerror(ret));
473 break;
474 default:
475 return ARGP_ERR_UNKNOWN7;
476 }
477
478 return 0;
479}
480
481/** Configuration parsing.
482 * Sets up the default values, and parses the command-line options
483 * using argp.
484 *
485 * @note Does not return if an error occurred.
486 */
487static crywrap_config_t *
488_crywrap_config_parse (int argc, char **argv)
489{
490 crywrap_config_t *config =
491 (crywrap_config_t *)malloc (sizeof (crywrap_config_t));
492
493 if (config == NULL((void*)0))
494 return NULL((void*)0);
495
496 config->listen.port = 0;
497 config->listen.addr = NULL((void*)0);
498 config->dest.port = 0;
499 config->dest.addr = NULL((void*)0);
500 config->priority = NULL((void*)0);
501 config->uid = _CRYWRAP_UID65534;
502 config->pidfile = _CRYWRAP_PIDFILE"/var/run/crywrap.pid";
503 config->inetd = 0;
504 config->anon = 0;
505 config->verify = 0;
506
507 argp_parse (&_crywrap_argp, argc, argv, 0, 0, config);
508
509 if (config->priority == NULL((void*)0))
510 gnutls_priority_init(&config->priority, "NORMAL", NULL((void*)0));
511
512 return config;
513}
514/** @} */
515
516/** @defgroup tls Lower-level TLS routines.
517 * @{
518 */
519
520/** Create a GNUTLS session.
521 * Initialises the cyphers and the session database for a new TLS
522 * session.
523 *
524 * @returns The newly created TLS session.
525 */
526static gnutls_session_t
527_crywrap_tls_session_create (const crywrap_config_t *config)
528{
529 gnutls_session_t session;
530 int ret;
531
532 gnutls_init (&session, GNUTLS_SERVER1);
533
534 if (config->anon) {
535 gnutls_credentials_set (session, GNUTLS_CRD_ANON, cred);
536 } else {
537 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cred);
538 }
539
540 ret = gnutls_priority_set(session, config->priority);
541 if (ret < 0)
542 {
543 cry_error ("Error setting priority %s: ", gnutls_strerror(ret));
544 exit (4);
545 }
546
547 if (config->verify==1)
548 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
549 else if (config->verify==2)
550 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
551
552 return session;
553}
554
555/** Generate initial DH and RSA params.
556 * Loads the pre-generated DH primes.
557 */
558static void
559_crywrap_tls_init (void)
560{
561
562 gnutls_dh_params_init (&dh_params);
563 gnutls_dh_params_import_pkcs3 (dh_params, &dh_file, GNUTLS_X509_FMT_PEM);
564
565 gnutls_certificate_set_dh_params (cred, dh_params);
566}
567/** @} */
568
569/** @defgroup networking Networking
570 * @{
571 */
572
573/** Bind to an address.
574 * This one binds to an address, handles errors and anything that may
575 * arise.
576 *
577 * @param ai is the address information.
578 * @param listen_port is the port to bind to, and listen on.
579 *
580 * @returns The bound filedescriptor, or -1 on error.
581 */
582static int
583_crywrap_bind (const struct addrinfo *ai, int listen_port)
584{
585 int ret;
586 const int one = 1;
587 int listenfd;
588 char sock_name[NI_MAXHOST1025];
589
590 listenfd = socket (ai->ai_family, SOCK_STREAMSOCK_STREAM, IPPROTO_IPIPPROTO_IP);
591 if (listenfd == -1)
592 {
593 cry_error ("socket: %s", strerrorrpl_strerror (errno(*__errno_location ())));
594 return -1;
595 }
596
597 memset (sock_name, 0, sizeof (sock_name));
598 getnameinfo ((struct sockaddr *)ai->ai_addr, ai->ai_addrlen, sock_name,
599 sizeof (sock_name), NULL((void*)0), 0, NI_NUMERICHOST1);
600
601 switch (ai->ai_family)
602 {
603 case AF_INET610:
604 ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_port = listen_port;
605 break;
606 case AF_INET2:
607 ((struct sockaddr_in *)(ai->ai_addr))->sin_port = listen_port;
608 break;
609 }
610
611 ret = setsockopt (listenfd, SOL_SOCKET1, SO_REUSEADDR2,
612 &one, sizeof (one));
613 if (ret != 0)
614 {
615 cry_error ("setsockopt: %s (%s)", strerrorrpl_strerror (errno(*__errno_location ())), sock_name);
616 return -1;
617 }
618
619 ret = bind (listenfd, ai->ai_addr, ai->ai_addrlen);
620 if (ret != 0)
621 {
622 cry_error ("bind to %s failed: %s", sock_name, strerrorrpl_strerror (errno(*__errno_location ())));
623 return -1;
624 }
625
626 if (listen (listenfd, _CRYWRAP_MAXCONN1024) != 0)
627 {
628 cry_error ("listen on %s failed: %s", sock_name, strerrorrpl_strerror (errno(*__errno_location ())));
629 return -1;
630 }
631
632 cry_log ("Socket bound to port %d on %s.", ntohs (listen_port), sock_name);
633
634 return listenfd;
635}
636
637/** Set up a listening socket.
638 * Sets up a listening socket on all the required addresses.
639 *
640 * @param config holds the CryWrap configuration, from where the
641 * listen address and port will be extracted.
642 *
643 * @returns The listening FD on success, -1 on error.
644 */
645static int
646_crywrap_listen (const crywrap_config_t *config)
647{
648 struct addrinfo *cur;
649 int ret;
650
651 cur = calloc (1, sizeof (struct addrinfo));
652 if (cur == NULL((void*)0))
653 return -1;
654
655 cur->ai_family = config->listen.addr->ss_family;
656
657 switch (cur->ai_family)
658 {
659 case AF_INET610:
660 cur->ai_addrlen = sizeof (struct sockaddr_in6);
661 break;
662 case AF_INET2:
663 cur->ai_addrlen = sizeof (struct sockaddr_in);
664 break;
665 }
666
667 cur->ai_addr = malloc (cur->ai_addrlen);
668 if (cur->ai_addr == NULL((void*)0))
669 return -1;
670
671 memcpy (cur->ai_addr, config->listen.addr, cur->ai_addrlen);
672
673 ret = _crywrap_bind (cur, htons (config->listen.port));
674 free (cur->ai_addr);
675 free (cur);
676
677 return ret;
678}
679
680/** Connect to a remote server.
681 * Estabilishes a connection to a remote server, and handles all
682 * errors and anything that may arise during this process.
683 *
684 * @param addr is the address of the remote server.
685 * @param port is the port to connect to.
686 *
687 * @returns the connected socket on success, otherwise it exits.
688 */
689static int
690_crywrap_remote_connect (const struct sockaddr_storage *addr, int port)
691{
692 struct addrinfo *cur;
693 int sock;
694
695 cur = calloc (1, sizeof (struct addrinfo));
696 if (cur == NULL((void*)0))
697 return -1;
698
699 cur->ai_family = addr->ss_family;
700
701 switch (cur->ai_family)
702 {
703 case AF_INET610:
704 cur->ai_addrlen = sizeof (struct sockaddr_in6);
705 break;
706 case AF_INET2:
707 cur->ai_addrlen = sizeof (struct sockaddr_in);
708 break;
709 }
710
711 cur->ai_addr = malloc (cur->ai_addrlen);
712 if (cur->ai_addr == NULL((void*)0))
713 return -1;
714
715 memcpy (cur->ai_addr, addr, cur->ai_addrlen);
716
717 switch (cur->ai_family)
718 {
719 case AF_INET610:
720 ((struct sockaddr_in6 *)(cur->ai_addr))->sin6_port = port;
721 break;
722 case AF_INET2:
723 ((struct sockaddr_in *)(cur->ai_addr))->sin_port = port;
724 break;
725 }
726
727 sock = socket (cur->ai_family, SOCK_STREAMSOCK_STREAM, IPPROTO_IPIPPROTO_IP);
728 if (sock < 0)
729 {
730 cry_error ("socket(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
731 exit (1);
732 }
733
734 if (connect (sock, cur->ai_addr, cur->ai_addrlen) < 0)
735 {
736 cry_error ("connect(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
737 exit (1);
738 }
739
740 free (cur->ai_addr);
741 free (cur);
742
743 return sock;
744}
745
746/** @} */
747
748/** @defgroup crywrap Main CryWrap code.
749 * @{
750 */
751
752/** Drop privileges.
753 * Drop privileges, if running as root.
754 * Upon failure, it will make CryWrap exit.
755 */
756static void
757_crywrap_privs_drop (const crywrap_config_t *config)
758{
759 struct passwd *pwd;
760
761 if (getuid () != 0)
762 {
763 cry_log ("%s", "Not running as root, not dropping privileges.");
764 return;
765 }
766
767 if ((pwd = getpwuid (config->uid)) == NULL((void*)0))
768 {
769 cry_error ("getpwuid(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
770 exit (1);
771 }
772
773 if (initgroups (pwd->pw_name, pwd->pw_gid) == -1)
774 {
775 cry_error ("initgroups(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
776 exit (1);
777 }
778
779 if (setgid (pwd->pw_gid) == -1)
780 {
781 cry_error ("setgid(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
782 exit (1);
783 }
784
785 if (setuid (config->uid))
786 {
787 cry_error ("setuid(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
788 exit (1);
789 }
790}
791
792/** Set up the PID file.
793 * Checks if a #pidfile already exists, and create one - containing the
794 * current PID - if one does not.
795 *
796 * @note Exits upon error.
797 */
798static void
799_crywrap_setup_pidfile (const crywrap_config_t *config)
800{
801 char mypid[128];
802 int pidfilefd;
803
804 if (!config->pidfile || !*(config->pidfile))
805 return;
806
807 if (!access (config->pidfile, F_OK0))
808 {
809 cry_error ("Pidfile (%s) already exists. Exiting.", config->pidfile);
810 exit (1);
811 }
812 if ((pidfilefd = open (config->pidfile,
813 O_WRONLY01 | O_CREAT0100 | O_TRUNC01000, 0644)) == -1)
814 {
815 cry_error ("Cannot create pidfile (%s): %s.\n", config->pidfile,
816 strerrorrpl_strerror (errno(*__errno_location ())));
817 exit (1);
818 }
819 fchown (pidfilefd, config->uid, (gid_t)-1);
820
821 main_pid = getpid ();
822 snprintf (mypid, sizeof (mypid), "%d\n", main_pid);
823 write (pidfilefd, mypid, strlen (mypid));
824 close (pidfilefd);
825 pidfile = config->pidfile;
826}
827
828
829/** Handles one client.
830 * This one connects to the remote server, and proxies every traffic
831 * between our client and the server.
832 *
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.
836 *
837 * @note Exits on error.
838 */
839static int
840_crywrap_do_one (const crywrap_config_t *config, int insock, int outsock)
841{
842 int sock, ret, tls_pending;
843 gnutls_session_t session;
844 char buffer[_CRYWRAP_MAXBUF64 * 1024 + 2];
845 fd_set fdset;
846 unsigned int status = 0;
847 struct sockaddr_storage faddr;
848 socklen_t socklen = sizeof (struct sockaddr_storage);
849 char peer_name[NI_MAXHOST1025];
850
851 /* Log the connection */
852 if (getpeername (insock, (struct sockaddr *)&faddr, &socklen) != 0)
853 cry_error ("getpeername(): %s", strerrorrpl_strerror (errno(*__errno_location ())));
854 else
855 {
856 getnameinfo ((struct sockaddr *)&faddr,
857 sizeof (struct sockaddr_storage), peer_name,
858 sizeof (peer_name), NULL((void*)0), 0, NI_NUMERICHOST1);
859 cry_log ("Accepted connection from %s on %d to %s/%d",
860 peer_name, insock, config->dest.host,
861 config->dest.port);
862 }
863
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);
869
870 do
871 {
872 ret = gnutls_handshake(session);
873 }
874 while (ret == GNUTLS_E_AGAIN-28 || ret == GNUTLS_E_INTERRUPTED-52);
875
876 if (ret < 0)
877 {
878 cry_error ("Handshake failed: %s", gnutls_strerror (ret));
879 gnutls_alert_send_appropriate(session, ret);
880 goto error;
881 }
882
883 /* Verify the client's certificate, if any. */
884 if (config->verify)
885 {
886 ret = gnutls_certificate_verify_peers2 (session, &status);
887 if (ret < 0)
888 cry_log ("Error getting certificate from client: %s",
889 gnutls_strerror (ret));
890
891 if (ret == 0 && status != 0)
892 {
893 if (status & GNUTLS_CERT_INVALID)
894 cry_log ("%s", "Client certificate not trusted or invalid");
895 }
896
897 if (config->verify > 0 && status != 0)
898 {
899 ret = -1;
900 gnutls_alert_send( session, GNUTLS_AL_FATAL, GNUTLS_A_INSUFFICIENT_SECURITY);
901 goto error;
902 }
903 }
904
905 /* Connect to the remote host */
906 sock = _crywrap_remote_connect (config->dest.addr,
907 htons (config->dest.port));
908
909 for (;;)
910 {
911 FD_ZERO (&fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fdset)->fds_bits)[0
]) : "memory"); } while (0)
;
912 FD_SET (insock, &fdset)(((&fdset)->fds_bits)[((insock) / (8 * (int) sizeof (__fd_mask
)))] |= ((__fd_mask) 1 << ((insock) % (8 * (int) sizeof
(__fd_mask)))))
;
913 FD_SET (sock, &fdset)(((&fdset)->fds_bits)[((sock) / (8 * (int) sizeof (__fd_mask
)))] |= ((__fd_mask) 1 << ((sock) % (8 * (int) sizeof (
__fd_mask)))))
;
914
915 memset (buffer, 0, _CRYWRAP_MAXBUF64 * 1024 + 1);
916
917 tls_pending = 0;
918
919 if (gnutls_record_check_pending(session) > 0)
920 tls_pending = 1;
921 else
922 {
923 select (sock + 1, &fdset, NULL((void*)0), NULL((void*)0), NULL((void*)0));
924 if (FD_ISSET (insock, &fdset)((((&fdset)->fds_bits)[((insock) / (8 * (int) sizeof (
__fd_mask)))] & ((__fd_mask) 1 << ((insock) % (8 * (
int) sizeof (__fd_mask))))) != 0)
)
925 tls_pending = 1;
926 }
927 /* TLS client */
928 if (tls_pending != 0)
929 {
930 ret = gnutls_record_recv (session, buffer, _CRYWRAP_MAXBUF64 * 1024);
931 if (ret == 0)
932 {
933 cry_log ("%s", "Peer has closed the GNUTLS connection");
934 break;
935 }
936 else if (ret < 0)
937 {
938 cry_log ("Received corrupted data: %s.",
939 gnutls_strerror (ret));
940 break;
941 }
942 else
943 send (sock, buffer, ret, 0);
944 }
945
946 /* Remote server */
947 if (FD_ISSET (sock, &fdset)((((&fdset)->fds_bits)[((sock) / (8 * (int) sizeof (__fd_mask
)))] & ((__fd_mask) 1 << ((sock) % (8 * (int) sizeof
(__fd_mask))))) != 0)
)
948 {
949 ret = recv (sock, buffer, _CRYWRAP_MAXBUF64 * 1024, 0);
950 if (ret == 0)
951 {
952 cry_log ("%s", "Server has closed the connection");
953 break;
954 }
955 else if (ret < 0)
956 {
957 cry_log ("Received corrupted data: %s.", strerrorrpl_strerror (errno(*__errno_location ())));
958 break;
959 }
960 else
961 {
962 int r, o = 0;
963
964 do
965 {
966 r = gnutls_record_send (session, &buffer[o], ret - o);
967 o += r;
968 } while (r > 0 && ret > o);
969
970 if (r < 0)
971 cry_log ("Received corrupt data: %s", gnutls_strerror (r));
972 }
973 }
974 }
975
976error:
977 gnutls_bye (session, GNUTLS_SHUT_WR);
978 gnutls_deinit (session);
979 close (insock);
980 close (outsock);
981
982 return (ret == 0) ? 0 : 1;
983}
984
985/** CryWrap entry point.
986 * This is the main entry point - controls the whole program and so
987 * on...
988 */
989int
990main (int argc, char **argv, char **envp)
991{
992 crywrap_config_t *config;
993 int server_socket;
994
995 openlog (__CRYWRAP__"crywrap", LOG_PID0x01, LOG_DAEMON(3<<3));
996
997 gnutls_global_set_audit_log_function (tls_audit_log_func);
998
999 if (gnutls_global_init () < 0)
1000 {
1001 cry_error ("%s", "Global TLS state initialisation failed.");
1002 exit (1);
1003 }
1004 if (gnutls_certificate_allocate_credentials (&cred) < 0)
1005 {
1006 cry_error ("%s", "Couldn't allocate credentials.");
1007 exit (1);
1008 }
1009
1010 stringprep_locale_charset ();
1011
1012 config = _crywrap_config_parse (argc, argv);
1013 set_program_name(__CRYWRAP__"crywrap");
1014
1015 _crywrap_tls_init ();
1016
1017 if (config->inetd)
1018 {
1019 _crywrap_privs_drop (config);
1020 exit (_crywrap_do_one (config, 0, 1));
1021 }
1022
1023 if (!config->debug)
1024 if (daemon (0, 0))
1025 {
1026 cry_error ("daemon: %s", strerrorrpl_strerror (errno(*__errno_location ())));
1027 exit (1);
1028 }
1029
1030 cry_log ("%s", "Crywrap starting...");
1031
1032 server_socket = _crywrap_listen (config);
1033 if (server_socket < 0)
1034 exit (1);
1035
1036 if (!config->debug) _crywrap_setup_pidfile (config);
1037 _crywrap_privs_drop (config);
1038
1039 signal (SIGTERM15, _crywrap_sighandler);
1040 signal (SIGQUIT3, _crywrap_sighandler);
1041 signal (SIGSEGV11, _crywrap_sighandler);
1042 signal (SIGPIPE13, SIG_IGN((__sighandler_t) 1));
1043 signal (SIGHUP1, SIG_IGN((__sighandler_t) 1));
1044 signal (SIGCHLD17, _crywrap_sigchld_handler);
1045
1046 cry_log ("%s", "Accepting connections");
1047
1048
1049 for (;;)
1050 {
1051 int csock;
1052 int child;
1053
1054 csock = accept (server_socket, NULL((void*)0), NULL((void*)0));
1055 if (csock < 0)
1056 continue;
1057
1058 child = fork ();
1059 switch (child)
1060 {
1061 case 0:
1062 exit (_crywrap_do_one (config, csock, csock));
1063 break;
1064 case -1:
1065 cry_error ("%s", "Forking error.");
1066 exit (1);
1067 break;
1068 }
1069 close(csock);
1070 }
1071
1072 return 0;
1073}
1074
1075static int system_log(const char* fmt, ...)
1076{
1077 va_list args;
1078
1079 va_start (args, fmt)__builtin_va_start(args, fmt);
1080 vsyslog(LOG_NOTICE5, fmt, args);
1081 va_end (args)__builtin_va_end(args);
1082
1083 return 0;
1084}
1085
1086static int system_log_error(const char* fmt, ...)
1087{
1088 va_list args;
1089
1090 va_start (args, fmt)__builtin_va_start(args, fmt);
1091 vsyslog(LOG_ERR3, fmt, args);
1092 va_end (args)__builtin_va_end(args);
1093
1094 return 0;
1095}
1096
1097static int debug_log(const char* fmt, ...)
1098{
1099 va_list args;
1100
1101 va_start (args, fmt)__builtin_va_start(args, fmt);
1102 vprintfrpl_vprintf(fmt, args);
1103 puts("");
1104 va_end (args)__builtin_va_end(args);
1105
1106 return 0;
1107}
1108
1109/** @} */
1110