summaryrefslogtreecommitdiff
path: root/src/crywrap/crywrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crywrap/crywrap.c')
-rw-r--r--src/crywrap/crywrap.c1101
1 files changed, 0 insertions, 1101 deletions
diff --git a/src/crywrap/crywrap.c b/src/crywrap/crywrap.c
deleted file mode 100644
index 1277609be4..0000000000
--- a/src/crywrap/crywrap.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/* -*- mode: c; c-file-style: "gnu" -*-
- * crywrap.c -- CryWrap
- * Copyright (C) 2003, 2004 Gergely Nagy <algernon@bonehunter.rulez.org>
- * Copyright (C) 2011 Nikos Mavrogiannopoulos
- *
- * This file is part of CryWrap.
- *
- * CryWrap is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * CryWrap is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** @file crywrap.c
- * CryWrap itself.
- */
-
-#include <config.h>
-
-#include <argp.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#include <grp.h>
-#include <idna.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stringprep.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <syslog.h>
-#include <stdarg.h>
-#include <unistd.h>
-
-#include "crywrap.h"
-#include "primes.h"
-
-static int system_log(const char *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format(printf, 1, 2)))
-#endif
- ;
-
-static int system_log_error(const char *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format(printf, 1, 2)))
-#endif
- ;
-
-static int debug_log(const char *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format(printf, 1, 2)))
-#endif
- ;
-
-typedef int (*cry_log_func) (const char *format, ...)
-#ifdef __GNUC__
- __attribute__ ((format(printf, 1, 2)))
-#endif
- ;
-
-static cry_log_func cry_log = system_log;
-static cry_log_func cry_error = system_log_error;
-
-static void tls_audit_log_func(gnutls_session_t session, const char *str)
-{
- char peer_name[NI_MAXHOST] = "Unknown";
- gnutls_transport_ptr_t r, s;
- struct sockaddr_storage faddr;
- socklen_t socklen = sizeof(struct sockaddr_storage);
-
- if (session != NULL) {
- gnutls_transport_get_ptr2(session, &r, &s);
-
- /* Log the connection */
- if (getpeername
- ((int) (long) r, (struct sockaddr *) &faddr,
- &socklen) != 0)
- cry_error("getpeername(): %s", strerror(errno));
-
- cry_log("Peer %s: %s", peer_name, str);
- } else
- cry_log("%s", str);
-
-}
-
-/** @defgroup globals Global variables.
- * @{
- */
-
-/** An array of pids.
- * This array holds the PIDs of all of our children, indexed by the
- * socket the associated client connected to us.
- */
-static pid_t main_pid = -1; /**< Pid of the main process */
-static const char *pidfile = _CRYWRAP_PIDFILE; /**< File to log our PID
- into. */
-
-/** GNUTLS server credentials.
- */
-static gnutls_certificate_server_credentials cred;
-static gnutls_dh_params dh_params; /**< GNUTLS DH parameters. */
-static gnutls_datum dh_file = { (void *) _crywrap_prime_dh_1024, sizeof(_crywrap_prime_dh_1024) };
- /**< Diffie Hellman parameters */
-
-/** Bugreport address.
- * Used by the argp suite.
- */
-const char *argp_program_bug_address = "<bugs-gnutls@gnu.org>";
-/** Porgram version.
- * Used by the argp suite.
- */
-const char *argp_program_version = __CRYWRAP__ " " _CRYWRAP_VERSION;
-
-/* The certificate and key files */
-static char *pem_cert = NULL;
-static char *pem_key = NULL;
-
-
-/** The options CryWrap takes.
- * Used by the argp suite.
- */
-static const struct argp_option _crywrap_options[] = {
- {NULL, 0, NULL, 0, "Mandatory options:", 1},
- {"destination", 'd', "IP/PORT", 0, "IP and port to connect to", 1},
- {"listen", 'l', "IP/PORT", 0, "IP and port to listen on", 1},
- {NULL, 0, NULL, 0, "TLS certificates:", 2},
- {"key", 'k', "FILE", 0, "Server key", 2},
- {"cert", 'c', "FILE", 0, "Server certificate", 2},
- {"ca", 'z', "FILE", 0, "CA certificate", 2},
- {"anon", 'a', NULL, 0,
- "Enable anonymous authentication (no certificates)", 2},
- {"verify", 'v', "LEVEL", OPTION_ARG_OPTIONAL,
- "Verify clients certificate (1: verify if exists, 2: require)",
- 2},
- {NULL, 0, NULL, 0, "Other options:", 3},
- {"dhparams", 'r', "FILE", 0,
- "Diffie Hellman (PKCS #3) parameters file", 3},
- {"user", 'u', "UID", 0, "User ID to run as", 3},
- {"pidfile", 'P', "PATH", 0, "File to log the PID into", 3},
- {"priority", 'p', "STRING", 0,
- "GnuTLS ciphersuite priority string", 3},
- {"inetd", 'i', NULL, 0, "Enable inetd mode", 3},
- {"debug", 'D', NULL, 0, "Run the server into foreground", 3},
- {0, 0, 0, 0, NULL, 0}
-};
-
-static error_t _crywrap_config_parse_opt(int key, char *arg,
- struct argp_state *state);
-/** The main argp structure for Crywrap.
- */
-static const struct argp _crywrap_argp =
- { _crywrap_options, _crywrap_config_parse_opt, 0,
- __CRYWRAP__ " -- Security for the masses\v"
- "The --destination option is mandatory, as is --listen if --inetd "
- "was not used.",
- NULL, NULL, NULL
-};
-
-/** @} */
-
-/** @defgroup signal Signal handlers & co.
- * @{
- */
-
-/** SIGCHLD handler
- */
-static void _crywrap_sigchld_handler(int sig)
-{
- pid_t child;
- int status;
-
- while ((child = waitpid(-1, &status, WNOHANG)) > (pid_t) 0)
- signal(sig, _crywrap_sigchld_handler);
-}
-
-/* Helper functions to load a certificate and key
- * files into memory.
- */
-static gnutls_datum_t load_file(const char *file)
-{
- gnutls_datum_t loaded_file = { NULL, 0 };
-
- gnutls_load_file(file, &loaded_file);
-
- return loaded_file;
-}
-
-/** Generic signal handler.
- * This one removes the #pidfile, if necessary.
- */
-static void _crywrap_sighandler(int sig)
-{
- if (getpid() == main_pid) {
- cry_log("Exiting on signal %d", sig);
- if (pidfile && *pidfile)
- unlink(pidfile);
- closelog();
- exit(0);
- }
-}
-
-/** @} */
-
-/** @defgroup parsing Option parsing
- * @{
- */
-
-/** Service resolver.
- * Resolves a service - be it a name or a number.
- *
- * @param serv is the port to resolve.
- *
- * @returns The purt number, or -1 on error.
- */
-static int _crywrap_port_get(const char *serv)
-{
- int port;
- struct servent *se;
-
- if (!serv)
- return -1;
-
- se = getservbyname(serv, "tcp");
- if (!se)
- port = atoi(serv);
- else
- port = ntohs(se->s_port);
-
- return port;
-}
-
-/** Address resolver.
- * Resolves an address - be it numeric or a hostname, IPv4 or IPv6.
- *
- * @param hostname is the host to resolve.
- * @param addr is the structure to put the result into.
- *
- * @returns Zero on success, -1 on error.
- */
-static int
-_crywrap_addr_get(const char *hostname, struct sockaddr_storage **addr)
-{
- struct addrinfo *res;
- struct addrinfo hints;
- ssize_t len;
- char *lz = NULL;
-
- if (idna_to_ascii_lz(hostname, &lz, 0) != IDNA_SUCCESS)
- return -1;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_IP;
- *addr = calloc(1, sizeof(struct sockaddr_storage));
- if (*addr == NULL) {
- free(lz);
- return -1;
- }
-
- if (getaddrinfo(lz, NULL, &hints, &res) != 0) {
- free(lz);
- return -1;
- }
-
- free(lz);
-
- switch (res->ai_addr->sa_family) {
- case AF_INET:
- len = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- len = sizeof(struct sockaddr_in6);
- break;
- default:
- freeaddrinfo(res);
- return -1;
- }
-
- if (len < (ssize_t) res->ai_addrlen) {
- freeaddrinfo(res);
- return -1;
- }
-
- memcpy(*addr, res->ai_addr, res->ai_addrlen);
- freeaddrinfo(res);
-
- return 0;
-}
-
-/** Parse a HOST/IP pair.
- * Splits up a given HOST/IP pair, and converts them into structures
- * directly usable by libc routines.
- *
- * @param ip is the HOST/IP pair to parse.
- * @param port is a pointer to an integer where the port number should
- * go.
- * @param addr is the destination of the resolved and parsed IP.
- *
- * @returns Zero on success, -1 on error.
- */
-static int
-_crywrap_parse_ip(const char *ip, in_port_t * port,
- struct sockaddr_storage **addr, char **host)
-{
- char *s_ip = NULL;
- char *tmp;
- int ret;
-
- tmp = strchr(ip, '/');
-
- if (!tmp)
- return -1;
-
- if (tmp == ip) {
- s_ip = strdup("0.0.0.0");
- *port = (in_port_t) _crywrap_port_get(&ip[1]);
- } else {
- *port = (in_port_t) _crywrap_port_get(&tmp[1]);
- s_ip = strndup(ip, tmp - ip);
- }
-
- if (!*port)
- return -1;
-
- if (host)
- *host = strdup(s_ip);
-
- ret = _crywrap_addr_get(s_ip, addr);
- free(s_ip);
- return ret;
-}
-
-/** Argument parsing routine.
- * Used by the argp suite.
- */
-static error_t
-_crywrap_config_parse_opt(int key, char *arg, struct argp_state *state)
-{
- crywrap_config_t *cfg = (crywrap_config_t *) state->input;
- int ret;
-
- switch (key) {
- case 'D':
- cfg->debug = 1;
- cry_log = debug_log;
- cry_error = debug_log;
- break;
- case 'd':
- if (_crywrap_parse_ip
- (arg, &cfg->dest.port, &cfg->dest.addr,
- &cfg->dest.host) < 0)
- argp_error(state,
- "Could not resolve address: `%s'", arg);
- break;
- case 'l':
- if (_crywrap_parse_ip(arg, &cfg->listen.port,
- &cfg->listen.addr, NULL) < 0)
- argp_error(state,
- "Could not resolve address: `%s'", arg);
- break;
- case 'u':
- cfg->uid = atoi(arg);
- break;
- case 'P':
- if (arg && *arg)
- cfg->pidfile = strdup(arg);
- else
- cfg->pidfile = NULL;
- break;
- case 'r':
- if (arg && *arg) {
- dh_file = load_file(arg);
- if (dh_file.data == NULL)
- argp_error(state,
- "error loading Diffie Hellman parameters file: %s.",
- arg);
- }
- break;
- case 'p':
- if (arg && *arg) {
- const char *pos;
- ret =
- gnutls_priority_init(&cfg->priority, arg,
- &pos);
- if (ret < 0)
- argp_error(state,
- "error in priority string at: %s.",
- pos);
- }
- break;
- case 'c':
- if (arg && *arg)
- pem_cert = strdup(arg);
- break;
- case 'k':
- if (arg && *arg)
- pem_key = strdup(arg);
- break;
-
- break;
- case 'i':
- cfg->inetd = 1;
- break;
- case 'a':
- {
- const char *pos;
- ret =
- gnutls_priority_init(&cfg->priority,
- "NORMAL:+ANON-ECDH:+ANON-DH",
- &pos);
- if (ret < 0)
- argp_error(state,
- "error in priority string at: %s.",
- pos);
- }
- cfg->verify = 0;
- cfg->anon = 1;
- break;
- case 'v':
- cfg->verify = (arg) ? atoi(arg) : 1;
- break;
- case 'z':
- ret = gnutls_certificate_set_x509_trust_file(cred, arg,
- GNUTLS_X509_FMT_PEM);
- if (ret < 0)
- argp_error(state,
- "error reading X.509 CA file: %s.",
- gnutls_strerror(ret));
- break;
-
- case ARGP_KEY_END:
- if (!cfg->inetd) {
- if (!cfg->listen.addr || !cfg->dest.addr)
- argp_error
- (state,
- "a listening and a destination address must be set!");
- } else if (!cfg->dest.addr)
- argp_error(state,
- "a destination address must be set!");
- if (cfg->anon)
- break;
- if (pem_cert == NULL || pem_key == NULL)
- ret =
- gnutls_certificate_set_x509_key_file(cred,
- _CRYWRAP_PEMFILE,
- _CRYWRAP_PEMFILE,
- GNUTLS_X509_FMT_PEM);
- else
- ret =
- gnutls_certificate_set_x509_key_file(cred,
- pem_cert,
- pem_key,
- GNUTLS_X509_FMT_PEM);
-
- if (ret < 0)
- argp_error(state,
- "Error reading X.509 key or certificate file: %s",
- gnutls_strerror(ret));
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
-
- return 0;
-}
-
-/** Configuration parsing.
- * Sets up the default values, and parses the command-line options
- * using argp.
- *
- * @note Does not return if an error occurred.
- */
-static crywrap_config_t *_crywrap_config_parse(int argc, char **argv)
-{
- crywrap_config_t *config =
- (crywrap_config_t *) malloc(sizeof(crywrap_config_t));
-
- if (config == NULL)
- return NULL;
-
- config->listen.port = 0;
- config->listen.addr = NULL;
- config->dest.port = 0;
- config->dest.addr = NULL;
- config->priority = NULL;
- config->uid = _CRYWRAP_UID;
- config->pidfile = _CRYWRAP_PIDFILE;
- config->inetd = 0;
- config->anon = 0;
- config->verify = 0;
-
- argp_parse(&_crywrap_argp, argc, argv, 0, 0, config);
-
- if (config->priority == NULL)
- gnutls_priority_init(&config->priority, "NORMAL", NULL);
-
- return config;
-}
-
-/** @} */
-
-/** @defgroup tls Lower-level TLS routines.
- * @{
- */
-
-/** Create a GNUTLS session.
- * Initialises the cyphers and the session database for a new TLS
- * session.
- *
- * @returns The newly created TLS session.
- */
-static gnutls_session_t
-_crywrap_tls_session_create(const crywrap_config_t * config)
-{
- gnutls_session_t session;
- int ret;
-
- gnutls_init(&session, GNUTLS_SERVER);
-
- if (config->anon) {
- gnutls_credentials_set(session, GNUTLS_CRD_ANON, cred);
- } else {
- gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
- cred);
- }
-
- ret = gnutls_priority_set(session, config->priority);
- if (ret < 0) {
- cry_error("Error setting priority %s: ",
- gnutls_strerror(ret));
- exit(4);
- }
-
- if (config->verify == 1)
- gnutls_certificate_server_set_request(session,
- GNUTLS_CERT_REQUEST);
- else if (config->verify == 2)
- gnutls_certificate_server_set_request(session,
- GNUTLS_CERT_REQUIRE);
-
- return session;
-}
-
-/** Generate initial DH and RSA params.
- * Loads the pre-generated DH primes.
- */
-static void _crywrap_tls_init(void)
-{
-#ifdef ENABLE_DHE
- gnutls_dh_params_init(&dh_params);
- gnutls_dh_params_import_pkcs3(dh_params, &dh_file,
- GNUTLS_X509_FMT_PEM);
-
- gnutls_certificate_set_dh_params(cred, dh_params);
-#endif
-}
-
-/** @} */
-
-/** @defgroup networking Networking
- * @{
- */
-
-/** Bind to an address.
- * This one binds to an address, handles errors and anything that may
- * arise.
- *
- * @param ai is the address information.
- * @param listen_port is the port to bind to, and listen on.
- *
- * @returns The bound filedescriptor, or -1 on error.
- */
-static int _crywrap_bind(const struct addrinfo *ai, int listen_port)
-{
- int ret;
- const int one = 1;
- int listenfd;
- char sock_name[NI_MAXHOST];
-
- listenfd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_IP);
- if (listenfd == -1) {
- cry_error("socket: %s", strerror(errno));
- return -1;
- }
-
- memset(sock_name, 0, sizeof(sock_name));
- getnameinfo((struct sockaddr *) ai->ai_addr, ai->ai_addrlen,
- sock_name, sizeof(sock_name), NULL, 0, NI_NUMERICHOST);
-
- switch (ai->ai_family) {
- case AF_INET6:
- ((struct sockaddr_in6 *) (ai->ai_addr))->sin6_port =
- listen_port;
- break;
- case AF_INET:
- ((struct sockaddr_in *) (ai->ai_addr))->sin_port =
- listen_port;
- break;
- }
-
- ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
- &one, sizeof(one));
- if (ret != 0) {
- cry_error("setsockopt: %s (%s)", strerror(errno),
- sock_name);
- return -1;
- }
-
- ret = bind(listenfd, ai->ai_addr, ai->ai_addrlen);
- if (ret != 0) {
- cry_error("bind to %s failed: %s", sock_name,
- strerror(errno));
- return -1;
- }
-
- if (listen(listenfd, _CRYWRAP_MAXCONN) != 0) {
- cry_error("listen on %s failed: %s", sock_name,
- strerror(errno));
- return -1;
- }
-
- cry_log("Socket bound to port %d on %s.", ntohs(listen_port),
- sock_name);
-
- return listenfd;
-}
-
-/** Set up a listening socket.
- * Sets up a listening socket on all the required addresses.
- *
- * @param config holds the CryWrap configuration, from where the
- * listen address and port will be extracted.
- *
- * @returns The listening FD on success, -1 on error.
- */
-static int _crywrap_listen(const crywrap_config_t * config)
-{
- struct addrinfo *cur;
- int ret;
-
- cur = calloc(1, sizeof(struct addrinfo));
- if (cur == NULL)
- return -1;
-
- cur->ai_family = config->listen.addr->ss_family;
-
- switch (cur->ai_family) {
- case AF_INET6:
- cur->ai_addrlen = sizeof(struct sockaddr_in6);
- break;
- case AF_INET:
- cur->ai_addrlen = sizeof(struct sockaddr_in);
- break;
- default:
- ret = -1;
- goto cleanup;
- }
-
- cur->ai_addr = malloc(cur->ai_addrlen);
- if (cur->ai_addr == NULL)
- return -1;
-
- memcpy(cur->ai_addr, config->listen.addr, cur->ai_addrlen);
-
- ret = _crywrap_bind(cur, htons(config->listen.port));
- free(cur->ai_addr);
-
- cleanup:
- free(cur);
-
- return ret;
-}
-
-/** Connect to a remote server.
- * Estabilishes a connection to a remote server, and handles all
- * errors and anything that may arise during this process.
- *
- * @param addr is the address of the remote server.
- * @param port is the port to connect to.
- *
- * @returns the connected socket on success, otherwise it exits.
- */
-static int
-_crywrap_remote_connect(const struct sockaddr_storage *addr, int port)
-{
- struct addrinfo *cur;
- int sock;
-
- cur = calloc(1, sizeof(struct addrinfo));
- if (cur == NULL)
- return -1;
-
- cur->ai_family = addr->ss_family;
-
- switch (cur->ai_family) {
- case AF_INET6:
- cur->ai_addrlen = sizeof(struct sockaddr_in6);
- break;
- case AF_INET:
- cur->ai_addrlen = sizeof(struct sockaddr_in);
- break;
- default:
- sock = -1;
- goto cleanup;
- }
-
- cur->ai_addr = malloc(cur->ai_addrlen);
- if (cur->ai_addr == NULL)
- return -1;
-
- memcpy(cur->ai_addr, addr, cur->ai_addrlen);
-
- switch (cur->ai_family) {
- case AF_INET6:
- ((struct sockaddr_in6 *) (cur->ai_addr))->sin6_port = port;
- break;
- case AF_INET:
- ((struct sockaddr_in *) (cur->ai_addr))->sin_port = port;
- break;
- }
-
- sock = socket(cur->ai_family, SOCK_STREAM, IPPROTO_IP);
- if (sock < 0) {
- cry_error("socket(): %s", strerror(errno));
- exit(1);
- }
-
- if (connect(sock, cur->ai_addr, cur->ai_addrlen) < 0) {
- cry_error("connect(): %s", strerror(errno));
- exit(1);
- }
-
- free(cur->ai_addr);
-
- cleanup:
- free(cur);
-
- return sock;
-}
-
-/** @} */
-
-/** @defgroup crywrap Main CryWrap code.
- * @{
- */
-
-/** Drop privileges.
- * Drop privileges, if running as root.
- * Upon failure, it will make CryWrap exit.
- */
-static void _crywrap_privs_drop(const crywrap_config_t * config)
-{
- struct passwd *pwd;
-
- if (getuid() != 0) {
- cry_log("%s",
- "Not running as root, not dropping privileges.");
- return;
- }
-
- if ((pwd = getpwuid(config->uid)) == NULL) {
- cry_error("getpwuid(): %s", strerror(errno));
- exit(1);
- }
-
- if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
- cry_error("initgroups(): %s", strerror(errno));
- exit(1);
- }
-
- if (setgid(pwd->pw_gid) == -1) {
- cry_error("setgid(): %s", strerror(errno));
- exit(1);
- }
-
- if (setuid(config->uid)) {
- cry_error("setuid(): %s", strerror(errno));
- exit(1);
- }
-}
-
-/** Set up the PID file.
- * Checks if a #pidfile already exists, and create one - containing the
- * current PID - if one does not.
- *
- * @note Exits upon error.
- */
-static void _crywrap_setup_pidfile(const crywrap_config_t * config)
-{
- char mypid[128];
- int pidfilefd;
-
- if (!config->pidfile || !*(config->pidfile))
- return;
-
- if (!access(config->pidfile, F_OK)) {
- cry_error("Pidfile (%s) already exists. Exiting.",
- config->pidfile);
- exit(1);
- }
- if ((pidfilefd = open(config->pidfile,
- O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
- cry_error("Cannot create pidfile (%s): %s.\n",
- config->pidfile, strerror(errno));
- exit(1);
- }
- fchown(pidfilefd, config->uid, (gid_t) - 1);
-
- main_pid = getpid();
- snprintf(mypid, sizeof(mypid), "%d\n", main_pid);
- write(pidfilefd, mypid, strlen(mypid));
- close(pidfilefd);
- pidfile = config->pidfile;
-}
-
-
-/** Handles one client.
- * This one connects to the remote server, and proxies every traffic
- * between our client and the server.
- *
- * @param config is the main CryWrap configuration structure.
- * @param insock is the socket through which the client sends input.
- * @param outsock is the socket through which we send output.
- *
- * @note Exits on error.
- */
-static int
-_crywrap_do_one(const crywrap_config_t * config, int insock, int outsock)
-{
- int sock, ret, tls_pending;
- gnutls_session_t session;
- char buffer[_CRYWRAP_MAXBUF + 2];
- fd_set fdset;
- unsigned int status = 0;
- struct sockaddr_storage faddr;
- socklen_t socklen = sizeof(struct sockaddr_storage);
- char peer_name[NI_MAXHOST];
-
- /* Log the connection */
- if (getpeername(insock, (struct sockaddr *) &faddr, &socklen) != 0)
- cry_error("getpeername(): %s", strerror(errno));
- else {
- getnameinfo((struct sockaddr *) &faddr,
- sizeof(struct sockaddr_storage), peer_name,
- sizeof(peer_name), NULL, 0, NI_NUMERICHOST);
- cry_log("Accepted connection from %s on %d to %s/%d",
- peer_name, insock, config->dest.host,
- config->dest.port);
- }
-
- /* Do the handshake with our peer */
- session = _crywrap_tls_session_create(config);
- gnutls_transport_set_ptr2(session,
- (gnutls_transport_ptr_t) insock,
- (gnutls_transport_ptr_t) outsock);
-
- do {
- ret = gnutls_handshake(session);
- }
- while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
-
- if (ret < 0) {
- cry_error("Handshake failed: %s", gnutls_strerror(ret));
- gnutls_alert_send_appropriate(session, ret);
- goto error;
- }
-
- /* Verify the client's certificate, if any. */
- if (config->verify) {
- ret = gnutls_certificate_verify_peers2(session, &status);
- if (ret < 0)
- cry_log
- ("Error getting certificate from client: %s",
- gnutls_strerror(ret));
-
- if (ret == 0 && status != 0) {
- if (status & GNUTLS_CERT_INVALID)
- cry_log("%s",
- "Client certificate not trusted or invalid");
- }
-
- if (config->verify > 0 && status != 0) {
- ret = -1;
- gnutls_alert_send(session, GNUTLS_AL_FATAL,
- GNUTLS_A_INSUFFICIENT_SECURITY);
- goto error;
- }
- }
-
- /* Connect to the remote host */
- sock = _crywrap_remote_connect(config->dest.addr,
- htons(config->dest.port));
-
- for (;;) {
- FD_ZERO(&fdset);
- FD_SET(insock, &fdset);
- FD_SET(sock, &fdset);
-
- memset(buffer, 0, _CRYWRAP_MAXBUF + 1);
-
- tls_pending = 0;
-
- if (gnutls_record_check_pending(session) > 0)
- tls_pending = 1;
- else {
- select(sock + 1, &fdset, NULL, NULL, NULL);
- if (FD_ISSET(insock, &fdset))
- tls_pending = 1;
- }
- /* TLS client */
- if (tls_pending != 0) {
- ret =
- gnutls_record_recv(session, buffer,
- _CRYWRAP_MAXBUF);
- if (ret == 0) {
- cry_log("%s",
- "Peer has closed the GNUTLS connection");
- break;
- } else if (ret < 0) {
- cry_log("Received corrupted data: %s.",
- gnutls_strerror(ret));
- break;
- } else
- send(sock, buffer, ret, 0);
- }
-
- /* Remote server */
- if (FD_ISSET(sock, &fdset)) {
- ret = recv(sock, buffer, _CRYWRAP_MAXBUF, 0);
- if (ret == 0) {
- cry_log("%s",
- "Server has closed the connection");
- break;
- } else if (ret < 0) {
- cry_log("Received corrupted data: %s.",
- strerror(errno));
- break;
- } else {
- int r, o = 0;
-
- do {
- r = gnutls_record_send(session,
- &buffer[o],
- ret - o);
- o += r;
- } while (r > 0 && ret > o);
-
- if (r < 0)
- cry_log
- ("Received corrupt data: %s",
- gnutls_strerror(r));
- }
- }
- }
-
- error:
- gnutls_bye(session, GNUTLS_SHUT_WR);
- gnutls_deinit(session);
- close(insock);
- close(outsock);
-
- return (ret == 0) ? 0 : 1;
-}
-
-/** CryWrap entry point.
- * This is the main entry point - controls the whole program and so
- * on...
- */
-int main(int argc, char **argv, char **envp)
-{
- crywrap_config_t *config;
- int server_socket;
-
- openlog(__CRYWRAP__, LOG_PID, LOG_DAEMON);
-
- gnutls_global_set_audit_log_function(tls_audit_log_func);
-
- if (gnutls_global_init() < 0) {
- cry_error("%s", "Global TLS state initialisation failed.");
- exit(1);
- }
- if (gnutls_certificate_allocate_credentials(&cred) < 0) {
- cry_error("%s", "Couldn't allocate credentials.");
- exit(1);
- }
-
- stringprep_locale_charset();
-
- config = _crywrap_config_parse(argc, argv);
-
- _crywrap_tls_init();
-
- if (config->inetd) {
- _crywrap_privs_drop(config);
- exit(_crywrap_do_one(config, 0, 1));
- }
-
- if (!config->debug)
- if (daemon(0, 0)) {
- cry_error("daemon: %s", strerror(errno));
- exit(1);
- }
-
- cry_log("%s", "Crywrap starting...");
-
- server_socket = _crywrap_listen(config);
- if (server_socket < 0)
- exit(1);
-
- if (!config->debug)
- _crywrap_setup_pidfile(config);
- _crywrap_privs_drop(config);
-
- signal(SIGTERM, _crywrap_sighandler);
- signal(SIGQUIT, _crywrap_sighandler);
- signal(SIGSEGV, _crywrap_sighandler);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGCHLD, _crywrap_sigchld_handler);
-
- cry_log("%s", "Accepting connections");
-
-
- for (;;) {
- int csock;
- int child;
-
- csock = accept(server_socket, NULL, NULL);
- if (csock < 0)
- continue;
-
- child = fork();
- switch (child) {
- case 0:
- exit(_crywrap_do_one(config, csock, csock));
- break;
- case -1:
- cry_error("%s", "Forking error.");
- exit(1);
- break;
- }
- close(csock);
- }
-
- return 0;
-}
-
-static int system_log(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vsyslog(LOG_NOTICE, fmt, args);
- va_end(args);
-
- return 0;
-}
-
-static int system_log_error(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vsyslog(LOG_ERR, fmt, args);
- va_end(args);
-
- return 0;
-}
-
-static int debug_log(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vprintf(fmt, args);
- puts("");
- va_end(args);
-
- return 0;
-}
-
-/** @} */