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
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.
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.
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/>.
29 #include <arpa/inet.h>
32 #include <gnutls/gnutls.h>
33 #include <gnutls/x509.h>
37 #include <netinet/in.h>
43 #include <stringprep.h>
44 #include <sys/select.h>
45 #include <sys/socket.h>
46 #include <sys/types.h>
55 static int system_log(const char *fmt, ...)
57 __attribute__ ((format(printf, 1, 2)))
61 static int system_log_error(const char *fmt, ...)
63 __attribute__ ((format(printf, 1, 2)))
67 static int debug_log(const char *fmt, ...)
69 __attribute__ ((format(printf, 1, 2)))
73 typedef int (*cry_log_func) (const char *format, ...)
75 __attribute__ ((format(printf, 1, 2)))
79 static cry_log_func cry_log = system_log;
80 static cry_log_func cry_error = system_log_error;
82 static void tls_audit_log_func(gnutls_session_t session, const char *str)
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);
89 if (session != NULL) {
90 gnutls_transport_get_ptr2(session, &r, &s);
92 /* Log the connection */
94 ((int) (long) r, (struct sockaddr *) &faddr,
96 cry_error("getpeername(): %s", strerror(errno));
98 cry_log("Peer %s: %s", peer_name, str);
104 /** @defgroup globals Global variables.
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.
112 static pid_t main_pid = -1; /**< Pid of the main process */
113 static const char *pidfile = _CRYWRAP_PIDFILE; /**< File to log our PID
116 /** GNUTLS server credentials.
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 */
123 /** Bugreport address.
124 * Used by the argp suite.
126 const char *argp_program_bug_address = "<bugs-gnutls@gnu.org>";
128 * Used by the argp suite.
130 const char *argp_program_version = __CRYWRAP__ " " _CRYWRAP_VERSION;
132 /* The certificate and key files */
133 static char *pem_cert = NULL;
134 static char *pem_key = NULL;
137 /** The options CryWrap takes.
138 * Used by the argp suite.
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)",
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}
165 static error_t _crywrap_config_parse_opt(int key, char *arg,
166 struct argp_state *state);
167 /** The main argp structure for Crywrap.
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 "
179 /** @defgroup signal Signal handlers & co.
185 static void _crywrap_sigchld_handler(int sig)
190 while ((child = waitpid(-1, &status, WNOHANG)) > (pid_t) 0)
191 signal(sig, _crywrap_sigchld_handler);
194 /* Helper functions to load a certificate and key
197 static gnutls_datum_t load_file(const char *file)
199 gnutls_datum_t loaded_file = { NULL, 0 };
201 gnutls_load_file(file, &loaded_file);
206 /** Generic signal handler.
207 * This one removes the #pidfile, if necessary.
209 static void _crywrap_sighandler(int sig)
211 if (getpid() == main_pid) {
212 cry_log("Exiting on signal %d", sig);
213 if (pidfile && *pidfile)
222 /** @defgroup parsing Option parsing
226 /** Service resolver.
227 * Resolves a service - be it a name or a number.
229 * @param serv is the port to resolve.
231 * @returns The purt number, or -1 on error.
233 static int _crywrap_port_get(const char *serv)
241 se = getservbyname(serv, "tcp");
245 port = ntohs(se->s_port);
250 /** Address resolver.
251 * Resolves an address - be it numeric or a hostname, IPv4 or IPv6.
253 * @param hostname is the host to resolve.
254 * @param addr is the structure to put the result into.
256 * @returns Zero on success, -1 on error.
259 _crywrap_addr_get(const char *hostname, struct sockaddr_storage **addr)
261 struct addrinfo *res;
262 struct addrinfo hints;
266 if (idna_to_ascii_lz(hostname, &lz, 0) != IDNA_SUCCESS)
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));
279 if (getaddrinfo(lz, NULL, &hints, &res) != 0) {
286 switch (res->ai_addr->sa_family) {
288 len = sizeof(struct sockaddr_in);
291 len = sizeof(struct sockaddr_in6);
298 if (len < (ssize_t) res->ai_addrlen) {
303 memcpy(*addr, res->ai_addr, res->ai_addrlen);
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.
313 * @param ip is the HOST/IP pair to parse.
314 * @param port is a pointer to an integer where the port number should
316 * @param addr is the destination of the resolved and parsed IP.
318 * @returns Zero on success, -1 on error.
321 _crywrap_parse_ip(const char *ip, in_port_t * port,
322 struct sockaddr_storage **addr, char **host)
328 tmp = strchr(ip, '/');
334 s_ip = strdup("0.0.0.0");
335 *port = (in_port_t) _crywrap_port_get(&ip[1]);
337 *port = (in_port_t) _crywrap_port_get(&tmp[1]);
338 s_ip = strndup(ip, tmp - ip);
345 *host = strdup(s_ip);
347 ret = _crywrap_addr_get(s_ip, addr);
352 /** Argument parsing routine.
353 * Used by the argp suite.
356 _crywrap_config_parse_opt(int key, char *arg, struct argp_state *state)
358 crywrap_config_t *cfg = (crywrap_config_t *) state->input;
365 cry_error = debug_log;
368 if (_crywrap_parse_ip
369 (arg, &cfg->dest.port, &cfg->dest.addr,
370 &cfg->dest.host) < 0)
372 "Could not resolve address: `%s'", arg);
375 if (_crywrap_parse_ip(arg, &cfg->listen.port,
376 &cfg->listen.addr, NULL) < 0)
378 "Could not resolve address: `%s'", arg);
381 cfg->uid = atoi(arg);
385 cfg->pidfile = strdup(arg);
391 dh_file = load_file(arg);
392 if (dh_file.data == NULL)
394 "error loading Diffie Hellman parameters file: %s.",
402 gnutls_priority_init(&cfg->priority, arg,
406 "error in priority string at: %s.",
412 pem_cert = strdup(arg);
416 pem_key = strdup(arg);
427 gnutls_priority_init(&cfg->priority,
428 "NORMAL:+ANON-ECDH:+ANON-DH",
432 "error in priority string at: %s.",
439 cfg->verify = (arg) ? atoi(arg) : 1;
442 ret = gnutls_certificate_set_x509_trust_file(cred, arg,
443 GNUTLS_X509_FMT_PEM);
446 "error reading X.509 CA file: %s.",
447 gnutls_strerror(ret));
452 if (!cfg->listen.addr || !cfg->dest.addr)
455 "a listening and a destination address must be set!");
456 } else if (!cfg->dest.addr)
458 "a destination address must be set!");
461 if (pem_cert == NULL || pem_key == NULL)
463 gnutls_certificate_set_x509_key_file(cred,
466 GNUTLS_X509_FMT_PEM);
469 gnutls_certificate_set_x509_key_file(cred,
472 GNUTLS_X509_FMT_PEM);
476 "Error reading X.509 key or certificate file: %s",
477 gnutls_strerror(ret));
480 return ARGP_ERR_UNKNOWN;
486 /** Configuration parsing.
487 * Sets up the default values, and parses the command-line options
490 * @note Does not return if an error occurred.
492 static crywrap_config_t *_crywrap_config_parse(int argc, char **argv)
494 crywrap_config_t *config =
495 (crywrap_config_t *) malloc(sizeof(crywrap_config_t));
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;
511 argp_parse(&_crywrap_argp, argc, argv, 0, 0, config);
513 if (config->priority == NULL)
514 gnutls_priority_init(&config->priority, "NORMAL", NULL);
521 /** @defgroup tls Lower-level TLS routines.
525 /** Create a GNUTLS session.
526 * Initialises the cyphers and the session database for a new TLS
529 * @returns The newly created TLS session.
531 static gnutls_session_t
532 _crywrap_tls_session_create(const crywrap_config_t * config)
534 gnutls_session_t session;
537 gnutls_init(&session, GNUTLS_SERVER);
540 gnutls_credentials_set(session, GNUTLS_CRD_ANON, cred);
542 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
546 ret = gnutls_priority_set(session, config->priority);
548 cry_error("Error setting priority %s: ",
549 gnutls_strerror(ret));
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);
563 /** Generate initial DH and RSA params.
564 * Loads the pre-generated DH primes.
566 static void _crywrap_tls_init(void)
569 gnutls_dh_params_init(&dh_params);
570 gnutls_dh_params_import_pkcs3(dh_params, &dh_file,
571 GNUTLS_X509_FMT_PEM);
573 gnutls_certificate_set_dh_params(cred, dh_params);
578 /** @defgroup networking Networking
582 /** Bind to an address.
583 * This one binds to an address, handles errors and anything that may
586 * @param ai is the address information.
587 * @param listen_port is the port to bind to, and listen on.
589 * @returns The bound filedescriptor, or -1 on error.
591 static int _crywrap_bind(const struct addrinfo *ai, int listen_port)
596 char sock_name[NI_MAXHOST];
598 listenfd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_IP);
599 if (listenfd == -1) {
600 cry_error("socket: %s", strerror(errno));
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);
608 switch (ai->ai_family) {
610 ((struct sockaddr_in6 *) (ai->ai_addr))->sin6_port =
614 ((struct sockaddr_in *) (ai->ai_addr))->sin_port =
619 ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
622 cry_error("setsockopt: %s (%s)", strerror(errno),
627 ret = bind(listenfd, ai->ai_addr, ai->ai_addrlen);
629 cry_error("bind to %s failed: %s", sock_name,
634 if (listen(listenfd, _CRYWRAP_MAXCONN) != 0) {
635 cry_error("listen on %s failed: %s", sock_name,
640 cry_log("Socket bound to port %d on %s.", ntohs(listen_port),
646 /** Set up a listening socket.
647 * Sets up a listening socket on all the required addresses.
649 * @param config holds the CryWrap configuration, from where the
650 * listen address and port will be extracted.
652 * @returns The listening FD on success, -1 on error.
654 static int _crywrap_listen(const crywrap_config_t * config)
656 struct addrinfo *cur;
659 cur = calloc(1, sizeof(struct addrinfo));
663 cur->ai_family = config->listen.addr->ss_family;
665 switch (cur->ai_family) {
667 cur->ai_addrlen = sizeof(struct sockaddr_in6);
670 cur->ai_addrlen = sizeof(struct sockaddr_in);
677 cur->ai_addr = malloc(cur->ai_addrlen);
678 if (cur->ai_addr == NULL)
681 memcpy(cur->ai_addr, config->listen.addr, cur->ai_addrlen);
683 ret = _crywrap_bind(cur, htons(config->listen.port));
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.
696 * @param addr is the address of the remote server.
697 * @param port is the port to connect to.
699 * @returns the connected socket on success, otherwise it exits.
702 _crywrap_remote_connect(const struct sockaddr_storage *addr, int port)
704 struct addrinfo *cur;
707 cur = calloc(1, sizeof(struct addrinfo));
711 cur->ai_family = addr->ss_family;
713 switch (cur->ai_family) {
715 cur->ai_addrlen = sizeof(struct sockaddr_in6);
718 cur->ai_addrlen = sizeof(struct sockaddr_in);
725 cur->ai_addr = malloc(cur->ai_addrlen);
726 if (cur->ai_addr == NULL)
729 memcpy(cur->ai_addr, addr, cur->ai_addrlen);
731 switch (cur->ai_family) {
733 ((struct sockaddr_in6 *) (cur->ai_addr))->sin6_port = port;
736 ((struct sockaddr_in *) (cur->ai_addr))->sin_port = port;
740 sock = socket(cur->ai_family, SOCK_STREAM, IPPROTO_IP);
742 cry_error("socket(): %s", strerror(errno));
746 if (connect(sock, cur->ai_addr, cur->ai_addrlen) < 0) {
747 cry_error("connect(): %s", strerror(errno));
761 /** @defgroup crywrap Main CryWrap code.
766 * Drop privileges, if running as root.
767 * Upon failure, it will make CryWrap exit.
769 static void _crywrap_privs_drop(const crywrap_config_t * config)
775 "Not running as root, not dropping privileges.");
779 if ((pwd = getpwuid(config->uid)) == NULL) {
780 cry_error("getpwuid(): %s", strerror(errno));
784 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
785 cry_error("initgroups(): %s", strerror(errno));
789 if (setgid(pwd->pw_gid) == -1) {
790 cry_error("setgid(): %s", strerror(errno));
794 if (setuid(config->uid)) {
795 cry_error("setuid(): %s", strerror(errno));
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.
804 * @note Exits upon error.
806 static void _crywrap_setup_pidfile(const crywrap_config_t * config)
811 if (!config->pidfile || !*(config->pidfile))
814 if (!access(config->pidfile, F_OK)) {
815 cry_error("Pidfile (%s) already exists. Exiting.",
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));
825 fchown(pidfilefd, config->uid, (gid_t) - 1);
828 snprintf(mypid, sizeof(mypid), "%d\n", main_pid);
829 write(pidfilefd, mypid, strlen(mypid));
831 pidfile = config->pidfile;
835 /** Handles one client.
836 * This one connects to the remote server, and proxies every traffic
837 * between our client and the server.
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.
843 * @note Exits on error.
846 _crywrap_do_one(const crywrap_config_t * config, int insock, int outsock)
848 int sock, ret, tls_pending;
849 gnutls_session_t session;
850 char buffer[_CRYWRAP_MAXBUF + 2];
852 unsigned int status = 0;
853 struct sockaddr_storage faddr;
854 socklen_t socklen = sizeof(struct sockaddr_storage);
855 char peer_name[NI_MAXHOST];
857 /* Log the connection */
858 if (getpeername(insock, (struct sockaddr *) &faddr, &socklen) != 0)
859 cry_error("getpeername(): %s", strerror(errno));
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,
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);
876 ret = gnutls_handshake(session);
878 while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
881 cry_error("Handshake failed: %s", gnutls_strerror(ret));
882 gnutls_alert_send_appropriate(session, ret);
886 /* Verify the client's certificate, if any. */
887 if (config->verify) {
888 ret = gnutls_certificate_verify_peers2(session, &status);
891 ("Error getting certificate from client: %s",
892 gnutls_strerror(ret));
894 if (ret == 0 && status != 0) {
895 if (status & GNUTLS_CERT_INVALID)
897 "Client certificate not trusted or invalid");
900 if (config->verify > 0 && status != 0) {
902 gnutls_alert_send(session, GNUTLS_AL_FATAL,
903 GNUTLS_A_INSUFFICIENT_SECURITY);
908 /* Connect to the remote host */
909 sock = _crywrap_remote_connect(config->dest.addr,
910 htons(config->dest.port));
914 FD_SET(insock, &fdset);
915 FD_SET(sock, &fdset);
917 memset(buffer, 0, _CRYWRAP_MAXBUF + 1);
921 if (gnutls_record_check_pending(session) > 0)
924 select(sock + 1, &fdset, NULL, NULL, NULL);
925 if (FD_ISSET(insock, &fdset))
929 if (tls_pending != 0) {
931 gnutls_record_recv(session, buffer,
935 "Peer has closed the GNUTLS connection");
937 } else if (ret < 0) {
938 cry_log("Received corrupted data: %s.",
939 gnutls_strerror(ret));
942 send(sock, buffer, ret, 0);
946 if (FD_ISSET(sock, &fdset)) {
947 ret = recv(sock, buffer, _CRYWRAP_MAXBUF, 0);
950 "Server has closed the connection");
952 } else if (ret < 0) {
953 cry_log("Received corrupted data: %s.",
960 r = gnutls_record_send(session,
964 } while (r > 0 && ret > o);
968 ("Received corrupt data: %s",
975 gnutls_bye(session, GNUTLS_SHUT_WR);
976 gnutls_deinit(session);
980 return (ret == 0) ? 0 : 1;
983 /** CryWrap entry point.
984 * This is the main entry point - controls the whole program and so
987 int main(int argc, char **argv, char **envp)
989 crywrap_config_t *config;
992 openlog(__CRYWRAP__, LOG_PID, LOG_DAEMON);
994 gnutls_global_set_audit_log_function(tls_audit_log_func);
996 if (gnutls_global_init() < 0) {
997 cry_error("%s", "Global TLS state initialisation failed.");
1000 if (gnutls_certificate_allocate_credentials(&cred) < 0) {
1001 cry_error("%s", "Couldn't allocate credentials.");
1005 stringprep_locale_charset();
1007 config = _crywrap_config_parse(argc, argv);
1009 _crywrap_tls_init();
1011 if (config->inetd) {
1012 _crywrap_privs_drop(config);
1013 exit(_crywrap_do_one(config, 0, 1));
1018 cry_error("daemon: %s", strerror(errno));
1022 cry_log("%s", "Crywrap starting...");
1024 server_socket = _crywrap_listen(config);
1025 if (server_socket < 0)
1029 _crywrap_setup_pidfile(config);
1030 _crywrap_privs_drop(config);
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);
1039 cry_log("%s", "Accepting connections");
1046 csock = accept(server_socket, NULL, NULL);
1053 exit(_crywrap_do_one(config, csock, csock));
1056 cry_error("%s", "Forking error.");
1066 static int system_log(const char *fmt, ...)
1070 va_start(args, fmt);
1071 vsyslog(LOG_NOTICE, fmt, args);
1077 static int system_log_error(const char *fmt, ...)
1081 va_start(args, fmt);
1082 vsyslog(LOG_ERR, fmt, args);
1088 static int debug_log(const char *fmt, ...)
1092 va_start(args, fmt);