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