xref: /freebsd/contrib/openbsm/bin/auditdistd/pjdlog.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/pjdlog.c#1 $
31  */
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 
38 #include <assert.h>
39 #include <errno.h>
40 #ifdef __FreeBSD__
41 #include <libutil.h>
42 #include <printf.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <syslog.h>
50 #include <unistd.h>
51 
52 #include "pjdlog.h"
53 
54 #define	PJDLOG_NEVER_INITIALIZED	0
55 #define	PJDLOG_NOT_INITIALIZED		1
56 #define	PJDLOG_INITIALIZED		2
57 
58 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
59 static int pjdlog_mode, pjdlog_debug_level;
60 static char pjdlog_prefix[128];
61 
62 #ifdef __FreeBSD__
63 static int
64 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
65     size_t n, int *argt)
66 {
67 
68 	assert(n >= 1);
69 	argt[0] = PA_INT | PA_FLAG_INTMAX;
70 	return (1);
71 }
72 
73 static int
74 pjdlog_printf_render_humanized_number(struct __printf_io *io,
75     const struct printf_info *pi, const void * const *arg)
76 {
77 	char buf[5];
78 	intmax_t num;
79 	int ret;
80 
81 	num = *(const intmax_t *)arg[0];
82 	humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
83 	    HN_NOSPACE | HN_DECIMAL);
84 	ret = __printf_out(io, pi, buf, strlen(buf));
85 	__printf_flush(io);
86 	return (ret);
87 }
88 
89 static int
90 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
91     size_t n, int *argt)
92 {
93 
94 	assert(n >= 1);
95 	argt[0] = PA_POINTER;
96 	return (1);
97 }
98 
99 static int
100 pjdlog_printf_render_sockaddr(struct __printf_io *io,
101     const struct printf_info *pi, const void * const *arg)
102 {
103 	const struct sockaddr_storage *ss;
104 	char buf[64];
105 	int ret;
106 
107 	ss = *(const struct sockaddr_storage * const *)arg[0];
108 	switch (ss->ss_family) {
109 	case AF_INET:
110 	    {
111 		char addr[INET_ADDRSTRLEN];
112 		const struct sockaddr_in *sin;
113 		unsigned int port;
114 
115 		sin = (const struct sockaddr_in *)ss;
116 		port = ntohs(sin->sin_port);
117 		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
118 		    sizeof(addr)) == NULL) {
119 			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
120 			    strerror(errno));
121 		}
122 		snprintf(buf, sizeof(buf), "%s:%u", addr, port);
123 		break;
124 	    }
125 	case AF_INET6:
126 	    {
127 		char addr[INET6_ADDRSTRLEN];
128 		const struct sockaddr_in6 *sin;
129 		unsigned int port;
130 
131 		sin = (const struct sockaddr_in6 *)ss;
132 		port = ntohs(sin->sin6_port);
133 		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
134 		    sizeof(addr)) == NULL) {
135 			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
136 			    strerror(errno));
137 		}
138 		snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
139 		break;
140 	    }
141 	default:
142 		snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
143 		    ss->ss_family);
144 		break;
145 	}
146 	ret = __printf_out(io, pi, buf, strlen(buf));
147 	__printf_flush(io);
148 	return (ret);
149 }
150 #endif	/* __FreeBSD__ */
151 
152 void
153 pjdlog_init(int mode)
154 {
155 	int saved_errno;
156 
157 	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
158 	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
159 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
160 
161 	saved_errno = errno;
162 
163 	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
164 #ifdef __FreeBSD__
165 		__use_xprintf = 1;
166 		register_printf_render_std("T");
167 		register_printf_render('N',
168 		    pjdlog_printf_render_humanized_number,
169 		    pjdlog_printf_arginfo_humanized_number);
170 		register_printf_render('S',
171 		    pjdlog_printf_render_sockaddr,
172 		    pjdlog_printf_arginfo_sockaddr);
173 #endif
174 	}
175 
176 	if (mode == PJDLOG_MODE_SYSLOG)
177 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
178 	pjdlog_mode = mode;
179 	pjdlog_debug_level = 0;
180 	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
181 
182 	pjdlog_initialized = PJDLOG_INITIALIZED;
183 
184 	errno = saved_errno;
185 }
186 
187 void
188 pjdlog_fini(void)
189 {
190 	int saved_errno;
191 
192 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
193 
194 	saved_errno = errno;
195 
196 	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
197 		closelog();
198 
199 	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
200 
201 	errno = saved_errno;
202 }
203 
204 /*
205  * Configure where the logs should go.
206  * By default they are send to stdout/stderr, but after going into background
207  * (eg. by calling daemon(3)) application is responsible for changing mode to
208  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
209  */
210 void
211 pjdlog_mode_set(int mode)
212 {
213 	int saved_errno;
214 
215 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
216 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
217 
218 	if (pjdlog_mode == mode)
219 		return;
220 
221 	saved_errno = errno;
222 
223 	if (mode == PJDLOG_MODE_SYSLOG)
224 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
225 	else /* if (mode == PJDLOG_MODE_STD) */
226 		closelog();
227 
228 	pjdlog_mode = mode;
229 
230 	errno = saved_errno;
231 }
232 
233 /*
234  * Return current mode.
235  */
236 int
237 pjdlog_mode_get(void)
238 {
239 
240 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
241 
242 	return (pjdlog_mode);
243 }
244 
245 /*
246  * Set debug level. All the logs above the level specified here will be
247  * ignored.
248  */
249 void
250 pjdlog_debug_set(int level)
251 {
252 
253 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
254 	assert(level >= 0);
255 
256 	pjdlog_debug_level = level;
257 }
258 
259 /*
260  * Return current debug level.
261  */
262 int
263 pjdlog_debug_get(void)
264 {
265 
266 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
267 
268 	return (pjdlog_debug_level);
269 }
270 
271 /*
272  * Set prefix that will be used before each log.
273  * Setting prefix to NULL will remove it.
274  */
275 void
276 pjdlog_prefix_set(const char *fmt, ...)
277 {
278 	va_list ap;
279 
280 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
281 
282 	va_start(ap, fmt);
283 	pjdlogv_prefix_set(fmt, ap);
284 	va_end(ap);
285 }
286 
287 /*
288  * Set prefix that will be used before each log.
289  * Setting prefix to NULL will remove it.
290  */
291 void
292 pjdlogv_prefix_set(const char *fmt, va_list ap)
293 {
294 	int saved_errno;
295 
296 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
297 	assert(fmt != NULL);
298 
299 	saved_errno = errno;
300 
301 	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
302 
303 	errno = saved_errno;
304 }
305 
306 /*
307  * Convert log level into string.
308  */
309 static const char *
310 pjdlog_level_string(int loglevel)
311 {
312 
313 	switch (loglevel) {
314 	case LOG_EMERG:
315 		return ("EMERG");
316 	case LOG_ALERT:
317 		return ("ALERT");
318 	case LOG_CRIT:
319 		return ("CRIT");
320 	case LOG_ERR:
321 		return ("ERROR");
322 	case LOG_WARNING:
323 		return ("WARNING");
324 	case LOG_NOTICE:
325 		return ("NOTICE");
326 	case LOG_INFO:
327 		return ("INFO");
328 	case LOG_DEBUG:
329 		return ("DEBUG");
330 	}
331 	assert(!"Invalid log level.");
332 	abort();	/* XXX: gcc */
333 }
334 
335 /*
336  * Common log routine.
337  */
338 void
339 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
340 {
341 	va_list ap;
342 
343 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
344 
345 	va_start(ap, fmt);
346 	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
347 	va_end(ap);
348 }
349 
350 /*
351  * Common log routine, which can handle regular log level as well as debug
352  * level. We decide here where to send the logs (stdout/stderr or syslog).
353  */
354 void
355 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
356     va_list ap)
357 {
358 	int saved_errno;
359 
360 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
361 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
362 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
363 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
364 	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
365 	assert(loglevel != LOG_DEBUG || debuglevel > 0);
366 	assert(error >= -1);
367 
368 	/* Ignore debug above configured level. */
369 	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
370 		return;
371 
372 	saved_errno = errno;
373 
374 	switch (pjdlog_mode) {
375 	case PJDLOG_MODE_STD:
376 	    {
377 		FILE *out;
378 
379 		/*
380 		 * We send errors and warning to stderr and the rest to stdout.
381 		 */
382 		switch (loglevel) {
383 		case LOG_EMERG:
384 		case LOG_ALERT:
385 		case LOG_CRIT:
386 		case LOG_ERR:
387 		case LOG_WARNING:
388 			out = stderr;
389 			break;
390 		case LOG_NOTICE:
391 		case LOG_INFO:
392 		case LOG_DEBUG:
393 			out = stdout;
394 			break;
395 		default:
396 			assert(!"Invalid loglevel.");
397 			abort();	/* XXX: gcc */
398 		}
399 
400 		fprintf(out, "(%d) ", getpid());
401 		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
402 		/* Attach debuglevel if this is debug log. */
403 		if (loglevel == LOG_DEBUG)
404 			fprintf(out, "[%d]", debuglevel);
405 		fprintf(out, " %s", pjdlog_prefix);
406 		vfprintf(out, fmt, ap);
407 		if (error != -1)
408 			fprintf(out, ": %s.", strerror(error));
409 		fprintf(out, "\n");
410 		fflush(out);
411 		break;
412 	    }
413 	case PJDLOG_MODE_SYSLOG:
414 	    {
415 		char log[1024];
416 		int len;
417 
418 		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
419 		if ((size_t)len < sizeof(log))
420 			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
421 		if (error != -1 && (size_t)len < sizeof(log)) {
422 			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
423 			    strerror(error));
424 		}
425 		syslog(loglevel, "%s", log);
426 		break;
427 	    }
428 	default:
429 		assert(!"Invalid mode.");
430 	}
431 
432 	errno = saved_errno;
433 }
434 
435 /*
436  * Regular logs.
437  */
438 void
439 pjdlogv(int loglevel, const char *fmt, va_list ap)
440 {
441 
442 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
443 
444 	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
445 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
446 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
447 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
448 	    loglevel == LOG_INFO);
449 
450 	pjdlogv_common(loglevel, 0, -1, fmt, ap);
451 }
452 
453 /*
454  * Regular logs.
455  */
456 void
457 pjdlog(int loglevel, const char *fmt, ...)
458 {
459 	va_list ap;
460 
461 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
462 
463 	va_start(ap, fmt);
464 	pjdlogv(loglevel, fmt, ap);
465 	va_end(ap);
466 }
467 
468 /*
469  * Debug logs.
470  */
471 void
472 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
473 {
474 
475 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
476 
477 	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
478 }
479 
480 /*
481  * Debug logs.
482  */
483 void
484 pjdlog_debug(int debuglevel, const char *fmt, ...)
485 {
486 	va_list ap;
487 
488 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
489 
490 	va_start(ap, fmt);
491 	pjdlogv_debug(debuglevel, fmt, ap);
492 	va_end(ap);
493 }
494 
495 /*
496  * Error logs with errno logging.
497  */
498 void
499 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
500 {
501 
502 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
503 
504 	pjdlogv_common(loglevel, 0, errno, fmt, ap);
505 }
506 
507 /*
508  * Error logs with errno logging.
509  */
510 void
511 pjdlog_errno(int loglevel, const char *fmt, ...)
512 {
513 	va_list ap;
514 
515 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
516 
517 	va_start(ap, fmt);
518 	pjdlogv_errno(loglevel, fmt, ap);
519 	va_end(ap);
520 }
521 
522 /*
523  * Log error, errno and exit.
524  */
525 void
526 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
527 {
528 
529 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
530 
531 	pjdlogv_errno(LOG_ERR, fmt, ap);
532 	exit(exitcode);
533 	/* NOTREACHED */
534 }
535 
536 /*
537  * Log error, errno and exit.
538  */
539 void
540 pjdlog_exit(int exitcode, const char *fmt, ...)
541 {
542 	va_list ap;
543 
544 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
545 
546 	va_start(ap, fmt);
547 	pjdlogv_exit(exitcode, fmt, ap);
548 	/* NOTREACHED */
549 	va_end(ap);
550 }
551 
552 /*
553  * Log error and exit.
554  */
555 void
556 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
557 {
558 
559 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
560 
561 	pjdlogv(LOG_ERR, fmt, ap);
562 	exit(exitcode);
563 	/* NOTREACHED */
564 }
565 
566 /*
567  * Log error and exit.
568  */
569 void
570 pjdlog_exitx(int exitcode, const char *fmt, ...)
571 {
572 	va_list ap;
573 
574 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
575 
576 	va_start(ap, fmt);
577 	pjdlogv_exitx(exitcode, fmt, ap);
578 	/* NOTREACHED */
579 	va_end(ap);
580 }
581 
582 /*
583  * Log failure message and exit.
584  */
585 void
586 pjdlog_abort(const char *func, const char *file, int line,
587     const char *failedexpr, const char *fmt, ...)
588 {
589 	va_list ap;
590 
591 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
592 
593 	/*
594 	 * When there is no message we pass __func__ as 'fmt'.
595 	 * It would be cleaner to pass NULL or "", but gcc generates a warning
596 	 * for both of those.
597 	 */
598 	if (fmt != func) {
599 		va_start(ap, fmt);
600 		pjdlogv_critical(fmt, ap);
601 		va_end(ap);
602 	}
603 	if (failedexpr == NULL) {
604 		if (func == NULL) {
605 			pjdlog_critical("Aborted at file %s, line %d.", file,
606 			    line);
607 		} else {
608 			pjdlog_critical("Aborted at function %s, file %s, line %d.",
609 			    func, file, line);
610 		}
611 	} else {
612 		if (func == NULL) {
613 			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
614 			    failedexpr, file, line);
615 		} else {
616 			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
617 			    failedexpr, func, file, line);
618 		}
619 	}
620 	abort();
621 }
622