1 /*-
2  * SSLsplit - transparent SSL/TLS interception
3  * https://www.roe.ch/SSLsplit
4  *
5  * Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "opts.h"
30 
31 #include "sys.h"
32 #include "log.h"
33 
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 
38 #ifndef OPENSSL_NO_DH
39 #include <openssl/dh.h>
40 #endif /* !OPENSSL_NO_DH */
41 #include <openssl/x509.h>
42 
43 /*
44  * Handle out of memory conditions in early stages of main().
45  * Print error message and exit with failure status code.
46  * Does not return.
47  */
48 void NORET
oom_die(const char * argv0)49 oom_die(const char *argv0)
50 {
51 	fprintf(stderr, "%s: out of memory\n", argv0);
52 	exit(EXIT_FAILURE);
53 }
54 
55 /*
56  * Load a cert/chain/key combo from a single PEM file.
57  * Returns NULL on failure.
58  */
59 cert_t *
opts_load_cert_chain_key(const char * filename)60 opts_load_cert_chain_key(const char *filename)
61 {
62 	cert_t *cert;
63 
64 	cert = cert_new_load(filename);
65 	if (!cert) {
66 		log_err_printf("Failed to load cert and key from PEM file "
67 		                "'%s'\n", filename);
68 		return NULL;
69 	}
70 	if (X509_check_private_key(cert->crt, cert->key) != 1) {
71 		log_err_printf("Cert does not match key in PEM file "
72 		                "'%s':\n", filename);
73 		ERR_print_errors_fp(stderr);
74 		return NULL;
75 	}
76 
77 #ifdef DEBUG_CERTIFICATE
78 	log_dbg_printf("Loaded '%s':\n", filename);
79 	log_dbg_print_free(ssl_x509_to_str(cert->crt));
80 	log_dbg_print_free(ssl_x509_to_pem(cert->crt));
81 #endif /* DEBUG_CERTIFICATE */
82 	return cert;
83 }
84 
85 opts_t *
opts_new(void)86 opts_new(void)
87 {
88 	opts_t *opts;
89 
90 	opts = malloc(sizeof(opts_t));
91 	memset(opts, 0, sizeof(opts_t));
92 
93 	opts->sslcomp = 1;
94 	opts->cachain = sk_X509_new_null();
95 	opts->sslmethod = SSLv23_method;
96 	opts->allow_wrong_host = 1;
97 
98 	return opts;
99 }
100 
101 void
opts_free(opts_t * opts)102 opts_free(opts_t *opts)
103 {
104 	if (opts->clientcrt) {
105 		X509_free(opts->clientcrt);
106 	}
107 	if (opts->clientkey) {
108 		EVP_PKEY_free(opts->clientkey);
109 	}
110 	if (opts->cacrt) {
111 		X509_free(opts->cacrt);
112 	}
113 	if (opts->cakey) {
114 		EVP_PKEY_free(opts->cakey);
115 	}
116 	sk_X509_pop_free(opts->cachain, X509_free);
117 	if (opts->leafkey) {
118 		EVP_PKEY_free(opts->leafkey);
119 	}
120 	if (opts->leafcertdir) {
121 		free(opts->leafcertdir);
122 	}
123 	if (opts->defaultleafcert) {
124 		cert_free(opts->defaultleafcert);
125 	}
126 	if (opts->leafcrlurl) {
127 		free(opts->leafcrlurl);
128 	}
129 #ifndef OPENSSL_NO_DH
130 	if (opts->dh) {
131 		DH_free(opts->dh);
132 	}
133 #endif /* !OPENSSL_NO_DH */
134 #ifndef OPENSSL_NO_ECDH
135 	if (opts->ecdhcurve) {
136 		free(opts->ecdhcurve);
137 	}
138 #endif /* !OPENSSL_NO_ECDH */
139 	if (opts->spec) {
140 		proxyspec_free(opts->spec);
141 	}
142 	if (opts->ciphers) {
143 		free(opts->ciphers);
144 	}
145 #ifndef OPENSSL_NO_ENGINE
146 	if (opts->openssl_engine) {
147 		free(opts->openssl_engine);
148 	}
149 #endif /* !OPENSSL_NO_ENGINE */
150 	if (opts->dropuser) {
151 		free(opts->dropuser);
152 	}
153 	if (opts->dropgroup) {
154 		free(opts->dropgroup);
155 	}
156 	if (opts->jaildir) {
157 		free(opts->jaildir);
158 	}
159 	if (opts->pidfile) {
160 		free(opts->pidfile);
161 	}
162 	if (opts->connectlog) {
163 		free(opts->connectlog);
164 	}
165 	if (opts->contentlog) {
166 		free(opts->contentlog);
167 	}
168 	if (opts->certgendir) {
169 		free(opts->certgendir);
170 	}
171 	if (opts->contentlog_basedir) {
172 		free(opts->contentlog_basedir);
173 	}
174 	if (opts->masterkeylog) {
175 		free(opts->masterkeylog);
176 	}
177 	if (opts->pcaplog) {
178 		free(opts->pcaplog);
179 	}
180 	if (opts->pcaplog_basedir) {
181 		free(opts->pcaplog_basedir);
182 	}
183 #ifndef WITHOUT_MIRROR
184 	if (opts->mirrorif) {
185 		free(opts->mirrorif);
186 	}
187 	if (opts->mirrortarget) {
188 		free(opts->mirrortarget);
189 	}
190 #endif /* !WITHOUT_MIRROR */
191 	memset(opts, 0, sizeof(opts_t));
192 	free(opts);
193 }
194 
195 /*
196  * Return 1 if opts_t contains a proxyspec that (eventually) uses SSL/TLS,
197  * 0 otherwise.  When 0, it is safe to assume that no SSL/TLS operations
198  * will take place with this configuration.
199  */
200 int
opts_has_ssl_spec(opts_t * opts)201 opts_has_ssl_spec(opts_t *opts)
202 {
203 	proxyspec_t *p = opts->spec;
204 
205 	while (p) {
206 		if (p->ssl || p->upgrade)
207 			return 1;
208 		p = p->next;
209 	}
210 
211 	return 0;
212 }
213 
214 /*
215  * Return 1 if opts_t contains a proxyspec with dns, 0 otherwise.
216  */
217 int
opts_has_dns_spec(opts_t * opts)218 opts_has_dns_spec(opts_t *opts)
219 {
220 	proxyspec_t *p = opts->spec;
221 
222 	while (p) {
223 		if (p->dns)
224 			return 1;
225 		p = p->next;
226 	}
227 
228 	return 0;
229 }
230 
231 /*
232  * Dump the SSL/TLS protocol related configuration to the debug log.
233  */
234 void
opts_proto_dbg_dump(opts_t * opts)235 opts_proto_dbg_dump(opts_t *opts)
236 {
237 	log_dbg_printf("SSL/TLS protocol: %s%s%s%s%s%s\n",
238 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
239 #ifdef HAVE_SSLV2
240 	               (opts->sslmethod == SSLv2_method) ? "ssl2" :
241 #endif /* HAVE_SSLV2 */
242 #ifdef HAVE_SSLV3
243 	               (opts->sslmethod == SSLv3_method) ? "ssl3" :
244 #endif /* HAVE_SSLV3 */
245 #ifdef HAVE_TLSV10
246 	               (opts->sslmethod == TLSv1_method) ? "tls10" :
247 #endif /* HAVE_TLSV10 */
248 #ifdef HAVE_TLSV11
249 	               (opts->sslmethod == TLSv1_1_method) ? "tls11" :
250 #endif /* HAVE_TLSV11 */
251 #ifdef HAVE_TLSV12
252 	               (opts->sslmethod == TLSv1_2_method) ? "tls12" :
253 #endif /* HAVE_TLSV12 */
254 #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
255 #ifdef HAVE_SSLV3
256 	               (opts->sslversion == SSL3_VERSION) ? "ssl3" :
257 #endif /* HAVE_SSLV3 */
258 #ifdef HAVE_TLSV10
259 	               (opts->sslversion == TLS1_VERSION) ? "tls10" :
260 #endif /* HAVE_TLSV10 */
261 #ifdef HAVE_TLSV11
262 	               (opts->sslversion == TLS1_1_VERSION) ? "tls11" :
263 #endif /* HAVE_TLSV11 */
264 #ifdef HAVE_TLSV12
265 	               (opts->sslversion == TLS1_2_VERSION) ? "tls12" :
266 #endif /* HAVE_TLSV12 */
267 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
268 	               "negotiate",
269 #ifdef HAVE_SSLV2
270 	               opts->no_ssl2 ? " -ssl2" :
271 #endif /* HAVE_SSLV2 */
272 	               "",
273 #ifdef HAVE_SSLV3
274 	               opts->no_ssl3 ? " -ssl3" :
275 #endif /* HAVE_SSLV3 */
276 	               "",
277 #ifdef HAVE_TLSV10
278 	               opts->no_tls10 ? " -tls10" :
279 #endif /* HAVE_TLSV10 */
280 	               "",
281 #ifdef HAVE_TLSV11
282 	               opts->no_tls11 ? " -tls11" :
283 #endif /* HAVE_TLSV11 */
284 	               "",
285 #ifdef HAVE_TLSV12
286 	               opts->no_tls12 ? " -tls12" :
287 #endif /* HAVE_TLSV12 */
288 	               "");
289 }
290 
291 /*
292  * Parse proxyspecs using a simple state machine.
293  */
294 void
proxyspec_parse(int * argc,char ** argv[],const char * natengine,proxyspec_t ** opts_spec)295 proxyspec_parse(int *argc, char **argv[], const char *natengine,
296                 proxyspec_t **opts_spec)
297 {
298 	proxyspec_t *spec = NULL;
299 	char *addr = NULL;
300 	int af = AF_UNSPEC;
301 	int state = 0;
302 
303 	while ((*argc)--) {
304 		switch (state) {
305 			default:
306 			case 0:
307 				/* tcp | ssl | http | https | autossl */
308 				spec = malloc(sizeof(proxyspec_t));
309 				memset(spec, 0, sizeof(proxyspec_t));
310 				spec->next = *opts_spec;
311 				*opts_spec = spec;
312 
313 				/* Defaults */
314 				spec->ssl = 0;
315 				spec->http = 0;
316 				spec->upgrade = 0;
317 				if (!strcmp(**argv, "tcp")) {
318 					/* use defaults */
319 				} else
320 				if (!strcmp(**argv, "ssl")) {
321 					spec->ssl = 1;
322 				} else
323 				if (!strcmp(**argv, "http")) {
324 					spec->http = 1;
325 				} else
326 				if (!strcmp(**argv, "https")) {
327 					spec->ssl = 1;
328 					spec->http = 1;
329 				} else
330 				if (!strcmp(**argv, "autossl")) {
331 					spec->upgrade = 1;
332 				} else {
333 					fprintf(stderr, "Unknown connection "
334 					                "type '%s'\n", **argv);
335 					exit(EXIT_FAILURE);
336 				}
337 				state++;
338 				break;
339 			case 1:
340 				/* listenaddr */
341 				addr = **argv;
342 				state++;
343 				break;
344 			case 2:
345 				/* listenport */
346 				af = sys_sockaddr_parse(&spec->listen_addr,
347 				                        &spec->listen_addrlen,
348 				                        addr, **argv,
349 				                        sys_get_af(addr),
350 				                        EVUTIL_AI_PASSIVE);
351 				if (af == -1) {
352 					exit(EXIT_FAILURE);
353 				}
354 				if (natengine) {
355 					spec->natengine = strdup(natengine);
356 					if (!spec->natengine) {
357 						fprintf(stderr,
358 						        "Out of memory"
359 						        "\n");
360 						exit(EXIT_FAILURE);
361 					}
362 				} else {
363 					spec->natengine = NULL;
364 				}
365 				state++;
366 				break;
367 			case 3:
368 				/* [ natengine | dstaddr ] */
369 				if (!strcmp(**argv, "tcp") ||
370 				    !strcmp(**argv, "ssl") ||
371 				    !strcmp(**argv, "http") ||
372 				    !strcmp(**argv, "https") ||
373 				    !strcmp(**argv, "autossl")) {
374 					/* implicit default natengine */
375 					(*argv)--; (*argc)++; /* rewind */
376 					state = 0;
377 				} else
378 				if (!strcmp(**argv, "sni")) {
379 					free(spec->natengine);
380 					spec->natengine = NULL;
381 					if (!spec->ssl) {
382 						fprintf(stderr,
383 						        "SNI hostname lookup "
384 						        "only works for ssl "
385 						        "and https proxyspecs"
386 						        "\n");
387 						exit(EXIT_FAILURE);
388 					}
389 					state = 5;
390 				} else
391 				if (nat_exist(**argv)) {
392 					/* natengine */
393 					free(spec->natengine);
394 					spec->natengine = strdup(**argv);
395 					if (!spec->natengine) {
396 						fprintf(stderr,
397 						        "Out of memory"
398 						        "\n");
399 						exit(EXIT_FAILURE);
400 					}
401 					state = 0;
402 				} else {
403 					/* explicit target address */
404 					free(spec->natengine);
405 					spec->natengine = NULL;
406 					addr = **argv;
407 					state++;
408 				}
409 				break;
410 			case 4:
411 				/* dstport */
412 				af = sys_sockaddr_parse(&spec->connect_addr,
413 				                        &spec->connect_addrlen,
414 				                        addr, **argv, af, 0);
415 				if (af == -1) {
416 					exit(EXIT_FAILURE);
417 				}
418 				state = 0;
419 				break;
420 			case 5:
421 				/* SNI dstport */
422 				spec->sni_port = atoi(**argv);
423 				if (!spec->sni_port) {
424 					fprintf(stderr, "Invalid port '%s'\n",
425 					                **argv);
426 					exit(EXIT_FAILURE);
427 				}
428 				spec->dns = 1;
429 				state = 0;
430 				break;
431 		}
432 		(*argv)++;
433 	}
434 	if (state != 0 && state != 3) {
435 		fprintf(stderr, "Incomplete proxyspec!\n");
436 		exit(EXIT_FAILURE);
437 	}
438 }
439 
440 /*
441  * Clear and free a proxy spec.
442  */
443 void
proxyspec_free(proxyspec_t * spec)444 proxyspec_free(proxyspec_t *spec)
445 {
446 	do {
447 		proxyspec_t *next = spec->next;
448 		if (spec->natengine)
449 			free(spec->natengine);
450 		memset(spec, 0, sizeof(proxyspec_t));
451 		free(spec);
452 		spec = next;
453 	} while (spec);
454 }
455 
456 /*
457  * Return text representation of proxy spec for display to the user.
458  * Returned string must be freed by caller.
459  */
460 char *
proxyspec_str(proxyspec_t * spec)461 proxyspec_str(proxyspec_t *spec)
462 {
463 	char *s;
464 	char *lhbuf, *lpbuf;
465 	char *cbuf = NULL;
466 	if (sys_sockaddr_str((struct sockaddr *)&spec->listen_addr,
467 	                     spec->listen_addrlen, &lhbuf, &lpbuf) != 0) {
468 		return NULL;
469 	}
470 	if (spec->connect_addrlen) {
471 		char *chbuf, *cpbuf;
472 		if (sys_sockaddr_str((struct sockaddr *)&spec->connect_addr,
473 		                     spec->connect_addrlen,
474 		                     &chbuf, &cpbuf) != 0) {
475 			return NULL;
476 		}
477 		if (asprintf(&cbuf, "[%s]:%s", chbuf, cpbuf) < 0) {
478 			return NULL;
479 		}
480 		free(chbuf);
481 		free(cpbuf);
482 	}
483 	if (spec->sni_port) {
484 		if (asprintf(&cbuf, "sni %i", spec->sni_port) < 0) {
485 			return NULL;
486 		}
487 	}
488 	if (asprintf(&s, "[%s]:%s %s%s%s %s", lhbuf, lpbuf,
489 	             (spec->ssl ? "ssl" : "tcp"),
490 	             (spec->upgrade ? "|upgrade" : ""),
491 	             (spec->http ? "|http" : ""),
492 	             (spec->natengine ? spec->natengine : cbuf)) < 0) {
493 		s = NULL;
494 	}
495 	free(lhbuf);
496 	free(lpbuf);
497 	if (cbuf)
498 		free(cbuf);
499 	return s;
500 }
501 
502 void
opts_set_cacrt(opts_t * opts,const char * argv0,const char * optarg)503 opts_set_cacrt(opts_t *opts, const char *argv0, const char *optarg)
504 {
505 	if (opts->cacrt)
506 		X509_free(opts->cacrt);
507 	opts->cacrt = ssl_x509_load(optarg);
508 	if (!opts->cacrt) {
509 		fprintf(stderr, "%s: error loading CA cert from '%s':\n",
510 		        argv0, optarg);
511 		if (errno) {
512 			fprintf(stderr, "%s\n", strerror(errno));
513 		} else {
514 			ERR_print_errors_fp(stderr);
515 		}
516 		exit(EXIT_FAILURE);
517 	}
518 	ssl_x509_refcount_inc(opts->cacrt);
519 	sk_X509_insert(opts->cachain, opts->cacrt, 0);
520 	if (!opts->cakey) {
521 		opts->cakey = ssl_key_load(optarg);
522 	}
523 #ifndef OPENSSL_NO_DH
524 	if (!opts->dh) {
525 		opts->dh = ssl_dh_load(optarg);
526 	}
527 #endif /* !OPENSSL_NO_DH */
528 #ifdef DEBUG_OPTS
529 	log_dbg_printf("CACert: %s\n", optarg);
530 #endif /* DEBUG_OPTS */
531 }
532 
533 void
opts_set_cakey(opts_t * opts,const char * argv0,const char * optarg)534 opts_set_cakey(opts_t *opts, const char *argv0, const char *optarg)
535 {
536 	if (opts->cakey)
537 		EVP_PKEY_free(opts->cakey);
538 	opts->cakey = ssl_key_load(optarg);
539 	if (!opts->cakey) {
540 		fprintf(stderr, "%s: error loading CA key from '%s':\n",
541 		        argv0, optarg);
542 		if (errno) {
543 			fprintf(stderr, "%s\n", strerror(errno));
544 		} else {
545 			ERR_print_errors_fp(stderr);
546 		}
547 		exit(EXIT_FAILURE);
548 	}
549 	if (!opts->cacrt) {
550 		opts->cacrt = ssl_x509_load(optarg);
551 		if (opts->cacrt) {
552 			ssl_x509_refcount_inc(opts->cacrt);
553 			sk_X509_insert(opts->cachain, opts->cacrt, 0);
554 		}
555 	}
556 #ifndef OPENSSL_NO_DH
557 	if (!opts->dh) {
558 		opts->dh = ssl_dh_load(optarg);
559 	}
560 #endif /* !OPENSSL_NO_DH */
561 #ifdef DEBUG_OPTS
562 	log_dbg_printf("CAKey: %s\n", optarg);
563 #endif /* DEBUG_OPTS */
564 }
565 
566 void
opts_set_cachain(opts_t * opts,const char * argv0,const char * optarg)567 opts_set_cachain(opts_t *opts, const char *argv0, const char *optarg)
568 {
569 	if (ssl_x509chain_load(NULL, &opts->cachain, optarg) == -1) {
570 		fprintf(stderr, "%s: error loading CA chain from '%s':\n",
571 		        argv0, optarg);
572 		if (errno) {
573 			fprintf(stderr, "%s\n", strerror(errno));
574 		} else {
575 			ERR_print_errors_fp(stderr);
576 		}
577 		exit(EXIT_FAILURE);
578 	}
579 #ifdef DEBUG_OPTS
580 	log_dbg_printf("CAChain: %s\n", optarg);
581 #endif /* DEBUG_OPTS */
582 }
583 
584 void
opts_set_leafkey(opts_t * opts,const char * argv0,const char * optarg)585 opts_set_leafkey(opts_t *opts, const char *argv0, const char *optarg)
586 {
587 	if (opts->leafkey)
588 		EVP_PKEY_free(opts->leafkey);
589 	opts->leafkey = ssl_key_load(optarg);
590 	if (!opts->leafkey) {
591 		fprintf(stderr, "%s: error loading leaf key from '%s':\n",
592 		        argv0, optarg);
593 		if (errno) {
594 			fprintf(stderr, "%s\n", strerror(errno));
595 		} else {
596 			ERR_print_errors_fp(stderr);
597 		}
598 		exit(EXIT_FAILURE);
599 	}
600 #ifndef OPENSSL_NO_DH
601 	if (!opts->dh) {
602 		opts->dh = ssl_dh_load(optarg);
603 	}
604 #endif /* !OPENSSL_NO_DH */
605 #ifdef DEBUG_OPTS
606 	log_dbg_printf("LeafKey: %s\n", optarg);
607 #endif /* DEBUG_OPTS */
608 }
609 
610 void
opts_set_leafcrlurl(opts_t * opts,const char * optarg)611 opts_set_leafcrlurl(opts_t *opts, const char *optarg)
612 {
613 	if (opts->leafcrlurl)
614 		free(opts->leafcrlurl);
615 	opts->leafcrlurl = strdup(optarg);
616 #ifdef DEBUG_OPTS
617 	log_dbg_printf("LeafCRLURL: %s\n", opts->leafcrlurl);
618 #endif /* DEBUG_OPTS */
619 }
620 
621 void
opts_set_leafcertdir(opts_t * opts,const char * argv0,const char * optarg)622 opts_set_leafcertdir(opts_t *opts, const char *argv0, const char *optarg)
623 {
624 	if (!sys_isdir(optarg)) {
625 		fprintf(stderr, "%s: '%s' is not a directory\n",
626 		        argv0, optarg);
627 		exit(EXIT_FAILURE);
628 	}
629 	if (opts->leafcertdir)
630 		free(opts->leafcertdir);
631 	opts->leafcertdir = strdup(optarg);
632 	if (!opts->leafcertdir)
633 		oom_die(argv0);
634 #ifdef DEBUG_OPTS
635 	log_dbg_printf("LeafCertDir: %s\n", opts->leafcertdir);
636 #endif /* DEBUG_OPTS */
637 }
638 
639 void
opts_set_defaultleafcert(opts_t * opts,const char * argv0,const char * optarg)640 opts_set_defaultleafcert(opts_t *opts, const char *argv0, const char *optarg)
641 {
642 	if (opts->defaultleafcert)
643 		cert_free(opts->defaultleafcert);
644 	opts->defaultleafcert = opts_load_cert_chain_key(optarg);
645 	if (!opts->defaultleafcert) {
646 		fprintf(stderr, "%s: error loading default leaf cert/chain/key"
647 		                " from '%s':\n", argv0, optarg);
648 		if (errno) {
649 			fprintf(stderr, "%s\n", strerror(errno));
650 		} else {
651 			ERR_print_errors_fp(stderr);
652 		}
653 		exit(EXIT_FAILURE);
654 	}
655 #ifdef DEBUG_OPTS
656 	log_dbg_printf("DefaultLeafCert: %s\n", optarg);
657 #endif /* DEBUG_OPTS */
658 }
659 
660 static void
set_certgendir(opts_t * opts,const char * argv0,const char * optarg)661 set_certgendir(opts_t *opts, const char *argv0, const char *optarg)
662 {
663 	if (opts->certgendir)
664 		free(opts->certgendir);
665 	opts->certgendir = strdup(optarg);
666 	if (!opts->certgendir)
667 		oom_die(argv0);
668 }
669 
670 void
opts_set_certgendir_writegencerts(opts_t * opts,const char * argv0,const char * optarg)671 opts_set_certgendir_writegencerts(opts_t *opts, const char *argv0,
672                                   const char *optarg)
673 {
674 	opts->certgen_writeall = 0;
675 	set_certgendir(opts, argv0, optarg);
676 #ifdef DEBUG_OPTS
677 	log_dbg_printf("WriteGenCertsDir: certgendir=%s, writeall=%u\n",
678 	               opts->certgendir, opts->certgen_writeall);
679 #endif /* DEBUG_OPTS */
680 }
681 
682 void
opts_set_certgendir_writeall(opts_t * opts,const char * argv0,const char * optarg)683 opts_set_certgendir_writeall(opts_t *opts, const char *argv0,
684                              const char *optarg)
685 {
686 	opts->certgen_writeall = 1;
687 	set_certgendir(opts, argv0, optarg);
688 #ifdef DEBUG_OPTS
689 	log_dbg_printf("WriteAllCertsDir: certgendir=%s, writeall=%u\n",
690 	               opts->certgendir, opts->certgen_writeall);
691 #endif /* DEBUG_OPTS */
692 }
693 
694 void
opts_set_deny_ocsp(opts_t * opts)695 opts_set_deny_ocsp(opts_t *opts)
696 {
697 	opts->deny_ocsp = 1;
698 }
699 
700 void
opts_unset_deny_ocsp(opts_t * opts)701 opts_unset_deny_ocsp(opts_t *opts)
702 {
703 	opts->deny_ocsp = 0;
704 }
705 
706 void
opts_set_passthrough(opts_t * opts)707 opts_set_passthrough(opts_t *opts)
708 {
709 	opts->passthrough = 1;
710 }
711 
712 void
opts_unset_passthrough(opts_t * opts)713 opts_unset_passthrough(opts_t *opts)
714 {
715 	opts->passthrough = 0;
716 }
717 
718 void
opts_set_clientcrt(opts_t * opts,const char * argv0,const char * optarg)719 opts_set_clientcrt(opts_t *opts, const char *argv0, const char *optarg)
720 {
721 	if (opts->clientcrt)
722 		X509_free(opts->clientcrt);
723 	opts->clientcrt = ssl_x509_load(optarg);
724 	if (!opts->clientcrt) {
725 		fprintf(stderr, "%s: error loading client cert from '%s':\n",
726 		        argv0, optarg);
727 		if (errno) {
728 			fprintf(stderr, "%s\n", strerror(errno));
729 		} else {
730 			ERR_print_errors_fp(stderr);
731 		}
732 		exit(EXIT_FAILURE);
733 	}
734 #ifdef DEBUG_OPTS
735 	log_dbg_printf("ClientCert: %s\n", optarg);
736 #endif /* DEBUG_OPTS */
737 }
738 
739 void
opts_set_clientkey(opts_t * opts,const char * argv0,const char * optarg)740 opts_set_clientkey(opts_t *opts, const char *argv0, const char *optarg)
741 {
742 	if (opts->clientkey)
743 		EVP_PKEY_free(opts->clientkey);
744 	opts->clientkey = ssl_key_load(optarg);
745 	if (!opts->clientkey) {
746 		fprintf(stderr, "%s: error loading client key from '%s':\n",
747 		        argv0, optarg);
748 		if (errno) {
749 			fprintf(stderr, "%s\n", strerror(errno));
750 		} else {
751 			ERR_print_errors_fp(stderr);
752 		}
753 		exit(EXIT_FAILURE);
754 	}
755 #ifdef DEBUG_OPTS
756 	log_dbg_printf("ClientKey: %s\n", optarg);
757 #endif /* DEBUG_OPTS */
758 }
759 
760 #ifndef OPENSSL_NO_DH
761 void
opts_set_dh(opts_t * opts,const char * argv0,const char * optarg)762 opts_set_dh(opts_t *opts, const char *argv0, const char *optarg)
763 {
764 	if (opts->dh)
765 		DH_free(opts->dh);
766 	opts->dh = ssl_dh_load(optarg);
767 	if (!opts->dh) {
768 		fprintf(stderr, "%s: error loading DH params from '%s':\n",
769 		        argv0, optarg);
770 		if (errno) {
771 			fprintf(stderr, "%s\n", strerror(errno));
772 		} else {
773 			ERR_print_errors_fp(stderr);
774 		}
775 		exit(EXIT_FAILURE);
776 	}
777 #ifdef DEBUG_OPTS
778 	log_dbg_printf("DHGroupParams: %s\n", optarg);
779 #endif /* DEBUG_OPTS */
780 }
781 #endif /* !OPENSSL_NO_DH */
782 
783 #ifndef OPENSSL_NO_ECDH
784 void
opts_set_ecdhcurve(opts_t * opts,const char * argv0,const char * optarg)785 opts_set_ecdhcurve(opts_t *opts, const char *argv0, const char *optarg)
786 {
787 	EC_KEY *ec;
788 	if (opts->ecdhcurve)
789 		free(opts->ecdhcurve);
790 	if (!(ec = ssl_ec_by_name(optarg))) {
791 		fprintf(stderr, "%s: unknown curve '%s'\n", argv0, optarg);
792 		exit(EXIT_FAILURE);
793 	}
794 	EC_KEY_free(ec);
795 	opts->ecdhcurve = strdup(optarg);
796 	if (!opts->ecdhcurve)
797 		oom_die(argv0);
798 #ifdef DEBUG_OPTS
799 	log_dbg_printf("ECDHCurve: %s\n", opts->ecdhcurve);
800 #endif /* DEBUG_OPTS */
801 }
802 #endif /* !OPENSSL_NO_ECDH */
803 
804 void
opts_set_sslcomp(opts_t * opts)805 opts_set_sslcomp(opts_t *opts)
806 {
807 	opts->sslcomp = 1;
808 }
809 
810 void
opts_unset_sslcomp(opts_t * opts)811 opts_unset_sslcomp(opts_t *opts)
812 {
813 	opts->sslcomp = 0;
814 }
815 
816 void
opts_set_ciphers(opts_t * opts,const char * argv0,const char * optarg)817 opts_set_ciphers(opts_t *opts, const char *argv0, const char *optarg)
818 {
819 	if (opts->ciphers)
820 		free(opts->ciphers);
821 	opts->ciphers = strdup(optarg);
822 	if (!opts->ciphers)
823 		oom_die(argv0);
824 #ifdef DEBUG_OPTS
825 	log_dbg_printf("Ciphers: %s\n", opts->ciphers);
826 #endif /* DEBUG_OPTS */
827 }
828 
829 #ifndef OPENSSL_NO_ENGINE
830 void
opts_set_openssl_engine(opts_t * opts,const char * argv0,const char * optarg)831 opts_set_openssl_engine(opts_t *opts, const char *argv0, const char *optarg)
832 {
833 	if (opts->openssl_engine)
834 		free(opts->openssl_engine);
835 	opts->openssl_engine = strdup(optarg);
836 	if (!opts->openssl_engine)
837 		oom_die(argv0);
838 #ifdef DEBUG_OPTS
839 	log_dbg_printf("OpenSSLEngine: %s\n", opts->openssl_engine);
840 #endif /* DEBUG_OPTS */
841 }
842 #endif /* !OPENSSL_NO_ENGINE */
843 
844 /*
845  * Parse SSL proto string in optarg and look up the corresponding SSL method.
846  * Calls exit() on failure.
847  */
848 void
opts_force_proto(opts_t * opts,const char * argv0,const char * optarg)849 opts_force_proto(opts_t *opts, const char *argv0, const char *optarg)
850 {
851 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
852 	if (opts->sslmethod != SSLv23_method) {
853 #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
854 	if (opts->sslversion) {
855 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
856 		fprintf(stderr, "%s: cannot use -r multiple times\n", argv0);
857 		exit(EXIT_FAILURE);
858 	}
859 
860 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
861 #ifdef HAVE_SSLV2
862 	if (!strcmp(optarg, "ssl2")) {
863 		opts->sslmethod = SSLv2_method;
864 	} else
865 #endif /* HAVE_SSLV2 */
866 #ifdef HAVE_SSLV3
867 	if (!strcmp(optarg, "ssl3")) {
868 		opts->sslmethod = SSLv3_method;
869 	} else
870 #endif /* HAVE_SSLV3 */
871 #ifdef HAVE_TLSV10
872 	if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) {
873 		opts->sslmethod = TLSv1_method;
874 	} else
875 #endif /* HAVE_TLSV10 */
876 #ifdef HAVE_TLSV11
877 	if (!strcmp(optarg, "tls11")) {
878 		opts->sslmethod = TLSv1_1_method;
879 	} else
880 #endif /* HAVE_TLSV11 */
881 #ifdef HAVE_TLSV12
882 	if (!strcmp(optarg, "tls12")) {
883 		opts->sslmethod = TLSv1_2_method;
884 	} else
885 #endif /* HAVE_TLSV12 */
886 #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
887 /*
888  * Support for SSLv2 and the corresponding SSLv2_method(),
889  * SSLv2_server_method() and SSLv2_client_method() functions were
890  * removed in OpenSSL 1.1.0.
891  */
892 #ifdef HAVE_SSLV3
893 	if (!strcmp(optarg, "ssl3")) {
894 		opts->sslversion = SSL3_VERSION;
895 	} else
896 #endif /* HAVE_SSLV3 */
897 #ifdef HAVE_TLSV10
898 	if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) {
899 		opts->sslversion = TLS1_VERSION;
900 	} else
901 #endif /* HAVE_TLSV10 */
902 #ifdef HAVE_TLSV11
903 	if (!strcmp(optarg, "tls11")) {
904 		opts->sslversion = TLS1_1_VERSION;
905 	} else
906 #endif /* HAVE_TLSV11 */
907 #ifdef HAVE_TLSV12
908 	if (!strcmp(optarg, "tls12")) {
909 		opts->sslversion = TLS1_2_VERSION;
910 	} else
911 #endif /* HAVE_TLSV12 */
912 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
913 	{
914 		fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n",
915 		                argv0, optarg);
916 		exit(EXIT_FAILURE);
917 	}
918 #ifdef DEBUG_OPTS
919 	log_dbg_printf("ForceSSLProto: %s\n", optarg);
920 #endif /* DEBUG_OPTS */
921 }
922 
923 /*
924  * Parse SSL proto string in optarg and set the corresponding no_foo bit.
925  * Calls exit() on failure.
926  */
927 void
928 opts_disable_proto(opts_t *opts, const char *argv0, const char *optarg)
929 {
930 #ifdef HAVE_SSLV2
931 	if (!strcmp(optarg, "ssl2")) {
932 		opts->no_ssl2 = 1;
933 	} else
934 #endif /* HAVE_SSLV2 */
935 #ifdef HAVE_SSLV3
936 	if (!strcmp(optarg, "ssl3")) {
937 		opts->no_ssl3 = 1;
938 	} else
939 #endif /* HAVE_SSLV3 */
940 #ifdef HAVE_TLSV10
941 	if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) {
942 		opts->no_tls10 = 1;
943 	} else
944 #endif /* HAVE_TLSV10 */
945 #ifdef HAVE_TLSV11
946 	if (!strcmp(optarg, "tls11")) {
947 		opts->no_tls11 = 1;
948 	} else
949 #endif /* HAVE_TLSV11 */
950 #ifdef HAVE_TLSV12
951 	if (!strcmp(optarg, "tls12")) {
952 		opts->no_tls12 = 1;
953 	} else
954 #endif /* HAVE_TLSV12 */
955 	{
956 		fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n",
957 		                argv0, optarg);
958 		exit(EXIT_FAILURE);
959 	}
960 #ifdef DEBUG_OPTS
961 	log_dbg_printf("DisableSSLProto: %s\n", optarg);
962 #endif /* DEBUG_OPTS */
963 }
964 
965 void
966 opts_set_user(opts_t *opts, const char *argv0, const char *optarg)
967 {
968 	if (!sys_isuser(optarg)) {
969 		fprintf(stderr, "%s: '%s' is not an existing user\n",
970 		        argv0, optarg);
971 		exit(EXIT_FAILURE);
972 	}
973 	if (opts->dropuser)
974 		free(opts->dropuser);
975 	opts->dropuser = strdup(optarg);
976 	if (!opts->dropuser)
977 		oom_die(argv0);
978 #ifdef DEBUG_OPTS
979 	log_dbg_printf("User: %s\n", opts->dropuser);
980 #endif /* DEBUG_OPTS */
981 }
982 
983 void
984 opts_set_group(opts_t *opts, const char *argv0, const char *optarg)
985 {
986 
987 	if (!sys_isgroup(optarg)) {
988 		fprintf(stderr, "%s: '%s' is not an existing group\n",
989 		        argv0, optarg);
990 		exit(EXIT_FAILURE);
991 	}
992 	if (opts->dropgroup)
993 		free(opts->dropgroup);
994 	opts->dropgroup = strdup(optarg);
995 	if (!opts->dropgroup)
996 		oom_die(argv0);
997 #ifdef DEBUG_OPTS
998 	log_dbg_printf("Group: %s\n", opts->dropgroup);
999 #endif /* DEBUG_OPTS */
1000 }
1001 
1002 void
1003 opts_set_jaildir(opts_t *opts, const char *argv0, const char *optarg)
1004 {
1005 	if (!sys_isdir(optarg)) {
1006 		fprintf(stderr, "%s: '%s' is not a directory\n", argv0, optarg);
1007 		exit(EXIT_FAILURE);
1008 	}
1009 	if (opts->jaildir)
1010 		free(opts->jaildir);
1011 	opts->jaildir = realpath(optarg, NULL);
1012 	if (!opts->jaildir) {
1013 		fprintf(stderr, "%s: Failed to realpath '%s': %s (%i)\n",
1014 		        argv0, optarg, strerror(errno), errno);
1015 		exit(EXIT_FAILURE);
1016 	}
1017 #ifdef DEBUG_OPTS
1018 	log_dbg_printf("Chroot: %s\n", opts->jaildir);
1019 #endif /* DEBUG_OPTS */
1020 }
1021 
1022 void
1023 opts_set_pidfile(opts_t *opts, const char *argv0, const char *optarg)
1024 {
1025 	if (opts->pidfile)
1026 		free(opts->pidfile);
1027 	opts->pidfile = strdup(optarg);
1028 	if (!opts->pidfile)
1029 		oom_die(argv0);
1030 #ifdef DEBUG_OPTS
1031 	log_dbg_printf("PidFile: %s\n", opts->pidfile);
1032 #endif /* DEBUG_OPTS */
1033 }
1034 
1035 void
1036 opts_set_connectlog(opts_t *opts, const char *argv0, const char *optarg)
1037 {
1038 	if (opts->connectlog)
1039 		free(opts->connectlog);
1040 	if (!(opts->connectlog = sys_realdir(optarg))) {
1041 		if (errno == ENOENT) {
1042 			fprintf(stderr, "Directory part of '%s' does not "
1043 			                "exist\n", optarg);
1044 			exit(EXIT_FAILURE);
1045 		} else {
1046 			fprintf(stderr, "Failed to realpath '%s': %s (%i)\n",
1047 			              optarg, strerror(errno), errno);
1048 			oom_die(argv0);
1049 		}
1050 	}
1051 #ifdef DEBUG_OPTS
1052 	log_dbg_printf("ConnectLog: %s\n", opts->connectlog);
1053 #endif /* DEBUG_OPTS */
1054 }
1055 
1056 void
1057 opts_set_contentlog(opts_t *opts, const char *argv0, const char *optarg)
1058 {
1059 	if (opts->contentlog)
1060 		free(opts->contentlog);
1061 	if (!(opts->contentlog = sys_realdir(optarg))) {
1062 		if (errno == ENOENT) {
1063 			fprintf(stderr, "Directory part of '%s' does not "
1064 			                "exist\n", optarg);
1065 			exit(EXIT_FAILURE);
1066 		} else {
1067 			fprintf(stderr, "Failed to realpath '%s': %s (%i)\n",
1068 			              optarg, strerror(errno), errno);
1069 			oom_die(argv0);
1070 		}
1071 	}
1072 	opts->contentlog_isdir = 0;
1073 	opts->contentlog_isspec = 0;
1074 #ifdef DEBUG_OPTS
1075 	log_dbg_printf("ContentLog: %s\n", opts->contentlog);
1076 #endif /* DEBUG_OPTS */
1077 }
1078 
1079 void
1080 opts_set_contentlogdir(opts_t *opts, const char *argv0, const char *optarg)
1081 {
1082 	if (!sys_isdir(optarg)) {
1083 		fprintf(stderr, "%s: '%s' is not a directory\n", argv0, optarg);
1084 		exit(EXIT_FAILURE);
1085 	}
1086 	if (opts->contentlog)
1087 		free(opts->contentlog);
1088 	opts->contentlog = realpath(optarg, NULL);
1089 	if (!opts->contentlog) {
1090 		fprintf(stderr, "%s: Failed to realpath '%s': %s (%i)\n",
1091 		        argv0, optarg, strerror(errno), errno);
1092 		exit(EXIT_FAILURE);
1093 	}
1094 	opts->contentlog_isdir = 1;
1095 	opts->contentlog_isspec = 0;
1096 #ifdef DEBUG_OPTS
1097 	log_dbg_printf("ContentLogDir: %s\n", opts->contentlog);
1098 #endif /* DEBUG_OPTS */
1099 }
1100 
1101 static void
1102 opts_set_logbasedir(const char *argv0, const char *optarg,
1103                     char **basedir, char **log)
1104 {
1105 	char *lhs, *rhs, *p, *q;
1106 	size_t n;
1107 	if (*basedir)
1108 		free(*basedir);
1109 	if (*log)
1110 		free(*log);
1111 	if (log_content_split_pathspec(optarg, &lhs, &rhs) == -1) {
1112 		fprintf(stderr, "%s: Failed to split '%s' in lhs/rhs:"
1113 		                " %s (%i)\n", argv0, optarg,
1114 		                strerror(errno), errno);
1115 		exit(EXIT_FAILURE);
1116 	}
1117 	/* eliminate %% from lhs */
1118 	for (p = q = lhs; *p; p++, q++) {
1119 		if (q < p)
1120 			*q = *p;
1121 		if (*p == '%' && *(p+1) == '%')
1122 			p++;
1123 	}
1124 	*q = '\0';
1125 	/* all %% in lhs resolved to % */
1126 	if (sys_mkpath(lhs, 0777) == -1) {
1127 		fprintf(stderr, "%s: Failed to create '%s': %s (%i)\n",
1128 		        argv0, lhs, strerror(errno), errno);
1129 		exit(EXIT_FAILURE);
1130 	}
1131 	*basedir = realpath(lhs, NULL);
1132 	if (!*basedir) {
1133 		fprintf(stderr, "%s: Failed to realpath '%s': %s (%i)\n",
1134 		        argv0, lhs, strerror(errno), errno);
1135 		exit(EXIT_FAILURE);
1136 	}
1137 	/* count '%' in basedir */
1138 	for (n = 0, p = *basedir;
1139 		 *p;
1140 		 p++) {
1141 		if (*p == '%')
1142 			n++;
1143 	}
1144 	free(lhs);
1145 	n += strlen(*basedir);
1146 	if (!(lhs = malloc(n + 1)))
1147 		oom_die(argv0);
1148 	/* re-encoding % to %%, copying basedir to lhs */
1149 	for (p = *basedir, q = lhs;
1150 		 *p;
1151 		 p++, q++) {
1152 		*q = *p;
1153 		if (*q == '%')
1154 			*(++q) = '%';
1155 	}
1156 	*q = '\0';
1157 	/* lhs contains encoded realpathed basedir */
1158 	if (asprintf(log, "%s/%s", lhs, rhs) < 0)
1159 		oom_die(argv0);
1160 	free(lhs);
1161 	free(rhs);
1162 }
1163 
1164 void
1165 opts_set_contentlogpathspec(opts_t *opts, const char *argv0, const char *optarg)
1166 {
1167 	opts_set_logbasedir(argv0, optarg, &opts->contentlog_basedir,
1168 	                    &opts->contentlog);
1169 	opts->contentlog_isdir = 0;
1170 	opts->contentlog_isspec = 1;
1171 #ifdef DEBUG_OPTS
1172 	log_dbg_printf("ContentLogPathSpec: basedir=%s, %s\n",
1173 	               opts->contentlog_basedir, opts->contentlog);
1174 #endif /* DEBUG_OPTS */
1175 }
1176 
1177 #ifdef HAVE_LOCAL_PROCINFO
1178 void
1179 opts_set_lprocinfo(opts_t *opts)
1180 {
1181 	opts->lprocinfo = 1;
1182 }
1183 
1184 void
1185 opts_unset_lprocinfo(opts_t *opts)
1186 {
1187 	opts->lprocinfo = 0;
1188 }
1189 #endif /* HAVE_LOCAL_PROCINFO */
1190 
1191 void
1192 opts_set_masterkeylog(opts_t *opts, const char *argv0, const char *optarg)
1193 {
1194 	if (opts->masterkeylog)
1195 		free(opts->masterkeylog);
1196 	if (!(opts->masterkeylog = sys_realdir(optarg))) {
1197 		if (errno == ENOENT) {
1198 			fprintf(stderr, "Directory part of '%s' does not "
1199 			                "exist\n", optarg);
1200 			exit(EXIT_FAILURE);
1201 		} else {
1202 			fprintf(stderr, "Failed to realpath '%s': %s (%i)\n",
1203 			              optarg, strerror(errno), errno);
1204 			oom_die(argv0);
1205 		}
1206 	}
1207 #ifdef DEBUG_OPTS
1208 	log_dbg_printf("MasterKeyLog: %s\n", opts->masterkeylog);
1209 #endif /* DEBUG_OPTS */
1210 }
1211 
1212 void
1213 opts_set_pcaplog(opts_t *opts, const char *argv0, const char *optarg)
1214 {
1215 	if (opts->pcaplog)
1216 		free(opts->pcaplog);
1217 	if (!(opts->pcaplog = sys_realdir(optarg))) {
1218 		if (errno == ENOENT) {
1219 			fprintf(stderr, "Directory part of '%s' does not "
1220 			                "exist\n", optarg);
1221 			exit(EXIT_FAILURE);
1222 		} else {
1223 			fprintf(stderr, "Failed to realpath '%s': %s (%i)\n",
1224 			              optarg, strerror(errno), errno);
1225 			oom_die(argv0);
1226 		}
1227 	}
1228 	opts->pcaplog_isdir = 0;
1229 	opts->pcaplog_isspec = 0;
1230 #ifdef DEBUG_OPTS
1231 	log_dbg_printf("PcapLog: %s\n", opts->pcaplog);
1232 #endif /* DEBUG_OPTS */
1233 }
1234 
1235 void
1236 opts_set_pcaplogdir(opts_t *opts, const char *argv0, const char *optarg)
1237 {
1238 	if (!sys_isdir(optarg)) {
1239 		fprintf(stderr, "%s: '%s' is not a directory\n", argv0, optarg);
1240 		exit(EXIT_FAILURE);
1241 	}
1242 	if (opts->pcaplog)
1243 		free(opts->pcaplog);
1244 	opts->pcaplog = realpath(optarg, NULL);
1245 	if (!opts->pcaplog) {
1246 		fprintf(stderr, "%s: Failed to realpath '%s': %s (%i)\n",
1247 		        argv0, optarg, strerror(errno), errno);
1248 		exit(EXIT_FAILURE);
1249 	}
1250 	opts->pcaplog_isdir = 1;
1251 	opts->pcaplog_isspec = 0;
1252 #ifdef DEBUG_OPTS
1253 	log_dbg_printf("PcapLogDir: %s\n", opts->pcaplog);
1254 #endif /* DEBUG_OPTS */
1255 }
1256 
1257 void
1258 opts_set_pcaplogpathspec(opts_t *opts, const char *argv0, const char *optarg)
1259 {
1260 	opts_set_logbasedir(argv0, optarg, &opts->pcaplog_basedir,
1261 	                    &opts->pcaplog);
1262 	opts->pcaplog_isdir = 0;
1263 	opts->pcaplog_isspec = 1;
1264 #ifdef DEBUG_OPTS
1265 	log_dbg_printf("PcapLogPathSpec: basedir=%s, %s\n",
1266 	               opts->pcaplog_basedir, opts->pcaplog);
1267 #endif /* DEBUG_OPTS */
1268 }
1269 
1270 #ifndef WITHOUT_MIRROR
1271 void
1272 opts_set_mirrorif(opts_t *opts, const char *argv0, const char *optarg)
1273 {
1274 	if (opts->mirrorif)
1275 		free(opts->mirrorif);
1276 	opts->mirrorif = strdup(optarg);
1277 	if (!opts->mirrorif)
1278 		oom_die(argv0);
1279 #ifdef DEBUG_OPTS
1280 	log_dbg_printf("MirrorIf: %s\n", opts->mirrorif);
1281 #endif /* DEBUG_OPTS */
1282 }
1283 
1284 void
1285 opts_set_mirrortarget(opts_t *opts, const char *argv0, const char *optarg)
1286 {
1287 	if (opts->mirrortarget)
1288 		free(opts->mirrortarget);
1289 	opts->mirrortarget = strdup(optarg);
1290 	if (!opts->mirrortarget)
1291 		oom_die(argv0);
1292 #ifdef DEBUG_OPTS
1293 	log_dbg_printf("MirrorTarget: %s\n", opts->mirrortarget);
1294 #endif /* DEBUG_OPTS */
1295 }
1296 #endif /* !WITHOUT_MIRROR */
1297 
1298 void
1299 opts_set_daemon(opts_t *opts)
1300 {
1301 	opts->detach = 1;
1302 }
1303 
1304 void
1305 opts_unset_daemon(opts_t *opts)
1306 {
1307 	opts->detach = 0;
1308 }
1309 
1310 void
1311 opts_set_debug(opts_t *opts)
1312 {
1313 	log_dbg_mode(LOG_DBG_MODE_ERRLOG);
1314 	opts->debug = 1;
1315 }
1316 
1317 void
1318 opts_unset_debug(opts_t *opts)
1319 {
1320 	log_dbg_mode(LOG_DBG_MODE_NONE);
1321 	opts->debug = 0;
1322 }
1323 
1324 static void
1325 opts_set_verify_peer(opts_t *opts)
1326 {
1327 	opts->verify_peer = 1;
1328 }
1329 
1330 static void
1331 opts_unset_verify_peer(opts_t *opts)
1332 {
1333 	opts->verify_peer = 0;
1334 }
1335 
1336 static void
1337 opts_set_allow_wrong_host(opts_t *opts)
1338 {
1339 	opts->allow_wrong_host = 1;
1340 }
1341 
1342 static void
1343 opts_unset_allow_wrong_host(opts_t *opts)
1344 {
1345 	opts->allow_wrong_host = 0;
1346 }
1347 
1348 static int
1349 check_value_yesno(const char *value, const char *name, int line_num)
1350 {
1351 	if (!strcmp(value, "yes")) {
1352 		return 1;
1353 	} else if (!strcmp(value, "no")) {
1354 		return 0;
1355 	}
1356 	fprintf(stderr, "Error in conf: Invalid '%s' value '%s' at line %d, use yes|no\n", name, value, line_num);
1357 	return -1;
1358 }
1359 
1360 #define MAX_TOKEN 10
1361 
1362 static int
1363 set_option(opts_t *opts, const char *argv0,
1364            const char *name, char *value, char **natengine, int line_num)
1365 {
1366 	int yes;
1367 	int retval = -1;
1368 
1369 	if (!strcmp(name, "CACert")) {
1370 		opts_set_cacrt(opts, argv0, value);
1371 	} else if (!strcmp(name, "CAKey")) {
1372 		opts_set_cakey(opts, argv0, value);
1373 	} else if (!strcmp(name, "ClientCert")) {
1374 		opts_set_clientcrt(opts, argv0, value);
1375 	} else if (!strcmp(name, "ClientKey")) {
1376 		opts_set_clientkey(opts, argv0, value);
1377 	} else if (!strcmp(name, "CAChain")) {
1378 		opts_set_cachain(opts, argv0, value);
1379 	} else if (!strcmp(name, "LeafCerts") ||        /* compat <= 0.5.4 */
1380 	           !strcmp(name, "LeafKey")) {
1381 		opts_set_leafkey(opts, argv0, value);
1382 	} else if (!strcmp(name, "CRL") ||              /* compat <= 0.5.4 */
1383 	           !strcmp(name, "LeafCRLURL")) {
1384 		opts_set_leafcrlurl(opts, value);
1385 	} else if (!strcmp(name, "TargetCertDir") ||    /* compat <= 0.5.4 */
1386 	           !strcmp(name, "LeafCertDir")) {
1387 		opts_set_leafcertdir(opts, argv0, value);
1388 	} else if (!strcmp(name, "DefaultLeafCert")) {
1389 		opts_set_defaultleafcert(opts, argv0, value);
1390 	} else if (!strcmp(name, "WriteGenCertsDir")) {
1391 		opts_set_certgendir_writegencerts(opts, argv0, value);
1392 	} else if (!strcmp(name, "WriteAllCertsDir")) {
1393 		opts_set_certgendir_writeall(opts, argv0, value);
1394 	} else if (!strcmp(name, "DenyOCSP")) {
1395 		yes = check_value_yesno(value, "DenyOCSP", line_num);
1396 		if (yes == -1) {
1397 			goto leave;
1398 		}
1399 		yes ? opts_set_deny_ocsp(opts) : opts_unset_deny_ocsp(opts);
1400 #ifdef DEBUG_OPTS
1401 		log_dbg_printf("DenyOCSP: %u\n", opts->deny_ocsp);
1402 #endif /* DEBUG_OPTS */
1403 	} else if (!strcmp(name, "Passthrough")) {
1404 		yes = check_value_yesno(value, "Passthrough", line_num);
1405 		if (yes == -1) {
1406 			goto leave;
1407 		}
1408 		yes ? opts_set_passthrough(opts) : opts_unset_passthrough(opts);
1409 #ifdef DEBUG_OPTS
1410 		log_dbg_printf("Passthrough: %u\n", opts->passthrough);
1411 #endif /* DEBUG_OPTS */
1412 #ifndef OPENSSL_NO_DH
1413 	} else if (!strcmp(name, "DHGroupParams")) {
1414 		opts_set_dh(opts, argv0, value);
1415 #endif /* !OPENSSL_NO_DH */
1416 #ifndef OPENSSL_NO_ECDH
1417 	} else if (!strcmp(name, "ECDHCurve")) {
1418 		opts_set_ecdhcurve(opts, argv0, value);
1419 #endif /* !OPENSSL_NO_ECDH */
1420 #ifdef SSL_OP_NO_COMPRESSION
1421 	} else if (!strcmp(name, "SSLCompression")) {
1422 		yes = check_value_yesno(value, "SSLCompression", line_num);
1423 		if (yes == -1) {
1424 			goto leave;
1425 		}
1426 		yes ? opts_set_sslcomp(opts) : opts_unset_sslcomp(opts);
1427 #ifdef DEBUG_OPTS
1428 		log_dbg_printf("SSLCompression: %u\n", opts->sslcomp);
1429 #endif /* DEBUG_OPTS */
1430 #endif /* SSL_OP_NO_COMPRESSION */
1431 	} else if (!strcmp(name, "ForceSSLProto")) {
1432 		opts_force_proto(opts, argv0, value);
1433 	} else if (!strcmp(name, "DisableSSLProto")) {
1434 		opts_disable_proto(opts, argv0, value);
1435 	} else if (!strcmp(name, "Ciphers")) {
1436 		opts_set_ciphers(opts, argv0, value);
1437 #ifndef OPENSSL_NO_ENGINE
1438 	} else if (!strcmp(name, "OpenSSLEngine")) {
1439 		opts_set_openssl_engine(opts, argv0, value);
1440 #endif /* !OPENSSL_NO_ENGINE */
1441 	} else if (!strcmp(name, "NATEngine")) {
1442 		if (*natengine)
1443 			free(*natengine);
1444 		*natengine = strdup(value);
1445 		if (!*natengine)
1446 			goto leave;
1447 #ifdef DEBUG_OPTS
1448 		log_dbg_printf("NATEngine: %s\n", *natengine);
1449 #endif /* DEBUG_OPTS */
1450 	} else if (!strcmp(name, "User")) {
1451 		opts_set_user(opts, argv0, value);
1452 	} else if (!strcmp(name, "Group")) {
1453 		opts_set_group(opts, argv0, value);
1454 	} else if (!strcmp(name, "Chroot")) {
1455 		opts_set_jaildir(opts, argv0, value);
1456 	} else if (!strcmp(name, "PidFile")) {
1457 		opts_set_pidfile(opts, argv0, value);
1458 	} else if (!strcmp(name, "ConnectLog")) {
1459 		opts_set_connectlog(opts, argv0, value);
1460 	} else if (!strcmp(name, "ContentLog")) {
1461 		opts_set_contentlog(opts, argv0, value);
1462 	} else if (!strcmp(name, "ContentLogDir")) {
1463 		opts_set_contentlogdir(opts, argv0, value);
1464 	} else if (!strcmp(name, "ContentLogPathSpec")) {
1465 		opts_set_contentlogpathspec(opts, argv0, value);
1466 #ifdef HAVE_LOCAL_PROCINFO
1467 	} else if (!strcmp(name, "LogProcInfo")) {
1468 		yes = check_value_yesno(value, "LogProcInfo", line_num);
1469 		if (yes == -1) {
1470 			goto leave;
1471 		}
1472 		yes ? opts_set_lprocinfo(opts) : opts_unset_lprocinfo(opts);
1473 #ifdef DEBUG_OPTS
1474 		log_dbg_printf("LogProcInfo: %u\n", opts->lprocinfo);
1475 #endif /* DEBUG_OPTS */
1476 #endif /* HAVE_LOCAL_PROCINFO */
1477 	} else if (!strcmp(name, "MasterKeyLog")) {
1478 		opts_set_masterkeylog(opts, argv0, value);
1479 	} else if (!strcmp(name, "PcapLog")) {
1480 		opts_set_pcaplog(opts, argv0, value);
1481 	} else if (!strcmp(name, "PcapLogDir")) {
1482 		opts_set_pcaplogdir(opts, argv0, value);
1483 	} else if (!strcmp(name, "PcapLogPathSpec")) {
1484 		opts_set_pcaplogpathspec(opts, argv0, value);
1485 #ifndef WITHOUT_MIRROR
1486 	} else if (!strcmp(name, "MirrorIf")) {
1487 		opts_set_mirrorif(opts, argv0, value);
1488 	} else if (!strcmp(name, "MirrorTarget")) {
1489 		opts_set_mirrortarget(opts, argv0, value);
1490 #endif /* !WITHOUT_MIRROR */
1491 	} else if (!strcmp(name, "Daemon")) {
1492 		yes = check_value_yesno(value, "Daemon", line_num);
1493 		if (yes == -1) {
1494 			goto leave;
1495 		}
1496 		yes ? opts_set_daemon(opts) : opts_unset_daemon(opts);
1497 #ifdef DEBUG_OPTS
1498 		log_dbg_printf("Daemon: %u\n", opts->detach);
1499 #endif /* DEBUG_OPTS */
1500 	} else if (!strcmp(name, "Debug")) {
1501 		yes = check_value_yesno(value, "Debug", line_num);
1502 		if (yes == -1) {
1503 			goto leave;
1504 		}
1505 		yes ? opts_set_debug(opts) : opts_unset_debug(opts);
1506 #ifdef DEBUG_OPTS
1507 		log_dbg_printf("Debug: %u\n", opts->debug);
1508 #endif /* DEBUG_OPTS */
1509 	} else if (!strcmp(name, "ProxySpec")) {
1510 		/* Use MAX_TOKEN instead of computing the actual number of tokens in value */
1511 		char **argv = malloc(sizeof(char *) * MAX_TOKEN);
1512 		char **save_argv = argv;
1513 		int argc = 0;
1514 		char *p, *last = NULL;
1515 
1516 		for ((p = strtok_r(value, " ", &last));
1517 		     p;
1518 		     (p = strtok_r(NULL, " ", &last))) {
1519 			/* Limit max # token */
1520 			if (argc < MAX_TOKEN) {
1521 				argv[argc++] = p;
1522 			} else {
1523 				break;
1524 			}
1525 		}
1526 
1527 		proxyspec_parse(&argc, &argv, *natengine, &opts->spec);
1528 		free(save_argv);
1529 	} else if (!strcmp(name, "VerifyPeer")) {
1530 		yes = check_value_yesno(value, "VerifyPeer", line_num);
1531 		if (yes == -1) {
1532 			goto leave;
1533 		}
1534 		yes ? opts_set_verify_peer(opts) : opts_unset_verify_peer(opts);
1535 #ifdef DEBUG_OPTS
1536 		log_dbg_printf("VerifyPeer: %u\n", opts->verify_peer);
1537 #endif /* DEBUG_OPTS */
1538 	} else if (!strcmp(name, "AddSNIToCertificate")) {
1539 		yes = check_value_yesno(value, "AddSNIToCertificate", line_num);
1540 		if (yes == -1) {
1541 			goto leave;
1542 		}
1543 		yes ? opts_set_allow_wrong_host(opts)
1544 		    : opts_unset_allow_wrong_host(opts);
1545 #ifdef DEBUG_OPTS
1546 		log_dbg_printf("AddSNIToCertificate: %u\n",
1547 		               opts->allow_wrong_host);
1548 #endif /* DEBUG_OPTS */
1549 	} else {
1550 		fprintf(stderr, "Error in conf: Unknown option "
1551 		                "'%s' at line %d\n", name, line_num);
1552 		goto leave;
1553 	}
1554 
1555 	retval = 0;
1556 leave:
1557 	return retval;
1558 }
1559 
1560 /*
1561  * Separator param is needed for command line options only.
1562  * Conf file option separator is ' '.
1563  */
1564 static int
1565 get_name_value(char **name, char **value, const char sep)
1566 {
1567 	char *n, *v, *value_end;
1568 	int retval = -1;
1569 
1570 	/* Skip to the end of option name and terminate it with '\0' */
1571 	for (n = *name;; n++) {
1572 		/* White spaces possible around separator,
1573 		 * if the command line option is passed between the quotes */
1574 		if (*n == ' ' || *n == '\t' || *n == sep) {
1575 			*n = '\0';
1576 			n++;
1577 			break;
1578 		}
1579 		if (*n == '\0') {
1580 			n = NULL;
1581 			break;
1582 		}
1583 	}
1584 
1585 	/* No option name */
1586 	if (n == NULL) {
1587 		fprintf(stderr, "Error in option: No option name\n");
1588 		goto leave;
1589 	}
1590 
1591 	/* White spaces possible before value and around separator,
1592 	 * if the command line option is passed between the quotes */
1593 	while (*n == ' ' || *n == '\t' || *n == sep) {
1594 		n++;
1595 	}
1596 
1597 	*value = n;
1598 
1599 	/* Find end of value and terminate it with '\0'
1600 	 * Find first occurrence of trailing white space */
1601 	value_end = NULL;
1602 	for (v = *value;; v++) {
1603 		if (*v == '\0') {
1604 			break;
1605 		}
1606 		if (*v == '\r' || *v == '\n') {
1607 			*v = '\0';
1608 			break;
1609 		}
1610 		if (*v == ' ' || *v == '\t') {
1611 			if (!value_end) {
1612 				value_end = v;
1613 			}
1614 		} else {
1615 			value_end = NULL;
1616 		}
1617 	}
1618 
1619 	if (value_end) {
1620 		*value_end = '\0';
1621 	}
1622 
1623 	retval = 0;
1624 leave:
1625 	return retval;
1626 }
1627 
1628 int
1629 opts_set_option(opts_t *opts, const char *argv0, const char *optarg,
1630                 char **natengine)
1631 {
1632 	char *name, *value;
1633 	int retval = -1;
1634 	char *line = strdup(optarg);
1635 
1636 	/* White spaces possible before option name,
1637 	 * if the command line option is passed between the quotes */
1638 	for (name = line; *name == ' ' || *name == '\t'; name++);
1639 
1640 	/* Command line option separator is '=' */
1641 	retval = get_name_value(&name, &value, '=');
1642 	if (retval == 0) {
1643 		/* Line number param is for conf file, pass 0 for command line options */
1644 		retval = set_option(opts, argv0, name, value, natengine, 0);
1645 	}
1646 
1647 	if (line) {
1648 		free(line);
1649 	}
1650 	return retval;
1651 }
1652 
1653 int
1654 load_conffile(opts_t *opts, const char *argv0, char **natengine)
1655 {
1656 	int retval, line_num;
1657 	char *line, *name, *value;
1658 	size_t line_len;
1659 	FILE *f;
1660 
1661 	f = fopen(opts->conffile, "r");
1662 	if (!f) {
1663 		fprintf(stderr, "Error opening conf file '%s': %s\n", opts->conffile, strerror(errno));
1664 		return -1;
1665 	}
1666 
1667 	line = NULL;
1668 	line_num = 0;
1669 	retval = -1;
1670 	while (!feof(f)) {
1671 		if (getline(&line, &line_len, f) == -1) {
1672 			break;
1673 		}
1674 		if (line == NULL) {
1675 			fprintf(stderr, "Error in conf file: getline() returns NULL line after line %d\n", line_num);
1676 			goto leave;
1677 		}
1678 		line_num++;
1679 
1680 		/* Skip white space */
1681 		for (name = line; *name == ' ' || *name == '\t'; name++);
1682 
1683 		/* Skip comments and empty lines */
1684 		if ((name[0] == '\0') || (name[0] == '#') || (name[0] == ';') ||
1685 			(name[0] == '\r') || (name[0] == '\n')) {
1686 			continue;
1687 		}
1688 
1689 		retval = get_name_value(&name, &value, ' ');
1690 		if (retval == 0) {
1691 			retval = set_option(opts, argv0, name, value, natengine, line_num);
1692 		}
1693 
1694 		if (retval == -1) {
1695 			goto leave;
1696 		}
1697 	}
1698 
1699 leave:
1700 	fclose(f);
1701 	if (line) {
1702 		free(line);
1703 	}
1704 	return retval;
1705 }
1706 
1707 /* vim: set noet ft=c: */
1708