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 "log.h"
30 
31 #include "logger.h"
32 #include "sys.h"
33 #include "attrib.h"
34 #include "privsep.h"
35 #include "defaults.h"
36 #include "logpkt.h"
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <syslog.h>
46 #include <assert.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49 
50 /*
51  * Centralized logging code multiplexing thread access to the logger based
52  * logging in separate threads.  Some log types are switchable to different
53  * backends, such as syslog and stderr.
54  */
55 
56 
57 /*
58  * Common code for all logs.
59  */
60 static proxy_ctx_t *proxy_ctx = NULL;
61 
62 // @attention The order of names should match the numbering in LOG_DBG_MODE_* macros
63 char *log_dbg_mode_names[] = {
64 	"NONE", // = 0
65 	"ERROR",
66 	"FINE",
67 	"FINER",
68 	"FINEST",
69 };
70 
71 void
log_exceptcb(void)72 log_exceptcb(void)
73 {
74 	log_err_level_printf(LOG_CRIT, "Error %d on logger: %s\n", errno, strerror(errno));
75 	/* Do not break the event loop if out of fds:
76 	 * Bad file descriptor (9) or Message too long (40) */
77 	if (errno == 9 || errno == 40) {
78 		return;
79 	}
80 	if (proxy_ctx) {
81 		proxy_loopbreak(proxy_ctx, -1);
82 		proxy_ctx = NULL;
83 	}
84 }
85 
86 /*
87  * Error log.
88  * Switchable between stderr and syslog.
89  * Uses logger thread.
90  */
91 
92 static logger_t *err_log = NULL;
93 static int err_shortcut_logger = 0;
94 static int err_mode = LOG_ERR_MODE_STDERR;
95 
96 static ssize_t
log_err_writecb(int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)97 log_err_writecb(int level, UNUSED void *fh, UNUSED unsigned long ctl,
98                 const void *buf, size_t sz)
99 {
100 	switch (err_mode) {
101 		case LOG_ERR_MODE_STDERR:
102 			return fwrite(buf, sz - 1, 1, stderr);
103 		case LOG_ERR_MODE_SYSLOG:
104 			syslog(LOG_DAEMON|level, "%s", (const char *)buf);
105 			return sz;
106 	}
107 	return -1;
108 }
109 
110 int
log_err_printf(const char * fmt,...)111 log_err_printf(const char *fmt, ...)
112 {
113 	va_list ap;
114 	char *buf;
115 	int rv;
116 
117 	va_start(ap, fmt);
118 	rv = vasprintf(&buf, fmt, ap);
119 	va_end(ap);
120 	if (rv < 0)
121 		return -1;
122 	if (err_shortcut_logger) {
123 		return logger_write_freebuf(err_log, LOG_ERR, NULL, 0,
124 		                            buf, strlen(buf) + 1);
125 	} else {
126 		log_err_writecb(LOG_ERR, NULL, 0, (unsigned char*)buf, strlen(buf) + 1);
127 		free(buf);
128 	}
129 	return 0;
130 }
131 
132 int
log_err_level_printf(int level,const char * fmt,...)133 log_err_level_printf(int level, const char *fmt, ...)
134 {
135 	va_list ap;
136 	char *buf;
137 	int rv;
138 
139 	va_start(ap, fmt);
140 	rv = vasprintf(&buf, fmt, ap);
141 	va_end(ap);
142 	if (rv < 0)
143 		return -1;
144 	if (err_shortcut_logger) {
145 		return logger_write_freebuf(err_log, level, NULL, 0,
146 		                            buf, strlen(buf) + 1);
147 	} else {
148 		log_err_writecb(level, NULL, 0, (unsigned char*)buf, strlen(buf) + 1);
149 		free(buf);
150 	}
151 	return 0;
152 }
153 
154 void
log_err_mode(int mode)155 log_err_mode(int mode)
156 {
157 	err_mode = mode;
158 }
159 
160 
161 /*
162  * Debug log.  Redirects logging to error log.
163  * Switchable between error log or no logging.
164  * Uses the error log logger thread.
165  */
166 
167 static int dbg_mode = LOG_DBG_MODE_NONE;
168 
169 int
log_dbg_write_free(void * buf,size_t sz)170 log_dbg_write_free(void *buf, size_t sz)
171 {
172 	if (dbg_mode == LOG_DBG_MODE_NONE)
173 		return 0;
174 
175 	if (err_shortcut_logger) {
176 		return logger_write_freebuf(err_log, LOG_DEBUG, NULL, 0, buf, sz);
177 	} else {
178 		log_err_writecb(LOG_DEBUG, NULL, 0, buf, sz);
179 		free(buf);
180 	}
181 	return 0;
182 }
183 
184 int
log_dbg_print_free(char * s)185 log_dbg_print_free(char *s)
186 {
187 	return log_dbg_write_free(s, strlen(s) + 1);
188 }
189 
190 int
log_dbg_printf(const char * fmt,...)191 log_dbg_printf(const char *fmt, ...)
192 {
193 	va_list ap;
194 	char *buf;
195 	int rv;
196 
197 	if (dbg_mode == LOG_DBG_MODE_NONE)
198 		return 0;
199 
200 	va_start(ap, fmt);
201 	rv = vasprintf(&buf, fmt, ap);
202 	va_end(ap);
203 	if (rv < 0)
204 		return -1;
205 	return log_dbg_print_free(buf);
206 }
207 
208 int
log_dbg_level_printf(int level,const char * function,int thrid,long long unsigned int id,evutil_socket_t fd,evutil_socket_t child_fd,const char * fmt,...)209 log_dbg_level_printf(int level, const char *function, int thrid, long long unsigned int id, evutil_socket_t fd, evutil_socket_t child_fd, const char *fmt, ...)
210 {
211 	va_list ap;
212 	char *buf;
213 	int rv;
214 
215 	if (dbg_mode == LOG_DBG_MODE_NONE || dbg_mode < level)
216 		return 0;
217 
218 	va_start(ap, fmt);
219 	rv = vasprintf(&buf, fmt, ap);
220 	va_end(ap);
221 	if (rv < 0)
222 		return -1;
223 
224 	char *logbuf;
225 	// The *_main and *_main_va macros always pass 0 as fd, and the other macros fd > 0
226 	if (fd) {
227 		rv = asprintf(&logbuf, "[%s] [%d.%llu fd=%d cfd=%d] %s: %s\n", log_dbg_mode_names[level], thrid, id, fd, child_fd, function, buf);
228 	} else {
229 		rv = asprintf(&logbuf, "[%s] %s: %s\n", log_dbg_mode_names[level], function, buf);
230 	}
231 	free(buf);
232 	if (rv < 0)
233 		return -1;
234 	return log_dbg_print_free(logbuf);
235 }
236 
237 void
log_dbg_mode(int mode)238 log_dbg_mode(int mode)
239 {
240 	dbg_mode = mode;
241 }
242 
243 /*
244  * Master key log.  Logs master keys in SSLKEYLOGFILE format.
245  * Uses a logger thread.
246  */
247 
248 logger_t *masterkey_log = NULL;
249 static int masterkey_fd = -1;
250 static char *masterkey_fn = NULL;
251 static int masterkey_clisock = -1;
252 
253 static int
log_masterkey_preinit(const char * logfile)254 log_masterkey_preinit(const char *logfile)
255 {
256 	masterkey_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
257 	if (masterkey_fd == -1) {
258 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
259 		               logfile, strerror(errno), errno);
260 		return -1;
261 	}
262 	masterkey_fn = strdup(logfile);
263 	if (!masterkey_fn) {
264 		close(masterkey_fd);
265 		masterkey_fd = -1;
266 		return -1;
267 	}
268 	return 0;
269 }
270 
271 static int
log_masterkey_reopencb(void)272 log_masterkey_reopencb(void)
273 {
274 	close(masterkey_fd);
275 	masterkey_fd = privsep_client_openfile(masterkey_clisock,
276 	                                       masterkey_fn,
277 	                                       0);
278 	if (masterkey_fd == -1) {
279 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s\n",
280 		               masterkey_fn, strerror(errno));
281 		free(masterkey_fn);
282 		masterkey_fn = NULL;
283 		return -1;
284 	}
285 	return 0;
286 }
287 
288 /*
289  * Do the actual write to the open master key log file descriptor.
290  */
291 static ssize_t
log_masterkey_writecb(UNUSED int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)292 log_masterkey_writecb(UNUSED int level, UNUSED void *fh, UNUSED unsigned long ctl,
293                       const void *buf, size_t sz)
294 {
295 	if (write(masterkey_fd, buf, sz) == -1) {
296 		log_err_level_printf(LOG_CRIT, "Warning: Failed to write to masterkey log:"
297 		               " %s\n", strerror(errno));
298 		return -1;
299 	}
300 	return sz;
301 }
302 
303 static void
log_masterkey_fini(void)304 log_masterkey_fini(void)
305 {
306 	close(masterkey_fd);
307 }
308 
309 /*
310  * Connection log.  Logs a one-liner to a file-based connection log.
311  * Uses a logger thread.
312  */
313 
314 logger_t *connect_log = NULL;
315 static int connect_fd = -1;
316 static char *connect_fn = NULL;
317 static int connect_clisock = -1;
318 
319 static int
log_connect_preinit(const char * logfile)320 log_connect_preinit(const char *logfile)
321 {
322 	connect_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
323 	if (connect_fd == -1) {
324 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
325 		               logfile, strerror(errno), errno);
326 		return -1;
327 	}
328 	connect_fn = strdup(logfile);
329 	if (!connect_fn) {
330 		close(connect_fd);
331 		connect_fd = -1;
332 		return -1;
333 	}
334 	return 0;
335 }
336 
337 static int
log_connect_reopencb(void)338 log_connect_reopencb(void)
339 {
340 	close(connect_fd);
341 	connect_fd = privsep_client_openfile(connect_clisock,
342 	                                     connect_fn,
343 	                                     0);
344 	if (connect_fd == -1) {
345 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s\n",
346 		               connect_fn, strerror(errno));
347 		free(connect_fn);
348 		connect_fn = NULL;
349 		return -1;
350 	}
351 	return 0;
352 }
353 
354 /*
355  * Do the actual write to the open connection log file descriptor.
356  * We prepend a timestamp here, which means that timestamps are slightly
357  * delayed from the time of actual logging.  Since we only have second
358  * resolution that should not make any difference.
359  */
360 static ssize_t
log_connect_writecb(UNUSED int level,UNUSED void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)361 log_connect_writecb(UNUSED int level, UNUSED void *fh, UNUSED unsigned long ctl,
362                     const void *buf, size_t sz)
363 {
364 	char timebuf[32];
365 	time_t epoch;
366 	struct tm *utc;
367 	size_t n;
368 
369 	time(&epoch);
370 	utc = gmtime(&epoch);
371 	n = strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S UTC ", utc);
372 	if (n == 0) {
373 		log_err_level_printf(LOG_CRIT, "Error from strftime(): buffer too small\n");
374 		return -1;
375 	}
376 	if ((write(connect_fd, timebuf, n) == -1) ||
377 	    (write(connect_fd, buf, sz) == -1)) {
378 		log_err_level_printf(LOG_CRIT, "Failed to write to connect log: %s\n",
379 		               strerror(errno));
380 		return -1;
381 	}
382 	return sz;
383 }
384 
385 static void
log_connect_fini(void)386 log_connect_fini(void)
387 {
388 	close(connect_fd);
389 }
390 
391 static int
log_info(int facility,const char * buf)392 log_info(int facility, const char *buf)
393 {
394 	size_t sz = strlen(buf) + 1;
395 	switch (err_mode) {
396 		case LOG_ERR_MODE_STDERR:
397 			return fwrite(buf, sz - 1, 1, stderr);
398 		case LOG_ERR_MODE_SYSLOG:
399 			syslog(facility|LOG_INFO, "%s", (const char *)buf);
400 			return sz;
401 	}
402 	return -1;
403 }
404 
405 int
log_stats(const char * buf)406 log_stats(const char *buf)
407 {
408 	return log_info(LOG_LOCAL0, buf);
409 }
410 
411 int
log_conn(const char * buf)412 log_conn(const char *buf)
413 {
414 	return log_info(LOG_LOCAL1, buf);
415 }
416 
417 /*
418  * Content log.
419  * Logs connection content to either a single file or a directory containing
420  * per-connection logs.
421  * Uses a logger thread; the actual logging happens in a separate thread.
422  * To ensure ordering of requests (open, write, ..., close), logging for a
423  * single connection must happen from a single thread.
424  * This is guaranteed by the current pxythr architecture.
425  */
426 
427 #define PREPFLAG_REQUEST 1
428 #define PREPFLAG_EOF     2
429 
430 typedef struct log_content_file_ctx {
431 	union {
432 		struct {
433 			char *header_req;
434 			char *header_resp;
435 		} single;
436 		struct {
437 			int fd;
438 			char *filename;
439 		} dir;
440 		struct {
441 			int fd;
442 			char *filename;
443 		} spec;
444 	} u;
445 } log_content_file_ctx_t;
446 
447 typedef struct log_content_pcap_ctx {
448 	union {
449 		struct {
450 			int fd;
451 			char *filename;
452 		} dir;
453 		struct {
454 			int fd;
455 			char *filename;
456 		} spec;
457 	} u;
458 	logpkt_ctx_t state;
459 } log_content_pcap_ctx_t;
460 
461 #ifndef WITHOUT_MIRROR
462 typedef struct log_content_mirror_ctx {
463 	logpkt_ctx_t state;
464 } log_content_mirror_ctx_t;
465 #endif /* !WITHOUT_MIRROR */
466 
467 static int content_file_clisock = -1;
468 static logger_t *content_file_log = NULL;
469 static int content_pcap_clisock = -1;
470 static logger_t *content_pcap_log = NULL;
471 static uint8_t content_pcap_src_ether[ETHER_ADDR_LEN] = {
472 	0x02, 0x00, 0x00, 0x11, 0x11, 0x11};
473 static uint8_t content_pcap_dst_ether[ETHER_ADDR_LEN] = {
474 	0x02, 0x00, 0x00, 0x22, 0x22, 0x22};
475 #ifndef WITHOUT_MIRROR
476 static logger_t *content_mirror_log = NULL;
477 static libnet_t *content_mirror_libnet = NULL;
478 static size_t content_mirror_mtu = 0;
479 static uint8_t content_mirror_src_ether[ETHER_ADDR_LEN];
480 static uint8_t content_mirror_dst_ether[ETHER_ADDR_LEN];
481 #endif /* !WITHOUT_MIRROR */
482 
483 /*
484  * Split a pathname into static LHS (including final slashes) and dynamic RHS.
485  * Returns -1 on error, 0 on success.
486  * On success, fills in lhs and rhs with newly allocated buffers that must
487  * be freed by the caller.
488  */
489 int
log_content_split_pathspec(const char * path,char ** lhs,char ** rhs)490 log_content_split_pathspec(const char *path, char **lhs, char **rhs)
491 {
492 	const char *p, *q, *r;
493 
494 	p = strchr(path, '%');
495 	/* at first % or EOS */
496 
497 	/* skip % if next char is % (and implicitly not \0) */
498 	while (p && p[1] == '%') {
499 		p = strchr(p + 2, '%');
500 	}
501 	/* at first % that is not %%, or at EOS */
502 
503 	if (!p || !p[1]) {
504 		/* EOS: no % that is not %% in path */
505 		p = path + strlen(path);
506 	}
507 	/* at first hot % or at '\0' */
508 
509 	/* find last / before % */
510 	for (r = q = strchr(path, '/'); q && (q < p); q = strchr(q + 1, '/')) {
511 		r = q;
512 	}
513 	if (!(p = r)) {
514 		/* no / found, use dummy ./ as LHS */
515 		*lhs = strdup("./");
516 		if (!*lhs)
517 			return -1;
518 		*rhs = strdup(path);
519 		if (!*rhs) {
520 			free(*lhs);
521 			return -1;
522 		}
523 		return 0;
524 	}
525 	/* at last / terminating the static part of path */
526 
527 	p++; /* skip / */
528 	*lhs = malloc(p - path + 1 /* for terminating null */);
529 	if (!*lhs)
530 		return -1;
531 	memcpy(*lhs, path, p - path);
532 	(*lhs)[p - path] = '\0';
533 	*rhs = strdup(p);
534 	if (!*rhs) {
535 		free(*lhs);
536 		return -1;
537 	}
538 
539 	return 0;
540 }
541 
542 /*
543  * Generate a log path based on the given log spec.
544  * Returns an allocated buffer which must be freed by caller, or NULL on error.
545  */
546 #define PATH_BUF_INC	1024
547 static char * MALLOC NONNULL(1,2,3)
log_content_format_pathspec(const char * logspec,char * srchost,char * srcport,char * dsthost,char * dstport,char * exec_path,char * user,char * group)548 log_content_format_pathspec(const char *logspec,
549                             char *srchost, char *srcport,
550                             char *dsthost, char *dstport,
551                             char *exec_path, char *user, char *group)
552 {
553 	/* set up buffer to hold our generated file path */
554 	size_t path_buflen = PATH_BUF_INC;
555 	char *path_buf = malloc(path_buflen);
556 	if (path_buf == NULL) {
557 		log_err_level_printf(LOG_CRIT, "Failed to allocate path buffer\n");
558 		return NULL;
559 	}
560 
561 	/* initialize the buffer as an empty C string */
562 	path_buf[0] = '\0';
563 
564 	/* iterate over format specifiers */
565 	size_t path_len = 0;
566 	for (const char *p = logspec; *p != '\0'; p++) {
567 		const char *elem = NULL;
568 		size_t elem_len = 0;
569 
570 		const char iso8601[] =  "%Y%m%dT%H%M%SZ";
571 		char timebuf[24]; /* sized for ISO 8601 format */
572 		char addrbuf[INET6_ADDRSTRLEN + 8]; /* [host]:port */
573 
574 		/* parse the format string and generate the next path element */
575 		switch (*p) {
576 		case '%':
577 			p++;
578 			/* handle format specifiers. */
579 			switch (*p) {
580 			case '\0':
581 				/* unexpected eof; backtrack and discard
582 				 * invalid format spec */
583 				p--;
584 				elem_len = 0;
585 				break;
586 			case '%':
587 				elem = p;
588 				elem_len = 1;
589 				break;
590 			case 'd':
591 				if (snprintf(addrbuf, sizeof(addrbuf),
592 				             "%s,%s", dsthost, dstport) < 0) {
593 					addrbuf[0] = '?';
594 					addrbuf[1] = '\0';
595 				}
596 				elem = addrbuf;
597 				elem_len = strlen(addrbuf);
598 				break;
599 			case 'D':
600 				elem = dsthost;
601 				elem_len = strlen(dsthost);
602 				break;
603 			case 'p':
604 				elem = dstport;
605 				elem_len = strlen(dstport);
606 				break;
607 			case 's':
608 				if (snprintf(addrbuf, sizeof(addrbuf),
609 				             "%s,%s", srchost, srcport) < 0) {
610 					addrbuf[0] = '?';
611 					addrbuf[1] = '\0';
612 				}
613 				elem = addrbuf;
614 				elem_len = strlen(addrbuf);
615 				break;
616 			case 'S':
617 				elem = srchost;
618 				elem_len = strlen(srchost);
619 				break;
620 			case 'q':
621 				elem = srcport;
622 				elem_len = strlen(srcport);
623 				break;
624 			case 'x':
625 				if (exec_path) {
626 					char *match = exec_path;
627 					while ((match = strchr(match, '/')) != NULL) {
628 						match++;
629 						elem = match;
630 					}
631 					elem_len = elem ? strlen(elem) : 0;
632 				} else {
633 					elem_len = 0;
634 				}
635 				break;
636 			case 'X':
637 				elem = exec_path;
638 				elem_len = exec_path ? strlen(exec_path) : 0;
639 				break;
640 			case 'u':
641 				elem = user;
642 				elem_len = user ? strlen(user) : 0;
643 				break;
644 			case 'g':
645 				elem = group;
646 				elem_len = group ? strlen(group) : 0;
647 				break;
648 			case 'T': {
649 				time_t epoch;
650 				struct tm *utc;
651 
652 				time(&epoch);
653 				utc = gmtime(&epoch);
654 				strftime(timebuf, sizeof(timebuf), iso8601, utc);
655 
656 				elem = timebuf;
657 				elem_len = sizeof(timebuf);
658 				break;
659 			}}
660 			break;
661 		default:
662 			elem = p;
663 			elem_len = 1;
664 			break;
665 		}
666 
667 		if (elem_len > 0) {
668 			/* growing the buffer to fit elem_len + terminating \0 */
669 			if (path_buflen - path_len < elem_len + 1) {
670 				/* Grow in PATH_BUF_INC chunks.
671 				 * Note that the use of `PATH_BUF_INC' provides
672 				 * our guaranteed space for a trailing '\0' */
673 				path_buflen += elem_len + PATH_BUF_INC;
674 				char *newbuf = realloc(path_buf, path_buflen);
675 				if (newbuf == NULL) {
676 					log_err_level_printf(LOG_CRIT, "Failed to reallocate"
677 					               " path buffer\n");
678 					free(path_buf);
679 					return NULL;
680 				}
681 				path_buf = newbuf;
682 			}
683 
684 			strncat(path_buf, elem, elem_len);
685 			path_len += elem_len;
686 		}
687 	}
688 
689 	/* apply terminating NUL */
690 	assert(path_buflen > path_len);
691 	path_buf[path_len] = '\0';
692 	return path_buf;
693 }
694 #undef PATH_BUF_INC
695 
696 /*
697  * log_content_ctx_t is preallocated by the caller (part of connection ctx).
698  */
699 int
log_content_open(log_content_ctx_t * ctx,global_t * global,const struct sockaddr * srcaddr,socklen_t srcaddrlen,const struct sockaddr * dstaddr,socklen_t dstaddrlen,char * srchost,char * srcport,char * dsthost,char * dstport,char * exec_path,char * user,char * group,int log_content,int log_pcap,int log_mirror)700 log_content_open(log_content_ctx_t *ctx, global_t *global,
701                  const struct sockaddr *srcaddr, socklen_t srcaddrlen,
702                  const struct sockaddr *dstaddr, socklen_t dstaddrlen,
703                  char *srchost, char *srcport,
704                  char *dsthost, char *dstport,
705                  char *exec_path, char *user, char *group,
706                  int log_content, int log_pcap
707 #ifndef WITHOUT_MIRROR
708                  , int log_mirror
709 #endif /* !WITHOUT_MIRROR */
710 	)
711 {
712 	char timebuf[24];
713 	time_t epoch;
714 	struct tm *utc;
715 	char *dsthost_clean = NULL;
716 	char *srchost_clean = NULL;
717 
718 	if (ctx->file || ctx->pcap
719 #ifndef WITHOUT_MIRROR
720 	    || ctx->mirror
721 #endif /* !WITHOUT_MIRROR */
722 	    )
723 		return 0; /* does this actually happen? */
724 
725 	if (!log_content && !log_pcap
726 #ifndef WITHOUT_MIRROR
727 		&& !log_mirror
728 #endif /* !WITHOUT_MIRROR */
729 		) {
730 		return 0;
731 	}
732 
733 	if ((log_content && (global->contentlog_isdir || global->contentlog_isspec)) ||
734 	    (log_pcap && (global->pcaplog_isdir || global->pcaplog_isspec))) {
735 		if (global->contentlog_isdir || global->pcaplog_isdir) {
736 			if (time(&epoch) == -1) {
737 				log_err_level_printf(LOG_CRIT, "Failed to get time\n");
738 				goto errout;
739 			}
740 			if ((utc = gmtime(&epoch)) == NULL) {
741 				log_err_level_printf(LOG_CRIT, "Failed to convert time:"
742 				               " %s (%i)\n",
743 				               strerror(errno), errno);
744 				goto errout;
745 			}
746 			if (!strftime(timebuf, sizeof(timebuf),
747 			              "%Y%m%dT%H%M%SZ", utc)) {
748 				log_err_level_printf(LOG_CRIT, "Failed to format time:"
749 				               " %s (%i)\n",
750 				               strerror(errno), errno);
751 				goto errout;
752 			}
753 		}
754 
755 		srchost_clean = sys_ip46str_sanitize(srchost);
756 		if (!srchost_clean) {
757 			log_err_level_printf(LOG_CRIT, "Failed to sanitize srchost\n");
758 			goto errout;
759 		}
760 		dsthost_clean = sys_ip46str_sanitize(dsthost);
761 		if (!dsthost_clean) {
762 			log_err_level_printf(LOG_CRIT, "Failed to sanitize dsthost\n");
763 			free(srchost_clean);
764 			goto errout;
765 		}
766 	}
767 
768 	if (log_content && global->contentlog) {
769 		ctx->file = malloc(sizeof(log_content_file_ctx_t));
770 		if (!ctx->file)
771 			goto errout;
772 		memset(ctx->file, 0, sizeof(log_content_file_ctx_t));
773 
774 		if (global->contentlog_isdir) {
775 			/* per-connection-file content log (-S) */
776 			if (asprintf(&ctx->file->u.dir.filename,
777 			             "%s/%s-%s,%s-%s,%s.log",
778 			             global->contentlog, timebuf,
779 			             srchost_clean, srcport,
780 			             dsthost_clean, dstport) < 0) {
781 				log_err_level_printf(LOG_CRIT, "Failed to format filename:"
782 				               " %s (%i)\n",
783 				               strerror(errno), errno);
784 				goto errout;
785 			}
786 		} else if (global->contentlog_isspec) {
787 			/* per-connection-file content log with logspec (-F) */
788 			ctx->file->u.spec.filename =
789 				log_content_format_pathspec(global->contentlog,
790 				                            srchost_clean,
791 				                            srcport,
792 				                            dsthost_clean,
793 				                            dstport,
794 				                            exec_path,
795 				                            user, group);
796 			if (!ctx->file->u.spec.filename) {
797 				goto errout;
798 			}
799 		} else {
800 			/* single-file content log (-L) */
801 			if (asprintf(&ctx->file->u.single.header_req,
802 			             "[%s]:%s -> [%s]:%s",
803 			             srchost, srcport, dsthost, dstport) < 0) {
804 				goto errout;
805 			}
806 			if (asprintf(&ctx->file->u.single.header_resp,
807 			             "[%s]:%s -> [%s]:%s",
808 			             dsthost, dstport, srchost, srcport) < 0) {
809 				free(ctx->file->u.single.header_req);
810 				goto errout;
811 			}
812 		}
813 	}
814 
815 	if (log_pcap && global->pcaplog) {
816 		ctx->pcap = malloc(sizeof(log_content_pcap_ctx_t));
817 		if (!ctx->pcap)
818 			goto errout;
819 		memset(ctx->pcap, 0, sizeof(log_content_pcap_ctx_t));
820 
821 		logpkt_ctx_init(&ctx->pcap->state, NULL, 0,
822 		                content_pcap_src_ether, content_pcap_dst_ether,
823 		                srcaddr, srcaddrlen, dstaddr, dstaddrlen);
824 
825 		if (global->pcaplog_isdir) {
826 			/* per-connection-file pcap log (-Y) */
827 			if (asprintf(&ctx->pcap->u.dir.filename,
828 			             "%s/%s-%s,%s-%s,%s.pcap",
829 			             global->pcaplog, timebuf,
830 			             srchost_clean, srcport,
831 			             dsthost_clean, dstport) < 0) {
832 				log_err_level_printf(LOG_CRIT, "Failed to format filename:"
833 				               " %s (%i)\n",
834 				               strerror(errno), errno);
835 				goto errout;
836 			}
837 		} else if (global->pcaplog_isspec) {
838 			/* per-connection-file pcap log with logspec (-y) */
839 			ctx->pcap->u.spec.filename =
840 				log_content_format_pathspec(global->pcaplog,
841 				                            srchost_clean,
842 				                            srcport,
843 				                            dsthost_clean,
844 				                            dstport,
845 				                            exec_path,
846 				                            user, group);
847 			if (!ctx->pcap->u.spec.filename) {
848 				goto errout;
849 			}
850 		}
851 	}
852 
853 #ifndef WITHOUT_MIRROR
854 	if (log_mirror && global->mirrorif) {
855 		ctx->mirror = malloc(sizeof(log_content_mirror_ctx_t));
856 		if (!ctx->mirror)
857 			goto errout;
858 		memset(ctx->mirror, 0, sizeof(log_content_mirror_ctx_t));
859 
860 		logpkt_ctx_init(&ctx->mirror->state,
861 		                content_mirror_libnet,
862 		                content_mirror_mtu,
863 		                content_mirror_src_ether,
864 		                content_mirror_dst_ether,
865 		                srcaddr, srcaddrlen, dstaddr, dstaddrlen);
866 	}
867 #endif /* !WITHOUT_MIRROR */
868 
869 	/* submit open events */
870 	if (log_content && ctx->file) {
871 		if (logger_open(content_file_log, ctx->file) == -1)
872 			goto errout;
873 	}
874 	if (log_pcap && ctx->pcap) {
875 		if (logger_open(content_pcap_log, ctx->pcap) == -1)
876 			goto errout;
877 	}
878 #ifndef WITHOUT_MIRROR
879 	if (log_mirror && ctx->mirror) {
880 		if (logger_open(content_mirror_log, ctx->mirror) == -1)
881 			goto errout;
882 	}
883 #endif /* !WITHOUT_MIRROR */
884 
885 	if (srchost_clean)
886 		free(srchost_clean);
887 	if (dsthost_clean)
888 		free(dsthost_clean);
889 	return 0;
890 
891 errout:
892 	if (srchost_clean)
893 		free(srchost_clean);
894 	if (dsthost_clean)
895 		free(dsthost_clean);
896 	if (ctx->file)
897 		free(ctx->file);
898 	if (ctx->pcap) {
899 		free(ctx->pcap);
900 	}
901 #ifndef WITHOUT_MIRROR
902 	if (ctx->mirror) {
903 		free(ctx->mirror);
904 	}
905 #endif /* !WITHOUT_MIRROR */
906 	memset(ctx, 0, sizeof(log_content_ctx_t));
907 	return -1;
908 }
909 
910 /*
911  * On failure, lb is not freed.
912  */
913 int
log_content_submit(log_content_ctx_t * ctx,logbuf_t * lb,int is_request,int log_content,int log_pcap,int log_mirror)914 log_content_submit(log_content_ctx_t *ctx, logbuf_t *lb, int is_request, int log_content, int log_pcap
915 #ifndef WITHOUT_MIRROR
916 	, int log_mirror
917 #endif /* !WITHOUT_MIRROR */
918 	)
919 {
920 	unsigned long prepflags = 0;
921 	logbuf_t *lbpcap, *lbmirror;
922 
923 	if (is_request)
924 		prepflags |= PREPFLAG_REQUEST;
925 
926 	lb = logbuf_make_contiguous(lb);
927 	if (!lb)
928 		return -1;
929 
930 	lbpcap = lbmirror = lb;
931 	if (log_content && content_file_log) {
932 		if (log_pcap && content_pcap_log) {
933 			lbpcap = logbuf_new_deepcopy(lb, 1);
934 			if (!lbpcap)
935 				goto errout;
936 		}
937 #ifndef WITHOUT_MIRROR
938 		if (log_mirror && content_mirror_log) {
939 			lbmirror = logbuf_new_deepcopy(lb, 1);
940 			if (!lbmirror)
941 				goto errout;
942 		}
943 	} else if (log_pcap && content_pcap_log && log_mirror && content_mirror_log) {
944 		lbmirror = logbuf_new_deepcopy(lb, 1);
945 		if (!lbmirror)
946 			goto errout;
947 #endif /* !WITHOUT_MIRROR */
948 	}
949 
950 	if (log_pcap && content_pcap_log) {
951 		if (logger_submit(content_pcap_log, ctx->pcap,
952 		                  prepflags, lbpcap) == -1) {
953 			goto errout;
954 		}
955 		lbpcap = NULL;
956 	}
957 #ifndef WITHOUT_MIRROR
958 	if (log_mirror && content_mirror_log) {
959 		if (logger_submit(content_mirror_log, ctx->mirror,
960 		                  prepflags, lbmirror) == -1) {
961 			goto errout;
962 		}
963 		lbmirror = NULL;
964 	}
965 #endif /* !WITHOUT_MIRROR */
966 	if (log_content && content_file_log) {
967 		if (logger_submit(content_file_log, ctx->file,
968 		                  prepflags, lb) == -1) {
969 			return -1;
970 		}
971 	}
972 	return 0;
973 errout:
974 	if (lbpcap && lbpcap != lb)
975 		logbuf_free(lbpcap);
976 	if (lbmirror && lbmirror != lb)
977 		logbuf_free(lbmirror);
978 	return -1;
979 }
980 
981 int
log_content_close(log_content_ctx_t * ctx,int by_requestor)982 log_content_close(log_content_ctx_t *ctx, int by_requestor)
983 {
984 	unsigned long prepflags = PREPFLAG_EOF;
985 	unsigned long ctl;
986 
987 	if (by_requestor) {
988 		prepflags |= PREPFLAG_REQUEST;
989 		ctl = LBFLAG_IS_REQ;
990 	} else {
991 		ctl = LBFLAG_IS_RESP;
992 	}
993 
994 	/* We call submit an empty log buffer in order to give the content log
995 	 * a chance to insert an EOF footer to be logged before actually
996 	 * closing the file.  The logger_close() call will actually close the
997 	 * log.  Some logs prefer to use the close callback for logging the
998 	 * close event to the log. */
999 	if (content_file_log && ctx->file) {
1000 		if (logger_submit(content_file_log, ctx->file,
1001 		                  prepflags, NULL) == -1) {
1002 			return -1;
1003 		}
1004 		if (logger_close(content_file_log, ctx->file, ctl) == -1) {
1005 			return -1;
1006 		}
1007 		ctx->file = NULL;
1008 	}
1009 	if (content_pcap_log && ctx->pcap) {
1010 		if (logger_submit(content_pcap_log, ctx->pcap,
1011 		                  prepflags, NULL) == -1) {
1012 			return -1;
1013 		}
1014 		if (logger_close(content_pcap_log, ctx->pcap, ctl) == -1) {
1015 			return -1;
1016 		}
1017 		ctx->pcap = NULL;
1018 	}
1019 #ifndef WITHOUT_MIRROR
1020 	if (content_mirror_log && ctx->mirror) {
1021 		if (logger_submit(content_mirror_log, ctx->mirror,
1022 		                  prepflags, NULL) == -1) {
1023 			return -1;
1024 		}
1025 		if (logger_close(content_mirror_log, ctx->mirror, ctl) == -1) {
1026 			return -1;
1027 		}
1028 		ctx->mirror = NULL;
1029 	}
1030 #endif /* !WITHOUT_MIRROR */
1031 	return 0;
1032 }
1033 
1034 /*
1035  * Log-type specific code.
1036  *
1037  * The init/fini functions are executed globally in the main thread.
1038  * Callback functions are executed in the logger thread.
1039  */
1040 
1041 static int
log_content_file_dir_opencb(void * fh)1042 log_content_file_dir_opencb(void *fh)
1043 {
1044 	log_content_file_ctx_t *ctx = fh;
1045 
1046 	if ((ctx->u.dir.fd = privsep_client_openfile(content_file_clisock,
1047 	                                             ctx->u.dir.filename,
1048 	                                             0)) == -1) {
1049 		log_err_level_printf(LOG_CRIT, "Opening logdir file '%s' failed: %s (%i)\n",
1050 		               ctx->u.dir.filename,
1051 		               strerror(errno), errno);
1052 		return -1;
1053 	}
1054 	return 0;
1055 }
1056 
1057 static void
log_content_file_dir_closecb(void * fh,UNUSED unsigned long ctl)1058 log_content_file_dir_closecb(void *fh, UNUSED unsigned long ctl)
1059 {
1060 	log_content_file_ctx_t *ctx = fh;
1061 
1062 	if (ctx->u.dir.filename)
1063 		free(ctx->u.dir.filename);
1064 	if (ctx->u.dir.fd != 1)
1065 		close(ctx->u.dir.fd);
1066 	free(ctx);
1067 }
1068 
1069 static ssize_t
log_content_file_dir_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1070 log_content_file_dir_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1071                              const void *buf, size_t sz)
1072 {
1073 	log_content_file_ctx_t *ctx = fh;
1074 
1075 	if (write(ctx->u.dir.fd, buf, sz) == -1) {
1076 		log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1077 		               strerror(errno));
1078 		return -1;
1079 	}
1080 	return sz;
1081 }
1082 
1083 static int
log_content_file_spec_opencb(void * fh)1084 log_content_file_spec_opencb(void *fh)
1085 {
1086 	log_content_file_ctx_t *ctx = fh;
1087 
1088 	if ((ctx->u.spec.fd = privsep_client_openfile(content_file_clisock,
1089 	                                              ctx->u.spec.filename,
1090 	                                              1)) == -1) {
1091 		log_err_level_printf(LOG_CRIT, "Opening logspec file '%s' failed: %s (%i)\n",
1092 		               ctx->u.spec.filename, strerror(errno), errno);
1093 		return -1;
1094 	}
1095 	return 0;
1096 }
1097 
1098 static void
log_content_file_spec_closecb(void * fh,UNUSED unsigned long ctl)1099 log_content_file_spec_closecb(void *fh, UNUSED unsigned long ctl)
1100 {
1101 	log_content_file_ctx_t *ctx = fh;
1102 
1103 	if (ctx->u.spec.filename)
1104 		free(ctx->u.spec.filename);
1105 	if (ctx->u.spec.fd != -1)
1106 		close(ctx->u.spec.fd);
1107 	free(ctx);
1108 }
1109 
1110 static ssize_t
log_content_file_spec_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1111 log_content_file_spec_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1112                               const void *buf, size_t sz)
1113 {
1114 	log_content_file_ctx_t *ctx = fh;
1115 
1116 	if (write(ctx->u.spec.fd, buf, sz) == -1) {
1117 		log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1118 		               strerror(errno));
1119 		return -1;
1120 	}
1121 	return sz;
1122 }
1123 
1124 static int content_file_single_fd = -1;
1125 static char *content_file_single_fn = NULL;
1126 
1127 static int
log_content_file_single_preinit(const char * logfile)1128 log_content_file_single_preinit(const char *logfile)
1129 {
1130 	content_file_single_fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT,
1131 	                       DFLT_FILEMODE);
1132 	if (content_file_single_fd == -1) {
1133 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1134 		               logfile, strerror(errno), errno);
1135 		return -1;
1136 	}
1137 	content_file_single_fn = strdup(logfile);
1138 	if (!content_file_single_fn) {
1139 		close(content_file_single_fd);
1140 		content_file_single_fd = -1;
1141 		return -1;
1142 	}
1143 	return 0;
1144 }
1145 
1146 static void
log_content_file_single_fini(void)1147 log_content_file_single_fini(void)
1148 {
1149 	if (content_file_single_fn) {
1150 		free(content_file_single_fn);
1151 		content_file_single_fn = NULL;
1152 	}
1153 	if (content_file_single_fd != -1) {
1154 		close(content_file_single_fd);
1155 		content_file_single_fd = -1;
1156 	}
1157 }
1158 
1159 static int
log_content_file_single_reopencb(void)1160 log_content_file_single_reopencb(void)
1161 {
1162 	close(content_file_single_fd);
1163 	content_file_single_fd = privsep_client_openfile(content_file_clisock,
1164 	                                                 content_file_single_fn,
1165 	                                                 0);
1166 	if (content_file_single_fd == -1) {
1167 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1168 		               content_file_single_fn, strerror(errno), errno);
1169 		return -1;
1170 	}
1171 	return 0;
1172 }
1173 
1174 static void
log_content_file_single_closecb(void * fh,UNUSED unsigned long ctl)1175 log_content_file_single_closecb(void *fh, UNUSED unsigned long ctl)
1176 {
1177 	log_content_file_ctx_t *ctx = fh;
1178 
1179 	if (ctx->u.single.header_req) {
1180 		free(ctx->u.single.header_req);
1181 	}
1182 	if (ctx->u.single.header_resp) {
1183 		free(ctx->u.single.header_resp);
1184 	}
1185 	free(ctx);
1186 }
1187 
1188 static ssize_t
log_content_file_single_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1189 log_content_file_single_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1190                                 const void *buf, size_t sz)
1191 {
1192 	UNUSED log_content_file_ctx_t *ctx = fh;
1193 
1194 	if (write(content_file_single_fd, buf, sz) == -1) {
1195 		log_err_level_printf(LOG_CRIT, "Failed to write to content log: %s\n",
1196 		               strerror(errno));
1197 		return -1;
1198 	}
1199 	return sz;
1200 }
1201 
1202 static logbuf_t *
log_content_file_single_prepcb(void * fh,unsigned long prepflags,logbuf_t * lb)1203 log_content_file_single_prepcb(void *fh, unsigned long prepflags,
1204                                logbuf_t *lb)
1205 {
1206 	log_content_file_ctx_t *ctx = fh;
1207 	int is_request = !!(prepflags & PREPFLAG_REQUEST);
1208 	logbuf_t *head;
1209 	time_t epoch;
1210 	struct tm *utc;
1211 	char *header;
1212 
1213 	if (!(header = is_request ? ctx->u.single.header_req
1214 	                          : ctx->u.single.header_resp))
1215 		goto out;
1216 
1217 	/* prepend size tag or EOF, and newline */
1218 	if (prepflags & PREPFLAG_EOF) {
1219 		head = logbuf_new_printf(NULL, " (EOF)\n");
1220 	} else {
1221 		head = logbuf_new_printf(lb, " (%zu):\n", logbuf_size(lb));
1222 	}
1223 	if (!head) {
1224 		log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1225 		logbuf_free(lb);
1226 		return NULL;
1227 	}
1228 	lb = head;
1229 
1230 	/* prepend header */
1231 	head = logbuf_new_copy(header, strlen(header), lb);
1232 	if (!head) {
1233 		log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1234 		logbuf_free(lb);
1235 		return NULL;
1236 	}
1237 	lb = head;
1238 
1239 	/* prepend timestamp */
1240 	head = logbuf_new_alloc(32, lb);
1241 	if (!head) {
1242 		log_err_level_printf(LOG_CRIT, "Failed to allocate memory\n");
1243 		logbuf_free(lb);
1244 		return NULL;
1245 	}
1246 	lb = head;
1247 	time(&epoch);
1248 	utc = gmtime(&epoch);
1249 	lb->sz = strftime((char*)lb->buf, lb->sz, "%Y-%m-%d %H:%M:%S UTC ",
1250 	                  utc);
1251 
1252 out:
1253 	return lb;
1254 }
1255 
1256 /*
1257  * Pcap writer for -X/-Y/-y options.
1258  */
1259 static int content_pcap_fd = -1;
1260 static char *content_pcap_fn = NULL;
1261 
1262 /*
1263  * Initialize pcap content logging.  For single-file mode, pcapfile is the
1264  * path to the file.  For dir/spec modes, pcapfile is NULL.
1265  */
1266 static int
log_content_pcap_preinit(const char * pcapfile)1267 log_content_pcap_preinit(const char *pcapfile)
1268 {
1269 	if (!pcapfile)
1270 		return 0;
1271 
1272 	/* single file pcap mode */
1273 
1274 	content_pcap_fd = open(pcapfile, O_RDWR|O_CREAT, DFLT_FILEMODE);
1275 	if (content_pcap_fd == -1) {
1276 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1277 		               pcapfile, strerror(errno), errno);
1278 		return -1;
1279 	}
1280 	if (logpkt_pcap_open_fd(content_pcap_fd) == -1) {
1281 		log_err_level_printf(LOG_CRIT, "Failed to prepare '%s' for PCAP writing"
1282 		               ": %s (%i)\n",
1283 		               pcapfile, strerror(errno), errno);
1284 		close(content_pcap_fd);
1285 		content_pcap_fd = -1;
1286 		return -1;
1287 	}
1288 	content_pcap_fn = strdup(pcapfile);
1289 	if (!content_pcap_fn) {
1290 		close(content_pcap_fd);
1291 		content_pcap_fd = -1;
1292 		return -1;
1293 	}
1294 	return 0;
1295 }
1296 
1297 static void
log_content_pcap_fini(void)1298 log_content_pcap_fini(void)
1299 {
1300 	if (content_pcap_fn) {
1301 		free(content_pcap_fn);
1302 		content_pcap_fn = NULL;
1303 	}
1304 	if (content_pcap_fd != -1) {
1305 		close(content_pcap_fd);
1306 		content_pcap_fd = -1;
1307 	}
1308 }
1309 
1310 static int
log_content_pcap_reopencb(void)1311 log_content_pcap_reopencb(void) {
1312 	close(content_pcap_fd);
1313 	content_pcap_fd = privsep_client_openfile(content_pcap_clisock,
1314 	                                          content_pcap_fn,
1315 	                                          0);
1316 	if (content_pcap_fd == -1) {
1317 		log_err_level_printf(LOG_CRIT, "Failed to open '%s' for writing: %s (%i)\n",
1318 		               content_pcap_fn, strerror(errno), errno);
1319 		return -1;
1320 	}
1321 	if (logpkt_pcap_open_fd(content_pcap_fd) == -1) {
1322 		log_err_level_printf(LOG_CRIT, "Failed to prepare '%s' for PCAP writing"
1323 		               ": %s (%i)\n",
1324 		               content_pcap_fn, strerror(errno), errno);
1325 		close(content_pcap_fd);
1326 		content_pcap_fd = -1;
1327 		return -1;
1328 	}
1329 	return 0;
1330 }
1331 
1332 static void
log_content_pcap_closecb_base(void * fh,unsigned long ctl,int fd)1333 log_content_pcap_closecb_base(void *fh, unsigned long ctl, int fd) {
1334 	log_content_pcap_ctx_t *ctx = fh;
1335 	int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1336 	                                      : LOGPKT_RESPONSE;
1337 
1338 	logpkt_write_close(&ctx->state, fd, direction);
1339 }
1340 
1341 static void
log_content_pcap_closecb(void * fh,unsigned long ctl)1342 log_content_pcap_closecb(void *fh, unsigned long ctl) {
1343 	log_content_pcap_ctx_t *ctx = fh;
1344 	log_content_pcap_closecb_base(fh, ctl, content_pcap_fd);
1345 	free(ctx);
1346 }
1347 
1348 static ssize_t
log_content_pcap_writecb_base(void * fh,unsigned long ctl,const void * buf,size_t sz,int fd)1349 log_content_pcap_writecb_base(void *fh, unsigned long ctl,
1350                               const void *buf, size_t sz, int fd) {
1351 	log_content_pcap_ctx_t *ctx = fh;
1352 	int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1353 	                                      : LOGPKT_RESPONSE;
1354 
1355 	if (logpkt_write_payload(&ctx->state, fd, direction, buf, sz) == -1)
1356 		goto errout;
1357 
1358 	return sz;
1359 errout:
1360 	log_err_level_printf(LOG_CRIT, "Failed to write to pcap log: %s (%i)\n",
1361 	               strerror(errno), errno);
1362 	return -1;
1363 }
1364 
1365 static ssize_t
log_content_pcap_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1366 log_content_pcap_writecb(UNUSED int level, void *fh, unsigned long ctl,
1367                          const void *buf, size_t sz) {
1368 	return log_content_pcap_writecb_base(fh, ctl, buf, sz, content_pcap_fd);
1369 }
1370 
1371 static int
log_content_pcap_dir_opencb(void * fh)1372 log_content_pcap_dir_opencb(void *fh)
1373 {
1374 	log_content_pcap_ctx_t *ctx = fh;
1375 
1376 	if ((ctx->u.dir.fd = privsep_client_openfile(content_pcap_clisock,
1377 	                                             ctx->u.dir.filename,
1378 	                                             0)) == -1) {
1379 		log_err_level_printf(LOG_CRIT, "Opening pcapdir file '%s' failed: %s (%i)\n",
1380 		               ctx->u.dir.filename, strerror(errno), errno);
1381 		return -1;
1382 	}
1383 	return logpkt_pcap_open_fd(ctx->u.dir.fd);
1384 }
1385 
1386 static void
log_content_pcap_dir_closecb(void * fh,unsigned long ctl)1387 log_content_pcap_dir_closecb(void *fh, unsigned long ctl)
1388 {
1389 	log_content_pcap_ctx_t *ctx = fh;
1390 	log_content_pcap_closecb_base(fh, ctl, ctx->u.dir.fd);
1391 	if (ctx->u.dir.filename)
1392 		free(ctx->u.dir.filename);
1393 	if (ctx->u.dir.fd != -1)
1394 		close(ctx->u.dir.fd);
1395 	free(ctx);
1396 }
1397 
1398 static ssize_t
log_content_pcap_dir_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1399 log_content_pcap_dir_writecb(UNUSED int level, void *fh, unsigned long ctl,
1400                              const void *buf, size_t sz)
1401 {
1402 	log_content_pcap_ctx_t *ctx = fh;
1403 	return log_content_pcap_writecb_base(fh, ctl, buf, sz, ctx->u.dir.fd);
1404 }
1405 
1406 static int
log_content_pcap_spec_opencb(void * fh)1407 log_content_pcap_spec_opencb(void *fh)
1408 {
1409 	log_content_pcap_ctx_t *ctx = fh;
1410 
1411 	if ((ctx->u.spec.fd = privsep_client_openfile(content_pcap_clisock,
1412 	                                              ctx->u.spec.filename,
1413 	                                              1)) == -1) {
1414 		log_err_level_printf(LOG_CRIT, "Opening pcapspec file '%s' failed: %s (%i)\n",
1415 		               ctx->u.spec.filename, strerror(errno), errno);
1416 		return -1;
1417 	}
1418 	return logpkt_pcap_open_fd(ctx->u.spec.fd);
1419 }
1420 
1421 static void
log_content_pcap_spec_closecb(void * fh,unsigned long ctl)1422 log_content_pcap_spec_closecb(void *fh, unsigned long ctl)
1423 {
1424 	log_content_pcap_ctx_t *ctx = fh;
1425 	log_content_pcap_closecb_base(fh, ctl, ctx->u.spec.fd);
1426 	if (ctx->u.spec.filename)
1427 		free(ctx->u.spec.filename);
1428 	if (ctx->u.spec.fd != -1)
1429 		close(ctx->u.spec.fd);
1430 	free(ctx);
1431 }
1432 
1433 static ssize_t
log_content_pcap_spec_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1434 log_content_pcap_spec_writecb(UNUSED int level, void *fh, unsigned long ctl,
1435                               const void *buf, size_t sz)
1436 {
1437 	log_content_pcap_ctx_t *ctx = fh;
1438 	return log_content_pcap_writecb_base(fh, ctl, buf, sz, ctx->u.spec.fd);
1439 }
1440 
1441 static logbuf_t *
log_content_pcap_prepcb(UNUSED void * fh,unsigned long prepflags,logbuf_t * lb)1442 log_content_pcap_prepcb(UNUSED void *fh, unsigned long prepflags,
1443                         logbuf_t *lb) {
1444 	/* log_content_pcap_ctx_t *ctx = fh; */
1445 	if (prepflags & PREPFLAG_EOF)
1446 		return lb;
1447 	logbuf_ctl_set(lb, (prepflags & PREPFLAG_REQUEST) ? LBFLAG_IS_REQ
1448 	                                                  : LBFLAG_IS_RESP);
1449 	return lb;
1450 }
1451 
1452 /*
1453  * Mirror writer for -T/-I options.
1454  */
1455 
1456 #ifndef WITHOUT_MIRROR
1457 static int
log_content_mirror_preinit(const char * ifname,const char * targetip)1458 log_content_mirror_preinit(const char *ifname, const char *targetip) {
1459 	char errbuf[LIBNET_ERRBUF_SIZE];
1460 
1461 	/* cast to char* needed on OpenBSD */
1462 	content_mirror_libnet = libnet_init(LIBNET_LINK, (char *)ifname,
1463 	                                    errbuf);
1464 	if (content_mirror_libnet == NULL) {
1465 		log_err_level_printf(LOG_CRIT, "Failed to init mirror libnet: %s\n", errbuf);
1466 		return -1;
1467 	}
1468 	libnet_seed_prand(content_mirror_libnet);
1469 
1470 	content_mirror_mtu = sys_get_mtu(ifname);
1471 	if (content_mirror_mtu == 0) {
1472 		log_err_level_printf(LOG_CRIT, "Failed to lookup MTU of interface %s\n",
1473 		               ifname);
1474 		return -1;
1475 	}
1476 
1477 	if (logpkt_ether_lookup(content_mirror_libnet,
1478 	                        content_mirror_src_ether,
1479 	                        content_mirror_dst_ether,
1480 	                        targetip, ifname) == -1) {
1481 		log_err_level_printf(LOG_CRIT, "Failed to lookup target ether\n");
1482 		libnet_destroy(content_mirror_libnet);
1483 		return -1;
1484 	}
1485 
1486 	return 0;
1487 }
1488 
1489 static void
log_content_mirror_fini(void)1490 log_content_mirror_fini(void)
1491 {
1492 	if (content_mirror_libnet) {
1493 		libnet_destroy(content_mirror_libnet);
1494 	}
1495 }
1496 
1497 static void
log_content_mirror_closecb(void * fh,unsigned long ctl)1498 log_content_mirror_closecb(void *fh, unsigned long ctl) {
1499 	log_content_mirror_ctx_t *ctx = fh;
1500 	int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1501 	                                      : LOGPKT_RESPONSE;
1502 
1503 	logpkt_write_close(&ctx->state, -1, direction);
1504 	free(ctx);
1505 }
1506 
1507 static ssize_t
log_content_mirror_writecb(UNUSED int level,void * fh,unsigned long ctl,const void * buf,size_t sz)1508 log_content_mirror_writecb(UNUSED int level, void *fh, unsigned long ctl,
1509                            const void *buf, size_t sz) {
1510 	log_content_mirror_ctx_t *ctx = fh;
1511 	int direction = (ctl & LBFLAG_IS_REQ) ? LOGPKT_REQUEST
1512 	                                      : LOGPKT_RESPONSE;
1513 
1514 	if (logpkt_write_payload(&ctx->state, -1, direction, buf, sz) == -1)
1515 		goto errout;
1516 	return sz;
1517 
1518 errout:
1519 	log_err_level_printf(LOG_CRIT, "Failed to write to mirror log: %s (%i)\n",
1520 	               strerror(errno), errno);
1521 	return -1;
1522 }
1523 
1524 static logbuf_t *
log_content_mirror_prepcb(UNUSED void * fh,unsigned long prepflags,logbuf_t * lb)1525 log_content_mirror_prepcb(UNUSED void *fh, unsigned long prepflags,
1526                           logbuf_t *lb) {
1527 	/* log_content_mirror_ctx_t *ctx = fh; */
1528 	if (prepflags & PREPFLAG_EOF)
1529 		return lb;
1530 	logbuf_ctl_set(lb, (prepflags & PREPFLAG_REQUEST) ? LBFLAG_IS_REQ
1531 	                                                  : LBFLAG_IS_RESP);
1532 	return lb;
1533 }
1534 #endif /* !WITHOUT_MIRROR */
1535 
1536 /*
1537  * Certificate writer for -w/-W options.
1538  */
1539 static logger_t *cert_log = NULL;
1540 static int cert_clisock = -1; /* privsep client socket for cert logger */
1541 
1542 int
log_cert_submit(const char * fn,X509 * crt)1543 log_cert_submit(const char *fn, X509 *crt)
1544 {
1545 	void *fh;
1546 	logbuf_t *lb;
1547 	char *pem;
1548 
1549 	if (!(fh = strdup(fn)))
1550 		goto errout1;
1551 	if (!(pem = ssl_x509_to_pem(crt)))
1552 		goto errout2;
1553 	if (!(lb = logbuf_new(0, pem, strlen(pem), NULL)))
1554 		goto errout3;
1555 	return logger_submit(cert_log, fh, 0, lb);
1556 errout3:
1557 	free(pem);
1558 errout2:
1559 	free(fh);
1560 errout1:
1561 	return -1;
1562 }
1563 
1564 static ssize_t
log_cert_writecb(UNUSED int level,void * fh,UNUSED unsigned long ctl,const void * buf,size_t sz)1565 log_cert_writecb(UNUSED int level, void *fh, UNUSED unsigned long ctl,
1566                  const void *buf, size_t sz)
1567 {
1568 	char *fn = fh;
1569 	int fd;
1570 
1571 	if ((fd = privsep_client_certfile(cert_clisock, fn)) == -1) {
1572 		if (errno != EEXIST) {
1573 			log_err_level_printf(LOG_CRIT, "Failed to open '%s': %s (%i)\n",
1574 			               fn, strerror(errno), errno);
1575 			return -1;
1576 		}
1577 		return sz;
1578 	}
1579 	if (write(fd, buf, sz) == -1) {
1580 		log_err_level_printf(LOG_CRIT, "Failed to write to '%s': %s (%i)\n",
1581 		               fn, strerror(errno), errno);
1582 		close(fd);
1583 		return -1;
1584 	}
1585 	close(fd);
1586 	return sz;
1587 }
1588 
1589 
1590 /*
1591  * Initialization and destruction.
1592  */
1593 
1594 /*
1595  * Log pre-init: open all log files but don't start any threads, since we may
1596  * fork() after pre-initialization.
1597  * Return -1 on errors, 0 otherwise.
1598  */
1599 int
log_preinit(global_t * global)1600 log_preinit(global_t *global)
1601 {
1602 	logger_reopen_func_t reopencb;
1603 	logger_open_func_t opencb;
1604 	logger_close_func_t closecb;
1605 	logger_write_func_t writecb;
1606 	logger_prep_func_t prepcb;
1607 
1608 	if (global->contentlog) {
1609 		if (global->contentlog_isdir) {
1610 			reopencb = NULL;
1611 			opencb = log_content_file_dir_opencb;
1612 			closecb = log_content_file_dir_closecb;
1613 			writecb = log_content_file_dir_writecb;
1614 			prepcb = NULL;
1615 		} else if (global->contentlog_isspec) {
1616 			reopencb = NULL;
1617 			opencb = log_content_file_spec_opencb;
1618 			closecb = log_content_file_spec_closecb;
1619 			writecb = log_content_file_spec_writecb;
1620 			prepcb = NULL;
1621 		} else {
1622 			if (log_content_file_single_preinit(global->contentlog) == -1)
1623 				goto out;
1624 			reopencb = log_content_file_single_reopencb;
1625 			opencb = NULL;
1626 			closecb = log_content_file_single_closecb;
1627 			writecb = log_content_file_single_writecb;
1628 			prepcb = log_content_file_single_prepcb;
1629 		}
1630 		if (!(content_file_log = logger_new(reopencb, opencb, closecb,
1631 		                                    writecb, prepcb,
1632 		                                    log_exceptcb))) {
1633 			log_content_file_single_fini();
1634 			goto out;
1635 		}
1636 	}
1637 	if (global->pcaplog) {
1638 		if (log_content_pcap_preinit((global->pcaplog_isdir ||
1639 		                              global->pcaplog_isspec) ?
1640 		                              NULL :
1641 		                              global->pcaplog) == -1)
1642 			goto out;
1643 		if (global->pcaplog_isdir) {
1644 			reopencb = NULL;
1645 			opencb = log_content_pcap_dir_opencb;
1646 			closecb = log_content_pcap_dir_closecb;
1647 			writecb = log_content_pcap_dir_writecb;
1648 			prepcb = log_content_pcap_prepcb;
1649 		} else if (global->pcaplog_isspec) {
1650 			reopencb = NULL;
1651 			opencb = log_content_pcap_spec_opencb;
1652 			closecb = log_content_pcap_spec_closecb;
1653 			writecb = log_content_pcap_spec_writecb;
1654 			prepcb = log_content_pcap_prepcb;
1655 		} else {
1656 			reopencb = log_content_pcap_reopencb;
1657 			opencb = NULL;
1658 			closecb = log_content_pcap_closecb;
1659 			writecb = log_content_pcap_writecb;
1660 			prepcb = log_content_pcap_prepcb;
1661 		}
1662 		if (!(content_pcap_log = logger_new(reopencb, opencb, closecb,
1663 		                                    writecb, prepcb,
1664 		                                    log_exceptcb))) {
1665 			log_content_pcap_fini();
1666 			goto out;
1667 		}
1668 	}
1669 #ifndef WITHOUT_MIRROR
1670 	if (global->mirrorif) {
1671 		if (log_content_mirror_preinit(global->mirrorif,
1672 		                               global->mirrortarget) == -1)
1673 			goto out;
1674 		reopencb = NULL;
1675 		opencb = NULL;
1676 		closecb = log_content_mirror_closecb;
1677 		writecb = log_content_mirror_writecb;
1678 		prepcb = log_content_mirror_prepcb;
1679 		if (!(content_mirror_log = logger_new(reopencb, opencb, closecb,
1680 		                                      writecb, prepcb,
1681 		                                      log_exceptcb))) {
1682 			log_content_mirror_fini();
1683 			goto out;
1684 		}
1685 	}
1686 #endif /* !WITHOUT_MIRROR */
1687 	if (global->connectlog) {
1688 		if (log_connect_preinit(global->connectlog) == -1)
1689 			goto out;
1690 		if (!(connect_log = logger_new(log_connect_reopencb,
1691 		                               NULL, NULL,
1692 		                               log_connect_writecb, NULL,
1693 		                               log_exceptcb))) {
1694 			log_connect_fini();
1695 			goto out;
1696 		}
1697 	}
1698 	if (global->masterkeylog) {
1699 		if (log_masterkey_preinit(global->masterkeylog) == -1)
1700 			goto out;
1701 		if (!(masterkey_log = logger_new(log_masterkey_reopencb,
1702 		                                 NULL, NULL,
1703 		                                 log_masterkey_writecb, NULL,
1704 		                                 log_exceptcb))) {
1705 			log_masterkey_fini();
1706 			goto out;
1707 		}
1708 	}
1709 	if (global->certgendir) {
1710 		if (!(cert_log = logger_new(NULL, NULL, NULL, log_cert_writecb,
1711 		                            NULL, log_exceptcb)))
1712 			goto out;
1713 	}
1714 	if (!(err_log = logger_new(NULL, NULL, NULL, log_err_writecb, NULL,
1715 	                           log_exceptcb)))
1716 		goto out;
1717 	return 0;
1718 
1719 out:
1720 	if (connect_log) {
1721 		log_connect_fini();
1722 		logger_free(connect_log);
1723 	}
1724 	if (content_file_log) {
1725 		log_content_file_single_fini();
1726 		logger_free(content_file_log);
1727 	}
1728 	if (content_pcap_log) {
1729 		log_content_pcap_fini();
1730 		logger_free(content_pcap_log);
1731 	}
1732 #ifndef WITHOUT_MIRROR
1733 	if (content_mirror_log) {
1734 		log_content_mirror_fini();
1735 		logger_free(content_mirror_log);
1736 	}
1737 #endif /* !WITHOUT_MIRROR */
1738 	if (cert_log) {
1739 		logger_free(cert_log);
1740 	}
1741 	if (masterkey_log) {
1742 		log_masterkey_fini();
1743 		logger_free(masterkey_log);
1744 	}
1745 	return -1;
1746 }
1747 
1748 /*
1749  * Close all file descriptors opened by log_preinit; used in privsep parent.
1750  * Only undo content, connect and masterkey logs, leave error and debug log
1751  * functional.
1752  */
1753 void
log_preinit_undo(void)1754 log_preinit_undo(void)
1755 {
1756 	if (connect_log) {
1757 		log_connect_fini();
1758 		logger_free(connect_log);
1759 	}
1760 	if (content_file_log) {
1761 		log_content_file_single_fini();
1762 		logger_free(content_file_log);
1763 	}
1764 	if (content_pcap_log) {
1765 		log_content_pcap_fini();
1766 		logger_free(content_pcap_log);
1767 	}
1768 #ifndef WITHOUT_MIRROR
1769 	if (content_mirror_log) {
1770 		log_content_mirror_fini();
1771 		logger_free(content_mirror_log);
1772 	}
1773 #endif /* !WITHOUT_MIRROR */
1774 	if (masterkey_log) {
1775 		log_masterkey_fini();
1776 		logger_free(masterkey_log);
1777 	}
1778 }
1779 
1780 /*
1781  * Log post-init: start logging threads.
1782  * Return -1 on errors, 0 otherwise.
1783  */
1784 int
log_init(global_t * global,proxy_ctx_t * ctx,int clisock[5])1785 log_init(global_t *global, proxy_ctx_t *ctx, int clisock[5])
1786 {
1787 	proxy_ctx = ctx;
1788 	if (err_log)
1789 		if (logger_start(err_log) == -1)
1790 			return -1;
1791 	if (!global->debug) {
1792 		err_shortcut_logger = 1;
1793 	}
1794 
1795 	if (masterkey_log) {
1796 		masterkey_clisock = clisock[0];
1797 		if (logger_start(masterkey_log) == -1)
1798 			return -1;
1799 	} else {
1800 		privsep_client_close(clisock[0]);
1801 	}
1802 
1803 	if (connect_log) {
1804 		connect_clisock = clisock[1];
1805 		if (logger_start(connect_log) == -1)
1806 			return -1;
1807 	} else {
1808 		privsep_client_close(clisock[1]);
1809 	}
1810 
1811 	if (content_file_log) {
1812 		content_file_clisock = clisock[2];
1813 		if (logger_start(content_file_log) == -1)
1814 			return -1;
1815 	} else {
1816 		privsep_client_close(clisock[2]);
1817 	}
1818 
1819 	if (content_pcap_log) {
1820 		content_pcap_clisock = clisock[3];
1821 		if (logger_start(content_pcap_log) == -1)
1822 			return -1;
1823 	} else {
1824 		privsep_client_close(clisock[3]);
1825 	}
1826 
1827 #ifndef WITHOUT_MIRROR
1828 	if (content_mirror_log) {
1829 		if (logger_start(content_mirror_log) == -1)
1830 			return -1;
1831 	}
1832 #endif /* !WITHOUT_MIRROR */
1833 
1834 	if (cert_log) {
1835 		cert_clisock = clisock[4];
1836 		if (logger_start(cert_log) == -1)
1837 			return -1;
1838 	} else {
1839 		privsep_client_close(clisock[4]);
1840 	}
1841 	return 0;
1842 }
1843 
1844 /*
1845  * Drain and cleanup.  Tell all loggers to leave, then join all logger threads,
1846  * and finally free resources and close log files.
1847  */
1848 void
log_fini(void)1849 log_fini(void)
1850 {
1851 	/* switch back to direct logging so we can still log errors while
1852 	 * tearing down the logging infrastructure */
1853 	err_shortcut_logger = 1;
1854 
1855 	if (cert_log)
1856 		logger_leave(cert_log);
1857 	if (masterkey_log)
1858 		logger_leave(masterkey_log);
1859 #ifndef WITHOUT_MIRROR
1860 	if (content_mirror_log)
1861 		logger_leave(content_mirror_log);
1862 #endif /* !WITHOUT_MIRROR */
1863 	if (content_pcap_log)
1864 		logger_leave(content_pcap_log);
1865 	if (content_file_log)
1866 		logger_leave(content_file_log);
1867 	if (connect_log)
1868 		logger_leave(connect_log);
1869 	if (err_log)
1870 		logger_leave(err_log);
1871 
1872 	if (cert_log)
1873 		logger_join(cert_log);
1874 	if (masterkey_log)
1875 		logger_join(masterkey_log);
1876 #ifndef WITHOUT_MIRROR
1877 	if (content_mirror_log)
1878 		logger_join(content_mirror_log);
1879 #endif /* !WITHOUT_MIRROR */
1880 	if (content_pcap_log)
1881 		logger_join(content_pcap_log);
1882 	if (content_file_log)
1883 		logger_join(content_file_log);
1884 	if (connect_log)
1885 		logger_join(connect_log);
1886 	if (err_log)
1887 		logger_join(err_log);
1888 
1889 	if (cert_log)
1890 		logger_free(cert_log);
1891 	if (masterkey_log)
1892 		logger_free(masterkey_log);
1893 #ifndef WITHOUT_MIRROR
1894 	if (content_mirror_log)
1895 		logger_free(content_mirror_log);
1896 #endif /* !WITHOUT_MIRROR */
1897 	if (content_pcap_log)
1898 		logger_free(content_pcap_log);
1899 	if (content_file_log)
1900 		logger_free(content_file_log);
1901 	if (connect_log)
1902 		logger_free(connect_log);
1903 	if (err_log)
1904 		logger_free(err_log);
1905 
1906 	if (masterkey_log)
1907 		log_masterkey_fini();
1908 #ifndef WITHOUT_MIRROR
1909 	if (content_mirror_log)
1910 		log_content_mirror_fini();
1911 #endif /* !WITHOUT_MIRROR */
1912 	if (content_pcap_log)
1913 		log_content_pcap_fini();
1914 	if (content_file_log)
1915 		log_content_file_single_fini();
1916 	if (connect_log)
1917 		log_connect_fini();
1918 
1919 	if (masterkey_clisock != -1)
1920 		privsep_client_close(masterkey_clisock);
1921 	if (cert_clisock != -1)
1922 		privsep_client_close(cert_clisock);
1923 	if (content_file_clisock != -1)
1924 		privsep_client_close(content_file_clisock);
1925 	if (content_pcap_clisock != -1)
1926 		privsep_client_close(content_pcap_clisock);
1927 	if (connect_clisock != -1)
1928 		privsep_client_close(connect_clisock);
1929 }
1930 
1931 int
log_reopen(void)1932 log_reopen(void)
1933 {
1934 	int rv = 0;
1935 
1936 	if (masterkey_log)
1937 		if (logger_reopen(masterkey_log) == -1)
1938 			rv = -1;
1939 	if (content_pcap_log)
1940 		if (logger_reopen(content_pcap_log) == -1)
1941 			rv = -1;
1942 	if (content_file_log)
1943 		if (logger_reopen(content_file_log) == -1)
1944 			rv = -1;
1945 	if (connect_log)
1946 		if (logger_reopen(connect_log) == -1)
1947 			rv = -1;
1948 
1949 	return rv;
1950 }
1951 
1952 /* vim: set noet ft=c: */
1953