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