2012-04-13 12:47:30 +00:00
|
|
|
/*
|
2015-02-24 18:19:20 +00:00
|
|
|
* SSLsplit - transparent SSL/TLS interception
|
2016-03-25 11:19:23 +00:00
|
|
|
* Copyright (c) 2009-2016, Daniel Roethlisberger <daniel@roe.ch>
|
2012-04-13 12:47:30 +00:00
|
|
|
* All rights reserved.
|
|
|
|
* http://www.roe.ch/SSLsplit
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
2015-02-24 18:19:20 +00:00
|
|
|
* notice, this list of conditions, and the following disclaimer.
|
2012-04-13 12:47:30 +00:00
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* silence daemon(3) deprecation warning on Mac OS X */
|
|
|
|
#if __APPLE__
|
|
|
|
#define daemon xdaemon
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
#include "opts.h"
|
|
|
|
#include "proxy.h"
|
2014-11-24 21:01:52 +00:00
|
|
|
#include "privsep.h"
|
2012-04-13 12:47:30 +00:00
|
|
|
#include "ssl.h"
|
|
|
|
#include "nat.h"
|
2014-11-14 15:20:07 +00:00
|
|
|
#include "proc.h"
|
2012-04-13 12:47:30 +00:00
|
|
|
#include "cachemgr.h"
|
|
|
|
#include "sys.h"
|
|
|
|
#include "log.h"
|
2012-04-13 20:40:36 +00:00
|
|
|
#include "version.h"
|
2014-11-25 22:45:40 +00:00
|
|
|
#include "defaults.h"
|
2012-04-13 12:47:30 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifndef __BSD__
|
|
|
|
#include <getopt.h>
|
|
|
|
#endif /* !__BSD__ */
|
|
|
|
|
|
|
|
#include <event2/event.h>
|
|
|
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <openssl/x509.h>
|
|
|
|
|
|
|
|
#if __APPLE__
|
|
|
|
#undef daemon
|
|
|
|
extern int daemon(int, int);
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
2014-11-24 21:01:52 +00:00
|
|
|
|
2012-04-13 12:47:30 +00:00
|
|
|
/*
|
|
|
|
* Print version information to stderr.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
main_version(void)
|
|
|
|
{
|
2012-04-13 20:40:36 +00:00
|
|
|
fprintf(stderr, "%s %s (built %s)\n", PNAME, version, build_date);
|
2016-03-25 11:34:52 +00:00
|
|
|
if (strlen(version) < 5) {
|
|
|
|
/*
|
|
|
|
* Note to package maintainers: If you break the version
|
|
|
|
* string in your build, it will be impossible to provide
|
|
|
|
* proper upstream support to the users of the package,
|
|
|
|
* because it will be difficult or impossible to identify
|
|
|
|
* the exact codebase that is being used by the user
|
|
|
|
* reporting a bug. The version string is provided through
|
|
|
|
* different means depending on whether the code is a git
|
|
|
|
* checkout, a tarball downloaded from GitHub or a release.
|
|
|
|
* See GNUmakefile for the gory details.
|
|
|
|
*/
|
|
|
|
fprintf(stderr, "---------------------------------------"
|
|
|
|
"---------------------------------------\n");
|
|
|
|
fprintf(stderr, "WARNING: Something is wrong with the "
|
|
|
|
"version compiled into sslsplit!\n");
|
|
|
|
fprintf(stderr, "The version should contain a release "
|
|
|
|
"number and/or a git commit reference.\n");
|
|
|
|
fprintf(stderr, "If using a package, please report a bug "
|
|
|
|
"to the distro package maintainer.\n");
|
|
|
|
fprintf(stderr, "---------------------------------------"
|
|
|
|
"---------------------------------------\n");
|
|
|
|
}
|
2016-03-25 11:19:23 +00:00
|
|
|
fprintf(stderr, "Copyright (c) 2009-2016, "
|
2012-04-13 12:47:30 +00:00
|
|
|
"Daniel Roethlisberger <daniel@roe.ch>\n");
|
|
|
|
fprintf(stderr, "http://www.roe.ch/SSLsplit\n");
|
2014-10-30 22:01:55 +00:00
|
|
|
if (build_info[0]) {
|
|
|
|
fprintf(stderr, "Build info: %s\n", build_info);
|
|
|
|
}
|
2012-04-13 20:40:36 +00:00
|
|
|
if (features[0]) {
|
|
|
|
fprintf(stderr, "Features: %s\n", features);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
nat_version();
|
2014-11-14 15:30:07 +00:00
|
|
|
fprintf(stderr, "Local process info support: ");
|
|
|
|
#ifdef HAVE_LOCAL_PROCINFO
|
2014-11-25 22:38:37 +00:00
|
|
|
fprintf(stderr, "yes (" LOCAL_PROCINFO_STR ")\n");
|
2014-11-14 15:30:07 +00:00
|
|
|
#else /* !HAVE_LOCAL_PROCINFO */
|
|
|
|
fprintf(stderr, "no\n");
|
|
|
|
#endif /* !HAVE_LOCAL_PROCINFO */
|
2012-04-13 12:47:30 +00:00
|
|
|
ssl_openssl_version();
|
|
|
|
fprintf(stderr, "compiled against libevent %s\n", LIBEVENT_VERSION);
|
|
|
|
fprintf(stderr, "rtlinked against libevent %s\n", event_get_version());
|
|
|
|
fprintf(stderr, "%d CPU cores detected\n", sys_get_cpu_cores());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print usage to stderr.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
main_usage(void)
|
|
|
|
{
|
|
|
|
const char *dflt, *warn;
|
|
|
|
|
|
|
|
if (!(dflt = nat_getdefaultname())) {
|
|
|
|
dflt = "n/a";
|
|
|
|
warn = "\nWarning: no supported NAT engine on this platform!\n"
|
|
|
|
"Only static and SNI proxyspecs are supported.\n";
|
|
|
|
} else {
|
|
|
|
warn = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
"Usage: %s [options...] [proxyspecs...]\n"
|
2012-04-22 20:59:00 +00:00
|
|
|
" -c pemfile use CA cert (and key) from pemfile to sign forged certs\n"
|
|
|
|
" -k pemfile use CA key (and cert) from pemfile to sign forged certs\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
" -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n"
|
|
|
|
" -K pemfile use key from pemfile for leaf certs (default: generate)\n"
|
|
|
|
" -t certdir use cert+chain+key PEM files from certdir to target all sites\n"
|
|
|
|
" matching the common names (non-matching: generate if CA)\n"
|
2014-12-13 01:36:45 +00:00
|
|
|
" -w gendir write leaf key and only generated certificates to gendir\n"
|
|
|
|
" -W gendir write leaf key and all certificates to gendir\n"
|
2012-04-22 17:12:38 +00:00
|
|
|
" -O deny all OCSP requests on all proxyspecs\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
" -P passthrough SSL connections if they cannot be split because of\n"
|
|
|
|
" client cert auth or no matching cert and no CA (default: drop)\n"
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
" -g pemfile use DH group params from pemfile (default: keyfiles or auto)\n"
|
|
|
|
#define OPT_g "g:"
|
|
|
|
#else /* OPENSSL_NO_DH */
|
|
|
|
#define OPT_g
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
|
|
|
#ifndef OPENSSL_NO_ECDH
|
2016-03-25 15:28:30 +00:00
|
|
|
" -G curve use ECDH named curve (default: " DFLT_CURVE ")\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
#define OPT_G "G:"
|
|
|
|
#else /* OPENSSL_NO_ECDH */
|
|
|
|
#define OPT_G
|
|
|
|
#endif /* OPENSSL_NO_ECDH */
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
|
|
|
" -Z disable SSL/TLS compression on all connections\n"
|
|
|
|
#define OPT_Z "Z"
|
|
|
|
#else /* !SSL_OP_NO_COMPRESSION */
|
|
|
|
#define OPT_Z
|
|
|
|
#endif /* !SSL_OP_NO_COMPRESSION */
|
2014-11-05 19:06:11 +00:00
|
|
|
" -r proto only support one of " SSL_PROTO_SUPPORT_S "(default: all)\n"
|
|
|
|
" -R proto disable one of " SSL_PROTO_SUPPORT_S "(default: none)\n"
|
2014-11-30 21:29:40 +00:00
|
|
|
" -s ciphers use the given OpenSSL cipher suite spec (default: " DFLT_CIPHERS ")\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
" -e engine specify default NAT engine to use (default: %s)\n"
|
|
|
|
" -E list available NAT engines and exit\n"
|
2014-11-25 22:45:40 +00:00
|
|
|
" -u user drop privileges to user (default if run as root: " DFLT_DROPUSER ")\n"
|
2014-10-23 11:23:57 +00:00
|
|
|
" -m group when using -u, override group (default: primary group of user)\n"
|
2014-11-24 21:01:52 +00:00
|
|
|
" -j jaildir chroot() to jaildir (impacts sni proxyspecs, see manual page)\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
" -p pidfile write pid to pidfile (default: no pid file)\n"
|
|
|
|
" -l logfile connect log: log one line summary per connection to logfile\n"
|
2014-11-13 22:38:46 +00:00
|
|
|
" -L logfile content log: full data to file or named pipe (excludes -S/-F)\n"
|
2014-10-18 22:40:22 +00:00
|
|
|
" -S logdir content log: full data to separate files in dir (excludes -L/-F)\n"
|
2014-11-13 22:38:46 +00:00
|
|
|
" -F pathspec content log: full data to sep files with %% subst (excl. -L/-S):\n"
|
|
|
|
" %%T - initial connection time as an ISO 8601 UTC timestamp\n"
|
2015-03-15 16:10:25 +00:00
|
|
|
" %%d - destination host and port\n"
|
2015-03-15 17:39:36 +00:00
|
|
|
" %%D - destination host\n"
|
|
|
|
" %%p - destination port\n"
|
2015-03-15 16:10:25 +00:00
|
|
|
" %%s - source host and port\n"
|
2015-03-15 17:39:36 +00:00
|
|
|
" %%S - source host\n"
|
|
|
|
" %%q - source port\n"
|
2014-11-14 15:20:07 +00:00
|
|
|
#ifdef HAVE_LOCAL_PROCINFO
|
|
|
|
" %%x - base name of local process (requires -i)\n"
|
|
|
|
" %%X - full path to local process (requires -i)\n"
|
|
|
|
" %%u - user name or id of local process (requires -i)\n"
|
|
|
|
" %%g - group name or id of local process (requires -i)\n"
|
|
|
|
#endif /* HAVE_LOCAL_PROCINFO */
|
2014-10-18 22:40:22 +00:00
|
|
|
" %%%% - literal '%%'\n"
|
2014-11-14 15:20:07 +00:00
|
|
|
#ifdef HAVE_LOCAL_PROCINFO
|
|
|
|
" e.g. \"/var/log/sslsplit/%%X/%%u-%%s-%%d-%%T.log\"\n"
|
|
|
|
" -i look up local process owning each connection for logging\n"
|
|
|
|
#define OPT_i "i"
|
|
|
|
#else /* !HAVE_LOCAL_PROCINFO */
|
|
|
|
" e.g. \"/var/log/sslsplit/%%T-%%s-%%d.log\"\n"
|
|
|
|
#define OPT_i
|
|
|
|
#endif /* HAVE_LOCAL_PROCINFO */
|
2012-04-13 12:47:30 +00:00
|
|
|
" -d daemon mode: run in background, log error messages to syslog\n"
|
|
|
|
" -D debug mode: run in foreground, log debug messages on stderr\n"
|
|
|
|
" -V print version information and exit\n"
|
|
|
|
" -h print usage information and exit\n"
|
|
|
|
" proxyspec = type listenaddr+port [natengine|targetaddr+port|\"sni\"+port]\n"
|
2014-11-13 22:38:46 +00:00
|
|
|
" e.g. http 0.0.0.0 8080 www.roe.ch 80 # http/4; static hostname dst\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
" https ::1 8443 2001:db8::1 443 # https/6; static address dst\n"
|
|
|
|
" https 127.0.0.1 9443 sni 443 # https/4; SNI DNS lookups\n"
|
|
|
|
" tcp 127.0.0.1 10025 # tcp/4; default NAT engine\n"
|
|
|
|
" ssl 2001:db8::2 9999 pf # ssl/6; NAT engine 'pf'\n"
|
2016-03-27 12:38:06 +00:00
|
|
|
" autossl ::1 10025 # autossl/6; STARTTLS et al\n"
|
2012-04-13 12:47:30 +00:00
|
|
|
"Example:\n"
|
|
|
|
" %s -k ca.key -c ca.pem -P https 127.0.0.1 8443 https ::1 8443\n"
|
2014-11-25 22:45:40 +00:00
|
|
|
"%s", BNAME, dflt, BNAME, warn);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Callback to load a cert/chain/key combo from a single PEM file.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
main_loadtgcrt(const char *filename, void *arg)
|
|
|
|
{
|
2012-10-16 22:10:47 +00:00
|
|
|
opts_t *opts = arg;
|
2012-04-13 12:47:30 +00:00
|
|
|
cert_t *cert;
|
|
|
|
char **names;
|
|
|
|
|
|
|
|
cert = cert_new_load(filename);
|
|
|
|
if (!cert) {
|
2012-10-16 22:10:47 +00:00
|
|
|
log_err_printf("Failed to load cert and key from PEM file "
|
|
|
|
"'%s'\n", filename);
|
2012-10-23 21:04:22 +00:00
|
|
|
log_fini();
|
2014-11-24 21:01:52 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
if (X509_check_private_key(cert->crt, cert->key) != 1) {
|
2012-10-16 22:10:47 +00:00
|
|
|
log_err_printf("Cert does not match key in PEM file "
|
|
|
|
"'%s':\n", filename);
|
2012-04-13 12:47:30 +00:00
|
|
|
ERR_print_errors_fp(stderr);
|
2012-10-23 21:04:22 +00:00
|
|
|
log_fini();
|
2014-11-24 21:01:52 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_CERTIFICATE
|
|
|
|
log_dbg_printf("Loaded '%s':\n", filename);
|
|
|
|
log_dbg_print_free(ssl_x509_to_str(cert->crt));
|
|
|
|
log_dbg_print_free(ssl_x509_to_pem(cert->crt));
|
|
|
|
#endif /* DEBUG_CERTIFICATE */
|
|
|
|
|
2012-05-13 13:24:50 +00:00
|
|
|
if (OPTS_DEBUG(opts)) {
|
2012-04-13 12:47:30 +00:00
|
|
|
log_dbg_printf("Targets for '%s':", filename);
|
|
|
|
}
|
|
|
|
names = ssl_x509_names(cert->crt);
|
|
|
|
for (char **p = names; *p; p++) {
|
|
|
|
/* be deliberately vulnerable to NULL prefix attacks */
|
|
|
|
char *sep;
|
|
|
|
if ((sep = strchr(*p, '!'))) {
|
|
|
|
*sep = '\0';
|
|
|
|
}
|
2012-05-13 13:24:50 +00:00
|
|
|
if (OPTS_DEBUG(opts)) {
|
2012-04-13 12:47:30 +00:00
|
|
|
log_dbg_printf(" '%s'", *p);
|
|
|
|
}
|
|
|
|
cachemgr_tgcrt_set(*p, cert);
|
|
|
|
free(*p);
|
|
|
|
}
|
2012-05-13 13:24:50 +00:00
|
|
|
if (OPTS_DEBUG(opts)) {
|
2012-04-13 12:47:30 +00:00
|
|
|
log_dbg_printf("\n");
|
|
|
|
}
|
|
|
|
free(names);
|
|
|
|
cert_free(cert);
|
|
|
|
}
|
|
|
|
|
2014-10-23 11:14:06 +00:00
|
|
|
/*
|
|
|
|
* Handle out of memory conditions in early stages of main().
|
|
|
|
* Print error message and exit with failure status code.
|
|
|
|
* Does not return.
|
|
|
|
*/
|
|
|
|
void NORET
|
|
|
|
oom_die(const char *argv0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: out of memory\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2012-04-13 12:47:30 +00:00
|
|
|
/*
|
|
|
|
* Main entry point.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
const char *argv0;
|
|
|
|
int ch;
|
|
|
|
opts_t *opts;
|
|
|
|
char *natengine;
|
|
|
|
int pidfd = -1;
|
2012-10-23 19:30:11 +00:00
|
|
|
int rv = EXIT_FAILURE;
|
2012-04-13 12:47:30 +00:00
|
|
|
|
|
|
|
argv0 = argv[0];
|
|
|
|
opts = opts_new();
|
2014-10-18 01:35:44 +00:00
|
|
|
if (nat_getdefaultname()) {
|
|
|
|
natengine = strdup(nat_getdefaultname());
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!natengine)
|
|
|
|
oom_die(argv0);
|
2014-10-18 01:35:44 +00:00
|
|
|
} else {
|
|
|
|
natengine = NULL;
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
|
2014-11-23 14:45:55 +00:00
|
|
|
while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i "k:c:C:K:t:"
|
2017-06-15 16:07:37 +00:00
|
|
|
"OPs:r:R:e:Eu:m:j:p:l:L:S:F:dD::VhW:w:")) != -1) {
|
2012-04-13 12:47:30 +00:00
|
|
|
switch (ch) {
|
2012-04-22 20:59:00 +00:00
|
|
|
case 'c':
|
|
|
|
if (opts->cacrt)
|
|
|
|
X509_free(opts->cacrt);
|
|
|
|
opts->cacrt = ssl_x509_load(optarg);
|
|
|
|
if (!opts->cacrt) {
|
2012-04-13 12:47:30 +00:00
|
|
|
fprintf(stderr, "%s: error loading CA "
|
2012-04-22 20:59:00 +00:00
|
|
|
"cert from '%s':\n",
|
2012-04-13 12:47:30 +00:00
|
|
|
argv0, optarg);
|
|
|
|
if (errno) {
|
|
|
|
fprintf(stderr, "%s\n",
|
|
|
|
strerror(errno));
|
|
|
|
} else {
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-22 20:59:00 +00:00
|
|
|
ssl_x509_refcount_inc(opts->cacrt);
|
|
|
|
sk_X509_insert(opts->chain, opts->cacrt, 0);
|
|
|
|
if (!opts->cakey) {
|
|
|
|
opts->cakey = ssl_key_load(optarg);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
if (!opts->dh) {
|
|
|
|
opts->dh = ssl_dh_load(optarg);
|
|
|
|
}
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
|
|
|
break;
|
2012-04-22 20:59:00 +00:00
|
|
|
case 'k':
|
|
|
|
if (opts->cakey)
|
|
|
|
EVP_PKEY_free(opts->cakey);
|
|
|
|
opts->cakey = ssl_key_load(optarg);
|
|
|
|
if (!opts->cakey) {
|
2012-04-13 12:47:30 +00:00
|
|
|
fprintf(stderr, "%s: error loading CA "
|
2012-04-22 20:59:00 +00:00
|
|
|
"key from '%s':\n",
|
2012-04-13 12:47:30 +00:00
|
|
|
argv0, optarg);
|
|
|
|
if (errno) {
|
|
|
|
fprintf(stderr, "%s\n",
|
|
|
|
strerror(errno));
|
|
|
|
} else {
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-22 20:59:00 +00:00
|
|
|
if (!opts->cacrt) {
|
|
|
|
opts->cacrt = ssl_x509_load(optarg);
|
|
|
|
if (opts->cacrt) {
|
|
|
|
ssl_x509_refcount_inc(
|
|
|
|
opts->cacrt);
|
|
|
|
sk_X509_insert(opts->chain,
|
|
|
|
opts->cacrt, 0);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
2012-04-22 20:59:00 +00:00
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
if (!opts->dh) {
|
|
|
|
opts->dh = ssl_dh_load(optarg);
|
|
|
|
}
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
if (ssl_x509chain_load(NULL, &opts->chain,
|
|
|
|
optarg) == -1) {
|
|
|
|
fprintf(stderr, "%s: error loading "
|
|
|
|
"chain from '%s':\n",
|
|
|
|
argv0, optarg);
|
|
|
|
if (errno) {
|
|
|
|
fprintf(stderr, "%s\n",
|
|
|
|
strerror(errno));
|
|
|
|
} else {
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'K':
|
|
|
|
if (opts->key)
|
|
|
|
EVP_PKEY_free(opts->key);
|
|
|
|
opts->key = ssl_key_load(optarg);
|
|
|
|
if (!opts->key) {
|
|
|
|
fprintf(stderr, "%s: error loading lea"
|
|
|
|
"f key from '%s':\n",
|
|
|
|
argv0, optarg);
|
|
|
|
if (errno) {
|
|
|
|
fprintf(stderr, "%s\n",
|
|
|
|
strerror(errno));
|
|
|
|
} else {
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
if (!opts->dh) {
|
|
|
|
opts->dh = ssl_dh_load(optarg);
|
|
|
|
}
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
if (!sys_isdir(optarg)) {
|
|
|
|
fprintf(stderr, "%s: '%s' is not a "
|
|
|
|
"directory\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (opts->tgcrtdir)
|
|
|
|
free(opts->tgcrtdir);
|
|
|
|
opts->tgcrtdir = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->tgcrtdir)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
2012-04-22 17:12:38 +00:00
|
|
|
case 'O':
|
|
|
|
opts->deny_ocsp = 1;
|
|
|
|
break;
|
2012-04-13 12:47:30 +00:00
|
|
|
case 'P':
|
|
|
|
opts->passthrough = 1;
|
|
|
|
break;
|
|
|
|
#ifndef OPENSSL_NO_DH
|
|
|
|
case 'g':
|
|
|
|
if (opts->dh)
|
|
|
|
DH_free(opts->dh);
|
|
|
|
opts->dh = ssl_dh_load(optarg);
|
|
|
|
if (!opts->dh) {
|
|
|
|
fprintf(stderr, "%s: error loading DH "
|
|
|
|
"params from '%s':\n",
|
|
|
|
argv0, optarg);
|
|
|
|
if (errno) {
|
|
|
|
fprintf(stderr, "%s\n",
|
|
|
|
strerror(errno));
|
|
|
|
} else {
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
|
|
|
#ifndef OPENSSL_NO_ECDH
|
|
|
|
case 'G':
|
|
|
|
{
|
2012-05-11 15:39:12 +00:00
|
|
|
EC_KEY *ec;
|
2012-04-13 12:47:30 +00:00
|
|
|
if (opts->ecdhcurve)
|
|
|
|
free(opts->ecdhcurve);
|
2012-05-11 15:39:12 +00:00
|
|
|
if (!(ec = ssl_ec_by_name(optarg))) {
|
2012-04-13 12:47:30 +00:00
|
|
|
fprintf(stderr, "%s: unknown curve "
|
|
|
|
"'%s'\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-05-11 15:39:12 +00:00
|
|
|
EC_KEY_free(ec);
|
2012-04-13 12:47:30 +00:00
|
|
|
opts->ecdhcurve = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->ecdhcurve)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* !OPENSSL_NO_ECDH */
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
|
|
|
case 'Z':
|
|
|
|
opts->sslcomp = 0;
|
|
|
|
break;
|
|
|
|
#endif /* SSL_OP_NO_COMPRESSION */
|
|
|
|
case 's':
|
|
|
|
if (opts->ciphers)
|
|
|
|
free(opts->ciphers);
|
|
|
|
opts->ciphers = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->ciphers)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
2014-11-05 19:06:11 +00:00
|
|
|
case 'r':
|
|
|
|
opts_proto_force(opts, optarg, argv0);
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
opts_proto_disable(opts, optarg, argv0);
|
|
|
|
break;
|
2012-04-13 12:47:30 +00:00
|
|
|
case 'e':
|
|
|
|
free(natengine);
|
|
|
|
natengine = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!natengine)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
nat_list_engines();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
break;
|
|
|
|
case 'u':
|
2014-11-23 21:52:09 +00:00
|
|
|
if (!sys_isuser(optarg)) {
|
|
|
|
fprintf(stderr, "%s: '%s' is not an "
|
|
|
|
"existing user\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
if (opts->dropuser)
|
|
|
|
free(opts->dropuser);
|
|
|
|
opts->dropuser = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->dropuser)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
2014-10-18 06:34:51 +00:00
|
|
|
case 'm':
|
2014-11-23 21:52:09 +00:00
|
|
|
if (!sys_isgroup(optarg)) {
|
|
|
|
fprintf(stderr, "%s: '%s' is not an "
|
|
|
|
"existing group\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-10-18 06:34:51 +00:00
|
|
|
if (opts->dropgroup)
|
|
|
|
free(opts->dropgroup);
|
|
|
|
opts->dropgroup = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->dropgroup)
|
|
|
|
oom_die(argv0);
|
2014-10-18 06:34:51 +00:00
|
|
|
break;
|
2012-04-13 12:47:30 +00:00
|
|
|
case 'p':
|
|
|
|
if (opts->pidfile)
|
|
|
|
free(opts->pidfile);
|
|
|
|
opts->pidfile = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->pidfile)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'j':
|
2014-11-23 14:46:37 +00:00
|
|
|
if (!sys_isdir(optarg)) {
|
|
|
|
fprintf(stderr, "%s: '%s' is not a "
|
|
|
|
"directory\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
if (opts->jaildir)
|
|
|
|
free(opts->jaildir);
|
2014-11-24 21:01:52 +00:00
|
|
|
opts->jaildir = realpath(optarg, NULL);
|
|
|
|
if (!opts->jaildir) {
|
|
|
|
fprintf(stderr, "%s: Failed to "
|
|
|
|
"canonicalize '%s': "
|
|
|
|
"%s (%i)\n",
|
|
|
|
argv0, optarg,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
if (opts->connectlog)
|
|
|
|
free(opts->connectlog);
|
|
|
|
opts->connectlog = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->connectlog)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
if (opts->contentlog)
|
|
|
|
free(opts->contentlog);
|
|
|
|
opts->contentlog = strdup(optarg);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->contentlog)
|
|
|
|
oom_die(argv0);
|
2014-11-21 11:03:08 +00:00
|
|
|
opts->contentlog_isdir = 0;
|
|
|
|
opts->contentlog_isspec = 0;
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'S':
|
2014-11-23 14:46:37 +00:00
|
|
|
if (!sys_isdir(optarg)) {
|
|
|
|
fprintf(stderr, "%s: '%s' is not a "
|
|
|
|
"directory\n",
|
|
|
|
argv0, optarg);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
if (opts->contentlog)
|
|
|
|
free(opts->contentlog);
|
2014-11-24 21:01:52 +00:00
|
|
|
opts->contentlog = realpath(optarg, NULL);
|
|
|
|
if (!opts->contentlog) {
|
|
|
|
fprintf(stderr, "%s: Failed to "
|
|
|
|
"canonicalize '%s': "
|
|
|
|
"%s (%i)\n",
|
|
|
|
argv0, optarg,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-11-21 11:03:08 +00:00
|
|
|
opts->contentlog_isdir = 1;
|
|
|
|
opts->contentlog_isspec = 0;
|
2014-10-18 22:40:22 +00:00
|
|
|
break;
|
2014-11-24 21:01:52 +00:00
|
|
|
case 'F': {
|
|
|
|
char *lhs, *rhs, *p, *q;
|
|
|
|
size_t n;
|
|
|
|
if (opts->contentlog_basedir)
|
|
|
|
free(opts->contentlog_basedir);
|
2014-10-18 22:40:22 +00:00
|
|
|
if (opts->contentlog)
|
|
|
|
free(opts->contentlog);
|
2014-11-24 21:01:52 +00:00
|
|
|
if (log_content_split_pathspec(optarg, &lhs,
|
|
|
|
&rhs) == -1) {
|
|
|
|
fprintf(stderr, "%s: Failed to split "
|
|
|
|
"'%s' in lhs/rhs: "
|
|
|
|
"%s (%i)\n",
|
|
|
|
argv0, optarg,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
/* eliminate %% from lhs */
|
|
|
|
for (p = q = lhs; *p; p++, q++) {
|
|
|
|
if (q < p)
|
|
|
|
*q = *p;
|
|
|
|
if (*p == '%' && *(p+1) == '%')
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
/* all %% in lhs resolved to % */
|
|
|
|
if (sys_mkpath(lhs, 0777) == -1) {
|
|
|
|
fprintf(stderr, "%s: Failed to create "
|
|
|
|
"'%s': %s (%i)\n",
|
|
|
|
argv0, lhs,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
opts->contentlog_basedir = realpath(lhs, NULL);
|
|
|
|
if (!opts->contentlog_basedir) {
|
|
|
|
fprintf(stderr, "%s: Failed to "
|
|
|
|
"canonicalize '%s': "
|
|
|
|
"%s (%i)\n",
|
|
|
|
argv0, lhs,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
/* count '%' in opts->contentlog_basedir */
|
|
|
|
for (n = 0, p = opts->contentlog_basedir;
|
|
|
|
*p;
|
|
|
|
p++) {
|
|
|
|
if (*p == '%')
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
free(lhs);
|
|
|
|
n += strlen(opts->contentlog_basedir);
|
|
|
|
if (!(lhs = malloc(n + 1)))
|
|
|
|
oom_die(argv0);
|
|
|
|
/* re-encoding % to %%, copying basedir to lhs */
|
|
|
|
for (p = opts->contentlog_basedir, q = lhs;
|
|
|
|
*p;
|
|
|
|
p++, q++) {
|
|
|
|
*q = *p;
|
|
|
|
if (*q == '%')
|
|
|
|
*(++q) = '%';
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
/* lhs contains encoded realpathed basedir */
|
|
|
|
if (asprintf(&opts->contentlog,
|
|
|
|
"%s/%s", lhs, rhs) < 0)
|
2014-11-07 23:44:47 +00:00
|
|
|
oom_die(argv0);
|
2014-11-21 11:03:08 +00:00
|
|
|
opts->contentlog_isdir = 0;
|
|
|
|
opts->contentlog_isspec = 1;
|
2014-11-24 21:01:52 +00:00
|
|
|
free(lhs);
|
|
|
|
free(rhs);
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
2014-12-09 21:43:05 +00:00
|
|
|
case 'W':
|
2014-12-13 01:36:45 +00:00
|
|
|
opts->certgen_writeall = 1;
|
2014-12-09 21:43:05 +00:00
|
|
|
if (opts->certgendir)
|
|
|
|
free(opts->certgendir);
|
|
|
|
opts->certgendir = strdup(optarg);
|
|
|
|
if (!opts->certgendir)
|
|
|
|
oom_die(argv0);
|
|
|
|
break;
|
2014-12-09 20:02:25 +00:00
|
|
|
case 'w':
|
2014-12-13 01:36:45 +00:00
|
|
|
opts->certgen_writeall = 0;
|
2014-12-09 19:08:11 +00:00
|
|
|
if (opts->certgendir)
|
|
|
|
free(opts->certgendir);
|
|
|
|
opts->certgendir = strdup(optarg);
|
|
|
|
if (!opts->certgendir)
|
|
|
|
oom_die(argv0);
|
|
|
|
break;
|
2014-11-24 21:01:52 +00:00
|
|
|
}
|
2014-11-14 15:20:07 +00:00
|
|
|
#ifdef HAVE_LOCAL_PROCINFO
|
|
|
|
case 'i':
|
|
|
|
opts->lprocinfo = 1;
|
|
|
|
break;
|
|
|
|
#endif /* HAVE_LOCAL_PROCINFO */
|
2012-04-13 12:47:30 +00:00
|
|
|
case 'd':
|
|
|
|
opts->detach = 1;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
opts->debug = 1;
|
2017-06-15 16:07:37 +00:00
|
|
|
|
|
|
|
fprintf(stderr, "Debug optarg = %s.\n", optarg);
|
|
|
|
|
|
|
|
if (optarg && strncmp(optarg, "2", 1) == 0) {
|
|
|
|
log_dbg_mode(LOG_DBG_MODE_FINE);
|
|
|
|
} else if (optarg && strncmp(optarg, "3", 1) == 0) {
|
|
|
|
log_dbg_mode(LOG_DBG_MODE_FINER);
|
|
|
|
} else if (optarg && strncmp(optarg, "4", 1) == 0) {
|
|
|
|
log_dbg_mode(LOG_DBG_MODE_FINEST);
|
|
|
|
} else {
|
|
|
|
log_dbg_mode(LOG_DBG_MODE_ERRLOG);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
main_version();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
case 'h':
|
|
|
|
main_usage();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
case '?':
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
default:
|
|
|
|
main_usage();
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
opts->spec = proxyspec_parse(&argc, &argv, natengine);
|
|
|
|
|
2014-10-23 11:23:57 +00:00
|
|
|
/* usage checks before defaults */
|
2012-05-13 13:24:50 +00:00
|
|
|
if (opts->detach && OPTS_DEBUG(opts)) {
|
2012-04-13 12:47:30 +00:00
|
|
|
fprintf(stderr, "%s: -d and -D are mutually exclusive.\n",
|
|
|
|
argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (!opts->spec) {
|
|
|
|
fprintf(stderr, "%s: no proxyspec specified.\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> Enter spec for loop\n");
|
2012-04-13 12:47:30 +00:00
|
|
|
for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> spec for loop: %s\n", spec->natengine);
|
2012-04-13 12:47:30 +00:00
|
|
|
if (spec->connect_addrlen || spec->sni_port)
|
|
|
|
continue;
|
|
|
|
if (!spec->natengine) {
|
|
|
|
fprintf(stderr, "%s: no supported NAT engines "
|
|
|
|
"on this platform.\n"
|
|
|
|
"Only static addr and SNI proxyspecs "
|
|
|
|
"supported.\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (spec->listen_addr.ss_family == AF_INET6 &&
|
|
|
|
!nat_ipv6ready(spec->natengine)) {
|
|
|
|
fprintf(stderr, "%s: IPv6 not supported by '%s'\n",
|
|
|
|
argv0, spec->natengine);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> nat_getlookupcb: %s\n", spec->natengine);
|
2012-04-13 12:47:30 +00:00
|
|
|
spec->natlookup = nat_getlookupcb(spec->natengine);
|
|
|
|
spec->natsocket = nat_getsocketcb(spec->natengine);
|
|
|
|
}
|
|
|
|
if (opts_has_ssl_spec(opts)) {
|
2015-04-30 14:54:09 +00:00
|
|
|
if (ssl_init() == -1) {
|
|
|
|
fprintf(stderr, "%s: failed to initialize OpenSSL.\n",
|
|
|
|
argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
if ((opts->cacrt || !opts->tgcrtdir) && !opts->cakey) {
|
|
|
|
fprintf(stderr, "%s: no CA key specified (-k).\n",
|
|
|
|
argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (opts->cakey && !opts->cacrt) {
|
|
|
|
fprintf(stderr, "%s: no CA cert specified (-c).\n",
|
|
|
|
argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (opts->cakey && opts->cacrt &&
|
|
|
|
(X509_check_private_key(opts->cacrt, opts->cakey) != 1)) {
|
|
|
|
fprintf(stderr, "%s: CA cert does not match key.\n",
|
|
|
|
argv0);
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
2014-11-27 23:04:20 +00:00
|
|
|
#ifdef __APPLE__
|
2014-11-28 09:03:29 +00:00
|
|
|
if (opts->dropuser && !!strcmp(opts->dropuser, "root") &&
|
|
|
|
nat_used("pf")) {
|
2014-11-27 23:04:20 +00:00
|
|
|
fprintf(stderr, "%s: cannot use 'pf' proxyspec with -u due "
|
|
|
|
"to Apple bug\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
#endif /* __APPLE__ */
|
2012-04-13 12:47:30 +00:00
|
|
|
|
2012-10-16 20:52:54 +00:00
|
|
|
/* prevent multiple instances running */
|
|
|
|
if (opts->pidfile) {
|
|
|
|
pidfd = sys_pidf_open(opts->pidfile);
|
|
|
|
if (pidfd == -1) {
|
|
|
|
fprintf(stderr, "%s: cannot open PID file '%s' "
|
|
|
|
"- process already running?\n",
|
|
|
|
argv0, opts->pidfile);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-13 12:47:30 +00:00
|
|
|
/* dynamic defaults */
|
|
|
|
if (!opts->ciphers) {
|
2014-11-30 21:29:40 +00:00
|
|
|
opts->ciphers = strdup(DFLT_CIPHERS);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->ciphers)
|
|
|
|
oom_die(argv0);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
if (!opts->dropuser && !geteuid() && !getuid() &&
|
2014-11-25 22:45:40 +00:00
|
|
|
sys_isuser(DFLT_DROPUSER)) {
|
2014-11-27 23:04:20 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
/* Apple broke ioctl(/dev/pf) for EUID != 0 so we do not
|
|
|
|
* want to automatically drop privileges to nobody there
|
|
|
|
* if pf has been used in any proxyspec */
|
|
|
|
if (!nat_used("pf")) {
|
|
|
|
#endif /* __APPLE__ */
|
2014-11-25 22:45:40 +00:00
|
|
|
opts->dropuser = strdup(DFLT_DROPUSER);
|
2014-10-23 11:14:06 +00:00
|
|
|
if (!opts->dropuser)
|
|
|
|
oom_die(argv0);
|
2014-11-27 23:04:20 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
}
|
|
|
|
#endif /* __APPLE__ */
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
2013-05-26 22:17:36 +00:00
|
|
|
if (opts_has_ssl_spec(opts) && opts->cakey && !opts->key) {
|
2015-03-24 19:33:38 +00:00
|
|
|
/*
|
|
|
|
* While browsers still generally accept it, use a leaf key
|
|
|
|
* size of 1024 bit for leaf keys. When browsers start to
|
|
|
|
* sunset 1024 bit RSA in leaf keys, we will need to make this
|
|
|
|
* value bigger, and/or configurable. Until then, users who
|
|
|
|
* want a different size can always use their own pre-generated
|
|
|
|
* leaf key instead of generating one.
|
|
|
|
*/
|
2012-10-16 20:52:54 +00:00
|
|
|
opts->key = ssl_key_genrsa(1024);
|
|
|
|
if (!opts->key) {
|
|
|
|
fprintf(stderr, "%s: error generating RSA key:\n",
|
|
|
|
argv0);
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (OPTS_DEBUG(opts)) {
|
|
|
|
log_dbg_printf("Generated RSA key for leaf certs.\n");
|
|
|
|
}
|
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
|
2014-12-12 17:28:06 +00:00
|
|
|
if (opts->certgendir) {
|
2014-12-13 01:36:45 +00:00
|
|
|
char *keyid, *keyfn;
|
|
|
|
int prv;
|
|
|
|
FILE *keyf;
|
|
|
|
|
|
|
|
keyid = ssl_key_identifier(opts->key, 0);
|
|
|
|
if (!keyid) {
|
|
|
|
fprintf(stderr, "%s: error generating key id\n", argv0);
|
2014-12-12 17:28:06 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-12-13 01:36:45 +00:00
|
|
|
|
|
|
|
prv = asprintf(&keyfn, "%s/%s.key", opts->certgendir, keyid);
|
|
|
|
if (prv == -1) {
|
|
|
|
fprintf(stderr, "%s: %s (%i)\n", argv0,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(keyf = fopen(keyfn, "w"))) {
|
|
|
|
fprintf(stderr, "%s: Failed to open '%s' for writing: "
|
|
|
|
"%s (%i)\n", argv0, keyfn,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (!PEM_write_PrivateKey(keyf, opts->key, NULL, 0, 0,
|
|
|
|
NULL, NULL)) {
|
|
|
|
fprintf(stderr, "%s: Failed to write key to '%s': "
|
|
|
|
"%s (%i)\n", argv0, keyfn,
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
2014-12-12 17:28:06 +00:00
|
|
|
}
|
2014-12-13 01:36:45 +00:00
|
|
|
fclose(keyf);
|
2014-12-12 17:28:06 +00:00
|
|
|
}
|
|
|
|
|
2014-10-23 11:23:57 +00:00
|
|
|
/* usage checks after defaults */
|
|
|
|
if (opts->dropgroup && !opts->dropuser) {
|
|
|
|
fprintf(stderr, "%s: -m depends on -u.\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2012-04-13 12:47:30 +00:00
|
|
|
/* debugging */
|
2012-05-13 13:24:50 +00:00
|
|
|
if (OPTS_DEBUG(opts)) {
|
2012-04-13 12:47:30 +00:00
|
|
|
main_version();
|
2014-11-05 20:18:53 +00:00
|
|
|
opts_proto_dbg_dump(opts);
|
2012-04-13 12:47:30 +00:00
|
|
|
log_dbg_printf("proxyspecs:\n");
|
|
|
|
for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
|
2015-03-15 21:55:34 +00:00
|
|
|
char *specstr = proxyspec_str(spec);
|
|
|
|
if (!specstr) {
|
2015-03-15 16:10:25 +00:00
|
|
|
fprintf(stderr, "%s: out of memory\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2015-03-15 21:55:34 +00:00
|
|
|
log_dbg_printf("- %s\n", specstr);
|
|
|
|
free(specstr);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
if (opts->cacrt) {
|
|
|
|
char *subj = ssl_x509_subject(opts->cacrt);
|
|
|
|
log_dbg_printf("Loaded CA: '%s'\n", subj);
|
|
|
|
free(subj);
|
|
|
|
#ifdef DEBUG_CERTIFICATE
|
|
|
|
log_dbg_print_free(ssl_x509_to_str(opts->cacrt));
|
|
|
|
log_dbg_print_free(ssl_x509_to_pem(opts->cacrt));
|
|
|
|
#endif /* DEBUG_CERTIFICATE */
|
|
|
|
} else {
|
|
|
|
log_dbg_printf("No CA loaded.\n");
|
|
|
|
}
|
|
|
|
}
|
2012-10-16 20:52:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize as much as possible before daemon() in order to be
|
|
|
|
* able to provide direct feedback to the user when failing.
|
|
|
|
*/
|
2012-10-16 21:05:37 +00:00
|
|
|
if (cachemgr_preinit() == -1) {
|
|
|
|
fprintf(stderr, "%s: failed to preinit cachemgr.\n", argv0);
|
2012-10-16 20:52:54 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
if (log_preinit(opts) == -1) {
|
|
|
|
fprintf(stderr, "%s: failed to preinit logging.\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (nat_preinit() == -1) {
|
|
|
|
fprintf(stderr, "%s: failed to preinit NAT lookup.\n", argv0);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2014-01-30 21:33:57 +00:00
|
|
|
/* Load certs before dropping privs but after cachemgr_preinit() */
|
|
|
|
if (opts->tgcrtdir) {
|
|
|
|
sys_dir_eachfile(opts->tgcrtdir, main_loadtgcrt, opts);
|
|
|
|
}
|
2013-04-03 16:02:45 +00:00
|
|
|
|
2014-11-24 21:01:52 +00:00
|
|
|
/* Detach from tty; from this point on, only canonicalized absolute
|
|
|
|
* paths should be used (-j, -F, -S). */
|
2012-04-13 12:47:30 +00:00
|
|
|
if (opts->detach) {
|
2012-10-23 19:30:11 +00:00
|
|
|
if (OPTS_DEBUG(opts)) {
|
|
|
|
log_dbg_printf("Detaching from TTY, see syslog for "
|
|
|
|
"errors after this point\n");
|
|
|
|
}
|
2014-11-24 21:01:52 +00:00
|
|
|
if (daemon(0, 0) == -1) {
|
2012-04-13 12:47:30 +00:00
|
|
|
fprintf(stderr, "%s: failed to detach from TTY: %s\n",
|
|
|
|
argv0, strerror(errno));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
log_err_mode(LOG_ERR_MODE_SYSLOG);
|
|
|
|
}
|
2012-10-16 22:24:26 +00:00
|
|
|
|
2014-11-24 21:01:52 +00:00
|
|
|
if (opts->pidfile && (sys_pidf_write(pidfd) == -1)) {
|
|
|
|
log_err_printf("Failed to write PID to PID file '%s': %s (%i)"
|
|
|
|
"\n", opts->pidfile, strerror(errno), errno);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fork into parent monitor process and (potentially unprivileged)
|
2014-12-13 22:52:17 +00:00
|
|
|
* child process doing the actual work. We request 3 privsep client
|
|
|
|
* sockets: content logger thread, cert writer thread, and the child
|
2014-11-24 21:01:52 +00:00
|
|
|
* process main thread (main proxy thread) */
|
2014-12-13 22:52:17 +00:00
|
|
|
int clisock[3];
|
|
|
|
if (privsep_fork(opts, clisock, 3) != 0) {
|
2014-11-24 21:01:52 +00:00
|
|
|
/* parent has exited the monitor loop after waiting for child,
|
|
|
|
* or an error occured */
|
|
|
|
if (opts->pidfile) {
|
|
|
|
sys_pidf_close(pidfd, opts->pidfile);
|
|
|
|
}
|
|
|
|
goto out_parent;
|
|
|
|
}
|
|
|
|
/* child */
|
|
|
|
|
|
|
|
/* close pidfile in child */
|
|
|
|
if (opts->pidfile)
|
|
|
|
close(pidfd);
|
|
|
|
|
|
|
|
/* Initialize proxy before dropping privs */
|
|
|
|
proxy_ctx_t *proxy = proxy_new(opts, clisock[0]);
|
|
|
|
if (!proxy) {
|
|
|
|
log_err_printf("Failed to initialize proxy.\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop privs, chroot */
|
|
|
|
if (sys_privdrop(opts->dropuser, opts->dropgroup,
|
|
|
|
opts->jaildir) == -1) {
|
|
|
|
log_err_printf("Failed to drop privileges: %s (%i)\n",
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
ssl_reinit();
|
|
|
|
|
2012-10-16 22:24:26 +00:00
|
|
|
/* Post-privdrop/chroot/detach initialization, thread spawning */
|
2016-03-25 14:56:42 +00:00
|
|
|
if (log_init(opts, proxy, clisock[1], clisock[2]) == -1) {
|
2014-01-06 18:03:29 +00:00
|
|
|
fprintf(stderr, "%s: failed to init log facility: %s\n",
|
|
|
|
argv0, strerror(errno));
|
2012-10-23 19:30:11 +00:00
|
|
|
goto out_log_failed;
|
2012-10-16 22:24:26 +00:00
|
|
|
}
|
2012-10-16 21:05:37 +00:00
|
|
|
if (cachemgr_init() == -1) {
|
|
|
|
log_err_printf("Failed to init cache manager.\n");
|
2012-10-23 19:30:11 +00:00
|
|
|
goto out_cachemgr_failed;
|
2012-10-16 21:05:37 +00:00
|
|
|
}
|
2012-04-13 12:47:30 +00:00
|
|
|
if (nat_init() == -1) {
|
|
|
|
log_err_printf("Failed to init NAT state table lookup.\n");
|
2012-10-23 19:30:11 +00:00
|
|
|
goto out_nat_failed;
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
2012-10-23 19:30:11 +00:00
|
|
|
rv = EXIT_SUCCESS;
|
2012-10-16 22:10:47 +00:00
|
|
|
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> Enter proxy_run\n");
|
2012-04-13 12:47:30 +00:00
|
|
|
proxy_run(proxy);
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> Exit proxy_run\n");
|
2017-05-29 09:22:23 +00:00
|
|
|
|
2017-06-15 16:07:37 +00:00
|
|
|
log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>> main: EXIT closing privsep clisock=%d\n", clisock[0]);
|
2017-05-29 09:22:23 +00:00
|
|
|
privsep_client_close(clisock[0]);
|
|
|
|
|
2012-04-13 12:47:30 +00:00
|
|
|
proxy_free(proxy);
|
|
|
|
nat_fini();
|
2012-10-23 19:30:11 +00:00
|
|
|
out_nat_failed:
|
|
|
|
cachemgr_fini();
|
|
|
|
out_cachemgr_failed:
|
|
|
|
log_fini();
|
|
|
|
out_log_failed:
|
2014-11-24 21:01:52 +00:00
|
|
|
out_parent:
|
2012-04-13 12:47:30 +00:00
|
|
|
opts_free(opts);
|
|
|
|
ssl_fini();
|
2012-10-23 19:30:11 +00:00
|
|
|
return rv;
|
2012-04-13 12:47:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* vim: set noet ft=c: */
|