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
msg_syslog_print(int level,const char * text)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
msg_syslog_init(const char * name,int logopt,int facility)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
msg_syslog_set_facility(const char * facility_name)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
msg_syslog_disable(void)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
main(int argc,char ** argv)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