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