Ejemplo n.º 1
0
END_TEST

START_TEST(cache_fkcrt_04)
{
	X509 *c1, *c2;

	c1 = ssl_x509_load(TESTCERT);
	fail_unless(!!c1, "loading certificate failed");
	fail_unless(c1->references == 1, "refcount != 1");
	cachemgr_fkcrt_set(c1, c1);
	fail_unless(c1->references == 2, "refcount != 2");
	c2 = cachemgr_fkcrt_get(c1);
	fail_unless(c1->references == 3, "refcount != 3");
	cachemgr_fkcrt_set(c1, c1);
	fail_unless(c1->references == 3, "refcount != 3");
	cachemgr_fkcrt_del(c1);
	fail_unless(c1->references == 2, "refcount != 2");
	cachemgr_fkcrt_set(c1, c1);
	fail_unless(c1->references == 3, "refcount != 3");
	X509_free(c1);
	fail_unless(c1->references == 2, "refcount != 2");
	cachemgr_fini();
	fail_unless(c1->references == 1, "refcount != 1");
	X509_free(c2);
	/* deliberate access of free'd X509* */
	fail_unless(c1->references == 0, "refcount != 0");
	fail_unless(cachemgr_preinit() != -1, "reinit");
}
Ejemplo n.º 2
0
END_TEST

START_TEST(ssl_x509_names_01)
{
	X509 *c;
	char **names, **p;

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	names = ssl_x509_names(c);
	fail_unless(!!names, "parsing names failed");
	fail_unless(!!names[0], "first name");
	fail_unless(!strcmp(names[0], "daniel.roe.ch"), "first name");
	fail_unless(!!names[1], "second name");
	fail_unless(!strcmp(names[1], "daniel.roe.ch"), "second name");
	fail_unless(!!names[2], "third name");
	fail_unless(!strcmp(names[2], "www.roe.ch"), "third name");
	fail_unless(!!names[3], "fourth name");
	fail_unless(!strcmp(names[3], "*.roe.ch"), "fourth name");
	fail_unless(!names[4], "too many names");
	p = names;
	while (*p)
		free(*p++);
	free(names);
	X509_free(c);
}
Ejemplo n.º 3
0
END_TEST

START_TEST(ssl_key_identifier_sha1_01)
{
	X509 *c;
	EVP_PKEY *k;
	unsigned char keyid[SSL_KEY_IDSZ];

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	k = ssl_key_load(TESTKEY);
	fail_unless(!!k, "loading key failed");

	fail_unless(ssl_key_identifier_sha1(k, keyid) == 0,
	            "ssl_key_identifier_sha1() failed");

	int loc = X509_get_ext_by_NID(c, NID_subject_key_identifier, -1);
	X509_EXTENSION *ext = X509_get_ext(c, loc);
	fail_unless(!!ext, "loading ext failed");
	ASN1_STRING *value = X509_EXTENSION_get_data(ext);
	fail_unless(ASN1_STRING_length(value) - 2 == SSL_KEY_IDSZ,
	             "extension length mismatch");
	fail_unless(!memcmp(ASN1_STRING_get0_data(value) + 2, keyid, SSL_KEY_IDSZ),
	            "key id mismatch");
	EVP_PKEY_free(k);
	X509_free(c);
}
Ejemplo n.º 4
0
END_TEST

START_TEST(cache_fkcrt_02)
{
	X509 *c1, *c2;

	c1 = ssl_x509_load(TESTCERT);
	fail_unless(!!c1, "loading certificate failed");
	c2 = cachemgr_fkcrt_get(c1);
	fail_unless(c2 == NULL, "certificate was already in empty cache");
	X509_free(c1);
}
Ejemplo n.º 5
0
END_TEST

START_TEST(ssl_x509_ocsps_02)
{
	X509 *c;
	char **ocsps;

	c = ssl_x509_load(TESTCERT2);
	fail_unless(!!c, "loading certificate failed");
	ocsps = ssl_x509_ocsps(c);
	fail_unless(!ocsps, "unexpected OCSP extensions");
	X509_free(c);
}
Ejemplo n.º 6
0
END_TEST

START_TEST(cache_fkcrt_03)
{
	X509 *c1, *c2;

	c1 = ssl_x509_load(TESTCERT);
	fail_unless(!!c1, "loading certificate failed");
	cachemgr_fkcrt_set(c1, c1);
	cachemgr_fkcrt_del(c1);
	c2 = cachemgr_fkcrt_get(c1);
	fail_unless(c2 == NULL, "cache returned deleted certificate");
	X509_free(c1);
}
Ejemplo n.º 7
0
END_TEST

START_TEST(ssl_x509_names_to_str_02)
{
	X509 *c;
	char *names;

	c = ssl_x509_load(TESTCERT2);
	fail_unless(!!c, "loading certificate failed");
	names = ssl_x509_names_to_str(c);
	fail_unless(!!names, "no string");
	fail_unless(!strcmp(names, "SSLsplit Root CA"), "wrong name string");
	X509_free(c);
}
Ejemplo n.º 8
0
END_TEST

START_TEST(ssl_x509_subject_01)
{
	X509 *c;
	char *subject;

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	subject = ssl_x509_subject(c);
	fail_unless(!!subject, "no string");
	fail_unless(!strcmp(subject, "/C=CH/O=SSLsplit Test Certificate/"
	                             "CN=daniel.roe.ch"),
	            "wrong subject string");
	X509_free(c);
}
Ejemplo n.º 9
0
END_TEST

START_TEST(ssl_x509_names_to_str_01)
{
	X509 *c;
	char *names;

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	names = ssl_x509_names_to_str(c);
	fail_unless(!!names, "no string");
	fail_unless(!strcmp(names,
	            "daniel.roe.ch/daniel.roe.ch/www.roe.ch/*.roe.ch"),
	            "wrong name string");
	X509_free(c);
}
Ejemplo n.º 10
0
END_TEST

START_TEST(ssl_x509_refcount_inc_01)
{
	X509 *crt;

	crt = ssl_x509_load(TESTCERT);
	fail_unless(!!crt, "loading certificate failed");
	ssl_x509_refcount_inc(crt);
	ssl_x509_refcount_inc(crt);
	ssl_x509_refcount_inc(crt);
	X509_free(crt);
	/* these must not crash */
	X509_free(crt);
	X509_free(crt);
	X509_free(crt);
}
Ejemplo n.º 11
0
END_TEST

START_TEST(ssl_x509_ocsps_01)
{
	X509 *c;
	char **ocsps, **p;

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	ocsps = ssl_x509_ocsps(c);
	fail_unless(!!ocsps, "parsing OCSP extensions failed");
	fail_unless(!!ocsps[0], "first OCSP");
	fail_unless(!strcmp(ocsps[0], "http://daniel.roe.ch/test/ocsp"),
	                              "first OCSP");
	fail_unless(!ocsps[1], "too many OCSPs");
	p = ocsps;
	while (*p)
		free(*p++);
	free(ocsps);
	X509_free(c);
}
Ejemplo n.º 12
0
END_TEST

START_TEST(ssl_x509_subject_cn_01)
{
	X509 *c;
	char *cn;
	size_t sz;
	size_t expsz = strlen("daniel.roe.ch") + 1;

	c = ssl_x509_load(TESTCERT);
	fail_unless(!!c, "loading certificate failed");
	cn = ssl_x509_subject_cn(c, &sz);
	fail_unless(!!cn, "no string");
	fail_unless(sz >= expsz, "subject CN size too small");
	fail_unless(!strcmp(cn, "daniel.roe.ch"), "wrong subject CN string");
#if 0
	for (unsigned int i = expsz; i < sz; i++) {
		fail_unless(cn[i] == '\0', "extra byte != 0");
	}
#endif
	X509_free(c);
}
Ejemplo n.º 13
0
/*
 * Main entry point.
 */
int
main(int argc, char *argv[])
{
	const char *argv0;
	int ch;
	opts_t *opts;
	char *natengine;
	int pidfd = -1;
	int rv = EXIT_FAILURE;

	argv0 = argv[0];
	opts = opts_new();
	natengine = strdup(nat_getdefaultname());

	while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z
	                    "k:c:C:K:t:OPs:e:Eu:j:p:l:L:S:dDVh")) != -1) {
		switch (ch) {
			case 'c':
				if (opts->cacrt)
					X509_free(opts->cacrt);
				opts->cacrt = ssl_x509_load(optarg);
				if (!opts->cacrt) {
					fprintf(stderr, "%s: error loading CA "
					                "cert from '%s':\n",
					                argv0, optarg);
					if (errno) {
						fprintf(stderr, "%s\n",
						        strerror(errno));
					} else {
						ERR_print_errors_fp(stderr);
					}
					exit(EXIT_FAILURE);
				}
				ssl_x509_refcount_inc(opts->cacrt);
				sk_X509_insert(opts->chain, opts->cacrt, 0);
				if (!opts->cakey) {
					opts->cakey = ssl_key_load(optarg);
				}
#ifndef OPENSSL_NO_DH
				if (!opts->dh) {
					opts->dh = ssl_dh_load(optarg);
				}
#endif /* !OPENSSL_NO_DH */
				break;
			case 'k':
				if (opts->cakey)
					EVP_PKEY_free(opts->cakey);
				opts->cakey = ssl_key_load(optarg);
				if (!opts->cakey) {
					fprintf(stderr, "%s: error loading CA "
					                "key from '%s':\n",
					                argv0, optarg);
					if (errno) {
						fprintf(stderr, "%s\n",
						        strerror(errno));
					} else {
						ERR_print_errors_fp(stderr);
					}
					exit(EXIT_FAILURE);
				}
				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);
					}
				}
#ifndef OPENSSL_NO_DH
				if (!opts->dh) {
					opts->dh = ssl_dh_load(optarg);
				}
#endif /* !OPENSSL_NO_DH */
				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);
				break;
			case 'O':
				opts->deny_ocsp = 1;
				break;
			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':
			{
				EC_KEY *ec;
				if (opts->ecdhcurve)
					free(opts->ecdhcurve);
				if (!(ec = ssl_ec_by_name(optarg))) {
					fprintf(stderr, "%s: unknown curve "
					                "'%s'\n",
					                argv0, optarg);
					exit(EXIT_FAILURE);
				}
				EC_KEY_free(ec);
				opts->ecdhcurve = strdup(optarg);
				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);
				break;
			case 'e':
				free(natengine);
				natengine = strdup(optarg);
				break;
			case 'E':
				nat_list_engines();
				exit(EXIT_SUCCESS);
				break;
			case 'u':
				if (opts->dropuser)
					free(opts->dropuser);
				opts->dropuser = strdup(optarg);
				break;
			case 'p':
				if (opts->pidfile)
					free(opts->pidfile);
				opts->pidfile = strdup(optarg);
				break;
			case 'j':
				if (opts->jaildir)
					free(opts->jaildir);
				opts->jaildir = strdup(optarg);
				break;
			case 'l':
				if (opts->connectlog)
					free(opts->connectlog);
				opts->connectlog = strdup(optarg);
				break;
			case 'L':
				if (opts->contentlog)
					free(opts->contentlog);
				opts->contentlog = strdup(optarg);
				opts->contentlogdir = 0;
				break;
			case 'S':
				if (opts->contentlog)
					free(opts->contentlog);
				opts->contentlog = strdup(optarg);
				opts->contentlogdir = 1;
				break;
			case 'd':
				opts->detach = 1;
				break;
			case 'D':
				log_dbg_mode(LOG_DBG_MODE_ERRLOG);
				opts->debug = 1;
				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);

	/* usage checks */
	if (opts->detach && OPTS_DEBUG(opts)) {
		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);
	}
	for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
		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);
		}
		spec->natlookup = nat_getlookupcb(spec->natengine);
		spec->natsocket = nat_getsocketcb(spec->natengine);
	}
	if (opts_has_ssl_spec(opts)) {
		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);
		}
	}

	/* 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);
		}
	}

	/* dynamic defaults */
	if (!opts->ciphers) {
		opts->ciphers = strdup("ALL:-aNULL");
		if (!opts->ciphers) {
			fprintf(stderr, "%s: out of memory.\n", argv0);
			exit(EXIT_FAILURE);
		}
	}
	if (!opts->jaildir && (geteuid() == 0) && !opts->contentlogdir) {
		opts->jaildir = strdup("/var/empty");
	}
	if (!opts->dropuser && !geteuid() && !getuid() &&
	    !opts->contentlogdir) {
		opts->dropuser = strdup("nobody");
	}
	if (opts_has_ssl_spec(opts) && !opts->key) {
		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");
		}
	}

	/* debugging */
	if (OPTS_DEBUG(opts)) {
		main_version();
		log_dbg_printf("proxyspecs:\n");
		for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
			char *lbuf, *cbuf = NULL;
			lbuf = sys_sockaddr_str((struct sockaddr *)
			                        &spec->listen_addr,
			                        spec->listen_addrlen);
			if (spec->connect_addrlen) {
				cbuf = sys_sockaddr_str((struct sockaddr *)
				                        &spec->connect_addr,
				                        spec->connect_addrlen);
			}
			if (spec->sni_port) {
				asprintf(&cbuf, "sni %i", spec->sni_port);
			}
			log_dbg_printf("- %s %s %s %s\n", lbuf,
			               (spec->ssl ? "ssl" : "tcp"),
			               (spec->http ? "http" : "plain"),
			               (spec->natengine ? spec->natengine
			                                : cbuf));
			if (lbuf)
				free(lbuf);
			if (cbuf)
				free(cbuf);
		}
		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");
		}
	}

	/*
	 * Initialize as much as possible before daemon() in order to be
	 * able to provide direct feedback to the user when failing.
	 */
	if (cachemgr_preinit() == -1) {
		fprintf(stderr, "%s: failed to preinit cachemgr.\n", argv0);
		exit(EXIT_FAILURE);
	}
	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);
	}

	/* Bind listeners before dropping privileges */
	proxy_ctx_t *proxy = proxy_new(opts);
	if (!proxy) {
		fprintf(stderr, "%s: failed to initialize proxy.\n", argv0);
		exit(EXIT_FAILURE);
	}

	/* Drop privs, chroot, detach from TTY */
	if (sys_privdrop(opts->dropuser, opts->jaildir) == -1) {
		fprintf(stderr, "%s: failed to drop privileges: %s\n",
		                argv0, strerror(errno));
		exit(EXIT_FAILURE);
	}
	if (opts->detach) {
		if (OPTS_DEBUG(opts)) {
			log_dbg_printf("Detaching from TTY, see syslog for "
			               "errors after this point\n");
		}
		if (daemon(1, 0) == -1) {
			fprintf(stderr, "%s: failed to detach from TTY: %s\n",
			                argv0, strerror(errno));
			exit(EXIT_FAILURE);
		}
		log_err_mode(LOG_ERR_MODE_SYSLOG);
		ssl_reinit();
	}

	/* Post-privdrop/chroot/detach initialization, thread spawning */
	if (log_init(opts) == -1) {
		fprintf(stderr, "%s: failed to init log facility.\n", argv0);
		goto out_log_failed;
	}
	if (opts->pidfile && (sys_pidf_write(pidfd) == -1)) {
		log_err_printf("Failed to write PID to PID file '%s': %s\n",
		               opts->pidfile, strerror(errno));
		goto out_pidwrite_failed;
	}
	if (cachemgr_init() == -1) {
		log_err_printf("Failed to init cache manager.\n");
		goto out_cachemgr_failed;
	}
	if (nat_init() == -1) {
		log_err_printf("Failed to init NAT state table lookup.\n");
		goto out_nat_failed;
	}

	if (opts->tgcrtdir) {
		sys_dir_eachfile(opts->tgcrtdir, main_loadtgcrt, opts);
	}

	rv = EXIT_SUCCESS;

	proxy_run(proxy);
	proxy_free(proxy);
	nat_fini();
out_nat_failed:
	cachemgr_fini();
out_cachemgr_failed:
	if (opts->pidfile) {
		sys_pidf_close(pidfd, opts->pidfile);
	}
out_pidwrite_failed:
	log_fini();
out_log_failed:
	opts_free(opts);
	ssl_fini();
	return rv;
}
Ejemplo n.º 14
0
int load_config() {
	string tmp;
	vector<string> splited;
	int tmpSize, tmpPort;

	if(configFilePath[0] == '\0') {
		strcpy(configFilePath, DEFAULT_CONFIG_FILE_PATH);
	}

	if(!options.read_options_file(configFilePath)) {
		log_message(ERROR_LOG, "Couldn't read configuration file %s.", configFilePath);
		return 1;
	}

	tmp = options["logLevel"];
	config.logLevel = atoi(tmp.c_str());

	tmp = options["maxClients"];
	config.maxClients = atoi(tmp.c_str());

	config.logFilePath = options["logFilePath"];

	tmp = options["bindPort"];
	config.bindPort = atoi(tmp.c_str());

	tmp = options["sslPorts"];
	splited = split(tmp, ',');
	tmpSize = splited.size();
	for(int i=0; i<tmpSize; i++) {
		tmpPort = atoi(splited.at(i).c_str());
		if((tmpPort >= 0) && (tmpPort <= 65535)) {
			config.sslPorts.push_back(tmpPort);
		}
	}

	/* load certificate */
	tmp = options["cacrt"];
	config.cacrt = ssl_x509_load(tmp.c_str());
	if(!config.cacrt) {
		log_message(ERROR_LOG, "Could not loading ca crt %s.", tmp.c_str());
		return 1;
	}

	config.chain = sk_X509_new_null();
	ssl_x509_refcount_inc(config.cacrt);
	sk_X509_insert(config.chain, config.cacrt, 0);

	tmp = options["cakey"];
	config.cakey = ssl_key_load(tmp.c_str());
	if (!config.cakey) {
		log_message(ERROR_LOG, "Could not loading ca key %s.", tmp.c_str());
		return 1;
	}

	tmp = options["leafkey"];
	config.key = ssl_key_load(tmp.c_str());
	if (!config.key) {
		log_message(ERROR_LOG, "Could not loading leaf key %s.", tmp.c_str());
		return 1;
	}

	config.ciphers = strdup("ALL:-aNULL");
	if (!config.ciphers) {
		log_message(ERROR_LOG, "Could not malloc ciphers.");
		return 1;
	}

	tmp = options["contentLogDir"];
	config.contentLogDir = strdup(tmp.c_str());
	if (!config.contentLogDir) {
		log_message(ERROR_LOG, "Could not malloc contentLogDir.");
		return 1;
	}

	if (!sys_isdir(config.contentLogDir)) {
		log_message(ERROR_LOG, "%s is not a directory.", config.contentLogDir);
		return 1;
	}

	return 0;
}