Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: msg_syslog.c,v 1.2 2020/03/18 19:05:21 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	msg_syslog 3
      6 /* SUMMARY
      7 /*	direct diagnostics to syslog daemon
      8 /* SYNOPSIS
      9 /*	#include <msg_syslog.h>
     10 /*
     11 /*	void	msg_syslog_init(progname, log_opt, facility)
     12 /*	const char *progname;
     13 /*	int	log_opt;
     14 /*	int	facility;
     15 /*
     16 /*	int     msg_syslog_set_facility(facility_name)
     17 /*	const char *facility_name;
     18 /*
     19 /*	void	msg_syslog_disable(void)
     20 /* DESCRIPTION
     21 /*	This module implements support to report msg(3) diagnostics
     22 /*	via the syslog daemon.
     23 /*
     24 /*	msg_syslog_init() is a wrapper around the openlog(3) routine
     25 /*	that directs subsequent msg(3) output to the syslog daemon.
     26 /*	This function may also be called to update msg_syslog
     27 /*	settings. If the program name appears to contain a process ID
     28 /*	then msg_syslog_init will attempt to suppress its own PID.
     29 /*
     30 /*	msg_syslog_set_facility() is a helper routine that overrides the
     31 /*	logging facility that is specified with msg_syslog_init().
     32 /*	The result is zero in case of an unknown facility name.
     33 /*
     34 /*	msg_syslog_disable() turns off the msg_syslog client,
     35 /*	until a subsequent msg_syslog_init() call.
     36 /* SEE ALSO
     37 /*	syslog(3) syslog library
     38 /*	msg(3)	diagnostics module
     39 /* BUGS
     40 /*	Output records are truncated to 2000 characters. This is done in
     41 /*	order to defend against a buffer overflow problem in some
     42 /*	implementations of the syslog() library routine.
     43 /* LICENSE
     44 /* .ad
     45 /* .fi
     46 /*	The Secure Mailer license must be distributed with this software.
     47 /* AUTHOR(S)
     48 /*	Wietse Venema
     49 /*	IBM T.J. Watson Research
     50 /*	P.O. Box 704
     51 /*	Yorktown Heights, NY 10598, USA
     52 /*
     53 /*	Wietse Venema
     54 /*	Google, Inc.
     55 /*	111 8th Avenue
     56 /*	New York, NY 10011, USA
     57 /*--*/
     58 
     59 /* System libraries. */
     60 
     61 #include <sys_defs.h>
     62 #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
     63 #include <stdarg.h>
     64 #include <errno.h>
     65 #include <syslog.h>
     66 #include <string.h>
     67 #include <time.h>
     68 
     69 /* Application-specific. */
     70 
     71 #include "vstring.h"
     72 #include "stringops.h"
     73 #include "msg.h"
     74 #include "msg_output.h"
     75 #include "msg_syslog.h"
     76 #include "safe.h"
     77 #include <mymalloc.h>
     78 
     79  /*
     80   * Stay a little below the 2048-byte limit of older syslog()
     81   * implementations.
     82   */
     83 #define MSG_SYSLOG_RECLEN	2000
     84 
     85 struct facility_list {
     86     const char *name;
     87     int     facility;
     88 };
     89 
     90 static struct facility_list facility_list[] = {
     91 #ifdef LOG_AUTH
     92     "auth", LOG_AUTH,
     93 #endif
     94 #ifdef LOG_AUTHPRIV
     95     "authpriv", LOG_AUTHPRIV,
     96 #endif
     97 #ifdef LOG_CRON
     98     "cron", LOG_CRON,
     99 #endif
    100 #ifdef LOG_DAEMON
    101     "daemon", LOG_DAEMON,
    102 #endif
    103 #ifdef LOG_FTP
    104     "ftp", LOG_FTP,
    105 #endif
    106 #ifdef LOG_KERN
    107     "kern", LOG_KERN,
    108 #endif
    109 #ifdef LOG_LPR
    110     "lpr", LOG_LPR,
    111 #endif
    112 #ifdef LOG_MAIL
    113     "mail", LOG_MAIL,
    114 #endif
    115 #ifdef LOG_NEWS
    116     "news", LOG_NEWS,
    117 #endif
    118 #ifdef LOG_SECURITY
    119     "security", LOG_SECURITY,
    120 #endif
    121 #ifdef LOG_SYSLOG
    122     "syslog", LOG_SYSLOG,
    123 #endif
    124 #ifdef LOG_USER
    125     "user", LOG_USER,
    126 #endif
    127 #ifdef LOG_UUCP
    128     "uucp", LOG_UUCP,
    129 #endif
    130 #ifdef LOG_LOCAL0
    131     "local0", LOG_LOCAL0,
    132 #endif
    133 #ifdef LOG_LOCAL1
    134     "local1", LOG_LOCAL1,
    135 #endif
    136 #ifdef LOG_LOCAL2
    137     "local2", LOG_LOCAL2,
    138 #endif
    139 #ifdef LOG_LOCAL3
    140     "local3", LOG_LOCAL3,
    141 #endif
    142 #ifdef LOG_LOCAL4
    143     "local4", LOG_LOCAL4,
    144 #endif
    145 #ifdef LOG_LOCAL5
    146     "local5", LOG_LOCAL5,
    147 #endif
    148 #ifdef LOG_LOCAL6
    149     "local6", LOG_LOCAL6,
    150 #endif
    151 #ifdef LOG_LOCAL7
    152     "local7", LOG_LOCAL7,
    153 #endif
    154     0,
    155 };
    156 
    157 static int msg_syslog_facility;
    158 static int msg_syslog_enable;
    159 
    160 /* msg_syslog_print - log info to syslog daemon */
    161 
    162 static void msg_syslog_print(int level, const char *text)
    163 {
    164     static int log_level[] = {
    165 	LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_CRIT,
    166     };
    167     static char *severity_name[] = {
    168 	"info", "warning", "error", "fatal", "panic",
    169     };
    170 
    171     if (msg_syslog_enable == 0)
    172 	return;
    173 
    174     if (level < 0 || level >= (int) (sizeof(log_level) / sizeof(log_level[0])))
    175 	msg_panic("msg_syslog_print: invalid severity level: %d", level);
    176 
    177     if (level == MSG_INFO) {
    178 	syslog(msg_syslog_facility | log_level[level], "%.*s",
    179 	       (int) MSG_SYSLOG_RECLEN, text);
    180     } else {
    181 	syslog(msg_syslog_facility | log_level[level], "%s: %.*s",
    182 	       severity_name[level], (int) MSG_SYSLOG_RECLEN, text);
    183     }
    184 }
    185 
    186 /* msg_syslog_init - initialize */
    187 
    188 void    msg_syslog_init(const char *name, int logopt, int facility)
    189 {
    190     static int first_call = 1;
    191     extern char **environ;
    192 
    193     /*
    194      * XXX If this program is set-gid, then TZ must not be trusted. This
    195      * scrubbing code is in the wrong place.
    196      */
    197     if (first_call) {
    198 	if (unsafe())
    199 	    while (getenv("TZ"))		/* There may be multiple. */
    200 		if (unsetenv("TZ") < 0) {	/* Desperate measures. */
    201 		    environ[0] = 0;
    202 		    msg_fatal("unsetenv: %m");
    203 		}
    204 	tzset();
    205     }
    206     /* Hack for internal logging forwarding after config change. */
    207     if (strchr(name, '[') != 0)
    208 	logopt &= ~LOG_PID;
    209     openlog(name, LOG_NDELAY | logopt, facility);
    210     if (first_call) {
    211 	first_call = 0;
    212 	msg_output(msg_syslog_print);
    213     }
    214     msg_syslog_enable = 1;
    215 }
    216 
    217 /* msg_syslog_set_facility - set logging facility by name */
    218 
    219 int     msg_syslog_set_facility(const char *facility_name)
    220 {
    221     struct facility_list *fnp;
    222 
    223     for (fnp = facility_list; fnp->name; ++fnp) {
    224 	if (!strcmp(fnp->name, facility_name)) {
    225 	    msg_syslog_facility = fnp->facility;
    226 	    return (1);
    227 	}
    228     }
    229     return 0;
    230 }
    231 
    232 /* msg_syslog_disable - disable the msg_syslog client */
    233 
    234 void    msg_syslog_disable(void)
    235 {
    236     msg_syslog_enable = 0;
    237 }
    238 
    239 #ifdef TEST
    240 
    241  /*
    242   * Proof-of-concept program to test the syslogging diagnostics interface
    243   *
    244   * Usage: msg_syslog_test text...
    245   */
    246 
    247 int     main(int argc, char **argv)
    248 {
    249     VSTRING *vp = vstring_alloc(256);
    250 
    251     msg_syslog_init(argv[0], LOG_PID, LOG_MAIL);
    252     if (argc < 2)
    253 	msg_error("usage: %s text to be logged", argv[0]);
    254     while (--argc && *++argv) {
    255 	vstring_strcat(vp, *argv);
    256 	if (argv[1])
    257 	    vstring_strcat(vp, " ");
    258     }
    259     msg_warn("static text");
    260     msg_warn("dynamic text: >%s<", vstring_str(vp));
    261     msg_warn("dynamic numeric: >%d<", 42);
    262     msg_warn("error text: >%m<");
    263     msg_warn("dynamic: >%s<: error: >%m<", vstring_str(vp));
    264     vstring_free(vp);
    265     return (0);
    266 }
    267 
    268 #endif
    269