Branch data Line data Source code
1 : : /* $OpenBSD: log.c,v 1.45 2013/05/16 09:08:41 dtucker Exp $ */
2 : : /*
3 : : * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 : : * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 : : * All rights reserved
6 : : *
7 : : * As far as I am concerned, the code I have written for this software
8 : : * can be used freely for any purpose. Any derived versions of this
9 : : * software must be clearly marked as such, and if the derived work is
10 : : * incompatible with the protocol description in the RFC file, it must be
11 : : * called by a name other than "ssh" or "Secure Shell".
12 : : */
13 : : /*
14 : : * Copyright (c) 2000 Markus Friedl. All rights reserved.
15 : : *
16 : : * Redistribution and use in source and binary forms, with or without
17 : : * modification, are permitted provided that the following conditions
18 : : * are met:
19 : : * 1. Redistributions of source code must retain the above copyright
20 : : * notice, this list of conditions and the following disclaimer.
21 : : * 2. Redistributions in binary form must reproduce the above copyright
22 : : * notice, this list of conditions and the following disclaimer in the
23 : : * documentation and/or other materials provided with the distribution.
24 : : *
25 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 : : */
36 : :
37 : : #include "includes.h"
38 : :
39 : : #include <sys/types.h>
40 : :
41 : : #include <fcntl.h>
42 : : #include <stdarg.h>
43 : : #include <stdio.h>
44 : : #include <stdlib.h>
45 : : #include <string.h>
46 : : #include <syslog.h>
47 : : #include <unistd.h>
48 : : #include <errno.h>
49 : : #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
50 : : # include <vis.h>
51 : : #endif
52 : :
53 : : #include "xmalloc.h"
54 : : #include "log.h"
55 : :
56 : : static LogLevel log_level = SYSLOG_LEVEL_INFO;
57 : : static int log_on_stderr = 1;
58 : : static int log_stderr_fd = STDERR_FILENO;
59 : : static int log_facility = LOG_AUTH;
60 : : static char *argv0;
61 : : static log_handler_fn *log_handler;
62 : : static void *log_handler_ctx;
63 : :
64 : : extern char *__progname;
65 : :
66 : : #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
67 : : #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL)
68 : :
69 : : /* textual representation of log-facilities/levels */
70 : :
71 : : static struct {
72 : : const char *name;
73 : : SyslogFacility val;
74 : : } log_facilities[] = {
75 : : { "DAEMON", SYSLOG_FACILITY_DAEMON },
76 : : { "USER", SYSLOG_FACILITY_USER },
77 : : { "AUTH", SYSLOG_FACILITY_AUTH },
78 : : #ifdef LOG_AUTHPRIV
79 : : { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV },
80 : : #endif
81 : : { "LOCAL0", SYSLOG_FACILITY_LOCAL0 },
82 : : { "LOCAL1", SYSLOG_FACILITY_LOCAL1 },
83 : : { "LOCAL2", SYSLOG_FACILITY_LOCAL2 },
84 : : { "LOCAL3", SYSLOG_FACILITY_LOCAL3 },
85 : : { "LOCAL4", SYSLOG_FACILITY_LOCAL4 },
86 : : { "LOCAL5", SYSLOG_FACILITY_LOCAL5 },
87 : : { "LOCAL6", SYSLOG_FACILITY_LOCAL6 },
88 : : { "LOCAL7", SYSLOG_FACILITY_LOCAL7 },
89 : : { NULL, SYSLOG_FACILITY_NOT_SET }
90 : : };
91 : :
92 : : static struct {
93 : : const char *name;
94 : : LogLevel val;
95 : : } log_levels[] =
96 : : {
97 : : { "QUIET", SYSLOG_LEVEL_QUIET },
98 : : { "FATAL", SYSLOG_LEVEL_FATAL },
99 : : { "ERROR", SYSLOG_LEVEL_ERROR },
100 : : { "INFO", SYSLOG_LEVEL_INFO },
101 : : { "VERBOSE", SYSLOG_LEVEL_VERBOSE },
102 : : { "DEBUG", SYSLOG_LEVEL_DEBUG1 },
103 : : { "DEBUG1", SYSLOG_LEVEL_DEBUG1 },
104 : : { "DEBUG2", SYSLOG_LEVEL_DEBUG2 },
105 : : { "DEBUG3", SYSLOG_LEVEL_DEBUG3 },
106 : : { NULL, SYSLOG_LEVEL_NOT_SET }
107 : : };
108 : :
109 : : SyslogFacility
110 : 0 : log_facility_number(char *name)
111 : : {
112 : : int i;
113 : :
114 [ # # ]: 0 : if (name != NULL)
115 [ # # ]: 0 : for (i = 0; log_facilities[i].name; i++)
116 [ # # ]: 0 : if (strcasecmp(log_facilities[i].name, name) == 0)
117 : 0 : return log_facilities[i].val;
118 : : return SYSLOG_FACILITY_NOT_SET;
119 : : }
120 : :
121 : : const char *
122 : 142 : log_facility_name(SyslogFacility facility)
123 : : {
124 : : u_int i;
125 : :
126 [ + - ]: 426 : for (i = 0; log_facilities[i].name; i++)
127 [ + + ]: 426 : if (log_facilities[i].val == facility)
128 : : return log_facilities[i].name;
129 : : return NULL;
130 : : }
131 : :
132 : : LogLevel
133 : 4051 : log_level_number(char *name)
134 : : {
135 : : int i;
136 : :
137 [ + - ]: 4051 : if (name != NULL)
138 [ + - ]: 36459 : for (i = 0; log_levels[i].name; i++)
139 [ + + ]: 36459 : if (strcasecmp(log_levels[i].name, name) == 0)
140 : 4051 : return log_levels[i].val;
141 : : return SYSLOG_LEVEL_NOT_SET;
142 : : }
143 : :
144 : : const char *
145 : 62949 : log_level_name(LogLevel level)
146 : : {
147 : : u_int i;
148 : :
149 [ + - ]: 503948 : for (i = 0; log_levels[i].name != NULL; i++)
150 [ + + ]: 503948 : if (log_levels[i].val == level)
151 : : return log_levels[i].name;
152 : : return NULL;
153 : : }
154 : :
155 : : /* Error messages that should be logged. */
156 : :
157 : : void
158 : 103 : error(const char *fmt,...)
159 : : {
160 : : va_list args;
161 : :
162 : 103 : va_start(args, fmt);
163 : 103 : do_log(SYSLOG_LEVEL_ERROR, fmt, args);
164 : 103 : va_end(args);
165 : 103 : }
166 : :
167 : : void
168 : 0 : sigdie(const char *fmt,...)
169 : : {
170 : : #ifdef DO_LOG_SAFE_IN_SIGHAND
171 : : va_list args;
172 : :
173 : : va_start(args, fmt);
174 : : do_log(SYSLOG_LEVEL_FATAL, fmt, args);
175 : : va_end(args);
176 : : #endif
177 : 0 : _exit(1);
178 : : }
179 : :
180 : :
181 : : /* Log this message (information that usually should go to the log). */
182 : :
183 : : void
184 : 1005 : logit(const char *fmt,...)
185 : : {
186 : : va_list args;
187 : :
188 : 1005 : va_start(args, fmt);
189 : 1005 : do_log(SYSLOG_LEVEL_INFO, fmt, args);
190 : 1005 : va_end(args);
191 : 1005 : }
192 : :
193 : : /* More detailed messages (information that does not need to go to the log). */
194 : :
195 : : void
196 : 6037 : verbose(const char *fmt,...)
197 : : {
198 : : va_list args;
199 : :
200 : 6037 : va_start(args, fmt);
201 : 6037 : do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
202 : 6037 : va_end(args);
203 : 6037 : }
204 : :
205 : : /* Debugging messages that should not be logged during normal operation. */
206 : :
207 : : void
208 : 104748 : debug(const char *fmt,...)
209 : : {
210 : : va_list args;
211 : :
212 : 104748 : va_start(args, fmt);
213 : 104748 : do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
214 : 104748 : va_end(args);
215 : 104748 : }
216 : :
217 : : void
218 : 108773 : debug2(const char *fmt,...)
219 : : {
220 : : va_list args;
221 : :
222 : 108773 : va_start(args, fmt);
223 : 108773 : do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
224 : 108773 : va_end(args);
225 : 108773 : }
226 : :
227 : : void
228 : 4400642 : debug3(const char *fmt,...)
229 : : {
230 : : va_list args;
231 : :
232 : 4400642 : va_start(args, fmt);
233 : 4400642 : do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
234 : 4400642 : va_end(args);
235 : 4400642 : }
236 : :
237 : : /*
238 : : * Initialize the log.
239 : : */
240 : :
241 : : void
242 : 8678 : log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
243 : : {
244 : : #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
245 : : struct syslog_data sdata = SYSLOG_DATA_INIT;
246 : : #endif
247 : :
248 : 8678 : argv0 = av0;
249 : :
250 [ + - ]: 8678 : switch (level) {
251 : : case SYSLOG_LEVEL_QUIET:
252 : : case SYSLOG_LEVEL_FATAL:
253 : : case SYSLOG_LEVEL_ERROR:
254 : : case SYSLOG_LEVEL_INFO:
255 : : case SYSLOG_LEVEL_VERBOSE:
256 : : case SYSLOG_LEVEL_DEBUG1:
257 : : case SYSLOG_LEVEL_DEBUG2:
258 : : case SYSLOG_LEVEL_DEBUG3:
259 : 8678 : log_level = level;
260 : : break;
261 : : default:
262 : 0 : fprintf(stderr, "Unrecognized internal syslog level code %d\n",
263 : : (int) level);
264 : 0 : exit(1);
265 : : }
266 : :
267 : 8678 : log_handler = NULL;
268 : 8678 : log_handler_ctx = NULL;
269 : :
270 : 8678 : log_on_stderr = on_stderr;
271 [ - + ]: 8678 : if (on_stderr)
272 : 8678 : return;
273 : :
274 [ # # # # : 0 : switch (facility) {
# # # # #
# # # # ]
275 : : case SYSLOG_FACILITY_DAEMON:
276 : 0 : log_facility = LOG_DAEMON;
277 : 0 : break;
278 : : case SYSLOG_FACILITY_USER:
279 : 0 : log_facility = LOG_USER;
280 : 0 : break;
281 : : case SYSLOG_FACILITY_AUTH:
282 : 0 : log_facility = LOG_AUTH;
283 : 0 : break;
284 : : #ifdef LOG_AUTHPRIV
285 : : case SYSLOG_FACILITY_AUTHPRIV:
286 : 0 : log_facility = LOG_AUTHPRIV;
287 : 0 : break;
288 : : #endif
289 : : case SYSLOG_FACILITY_LOCAL0:
290 : 0 : log_facility = LOG_LOCAL0;
291 : 0 : break;
292 : : case SYSLOG_FACILITY_LOCAL1:
293 : 0 : log_facility = LOG_LOCAL1;
294 : 0 : break;
295 : : case SYSLOG_FACILITY_LOCAL2:
296 : 0 : log_facility = LOG_LOCAL2;
297 : 0 : break;
298 : : case SYSLOG_FACILITY_LOCAL3:
299 : 0 : log_facility = LOG_LOCAL3;
300 : 0 : break;
301 : : case SYSLOG_FACILITY_LOCAL4:
302 : 0 : log_facility = LOG_LOCAL4;
303 : 0 : break;
304 : : case SYSLOG_FACILITY_LOCAL5:
305 : 0 : log_facility = LOG_LOCAL5;
306 : 0 : break;
307 : : case SYSLOG_FACILITY_LOCAL6:
308 : 0 : log_facility = LOG_LOCAL6;
309 : 0 : break;
310 : : case SYSLOG_FACILITY_LOCAL7:
311 : 0 : log_facility = LOG_LOCAL7;
312 : 0 : break;
313 : : default:
314 : 0 : fprintf(stderr,
315 : : "Unrecognized internal syslog facility code %d\n",
316 : : (int) facility);
317 : 0 : exit(1);
318 : : }
319 : :
320 : : /*
321 : : * If an external library (eg libwrap) attempts to use syslog
322 : : * immediately after reexec, syslog may be pointing to the wrong
323 : : * facility, so we force an open/close of syslog here.
324 : : */
325 : : #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
326 : : openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
327 : : closelog_r(&sdata);
328 : : #else
329 [ # # ]: 0 : openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
330 : 0 : closelog();
331 : : #endif
332 : : }
333 : :
334 : : void
335 : 0 : log_change_level(LogLevel new_log_level)
336 : : {
337 : : /* no-op if log_init has not been called */
338 [ # # ]: 0 : if (argv0 == NULL)
339 : 0 : return;
340 : 0 : log_init(argv0, new_log_level, log_facility, log_on_stderr);
341 : : }
342 : :
343 : : int
344 : 0 : log_is_on_stderr(void)
345 : : {
346 : 0 : return log_on_stderr;
347 : : }
348 : :
349 : : /* redirect what would usually get written to stderr to specified file */
350 : : void
351 : 2535 : log_redirect_stderr_to(const char *logfile)
352 : : {
353 : : int fd;
354 : :
355 [ - + ]: 2535 : if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
356 : 0 : fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile,
357 : 0 : strerror(errno));
358 : 0 : exit(1);
359 : : }
360 : 2535 : log_stderr_fd = fd;
361 : 2535 : }
362 : :
363 : : #define MSGBUFSIZ 1024
364 : :
365 : : void
366 : 761 : set_log_handler(log_handler_fn *handler, void *ctx)
367 : : {
368 : 761 : log_handler = handler;
369 : 761 : log_handler_ctx = ctx;
370 : 761 : }
371 : :
372 : : void
373 : 62807 : do_log2(LogLevel level, const char *fmt,...)
374 : : {
375 : : va_list args;
376 : :
377 : 62807 : va_start(args, fmt);
378 : 62807 : do_log(level, fmt, args);
379 : 62807 : va_end(args);
380 : 62807 : }
381 : :
382 : : void
383 : 4684118 : do_log(LogLevel level, const char *fmt, va_list args)
384 : : {
385 : : #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
386 : : struct syslog_data sdata = SYSLOG_DATA_INIT;
387 : : #endif
388 : : char msgbuf[MSGBUFSIZ];
389 : : char fmtbuf[MSGBUFSIZ];
390 : 4684118 : char *txt = NULL;
391 : 4684118 : int pri = LOG_INFO;
392 : 4684118 : int saved_errno = errno;
393 : : log_handler_fn *tmp_handler;
394 : :
395 [ + + ]: 4684118 : if (level > log_level)
396 : 4361260 : return;
397 : :
398 [ + + + + : 322858 : switch (level) {
+ - + ]
399 : : case SYSLOG_LEVEL_FATAL:
400 [ - + ]: 3 : if (!log_on_stderr)
401 : 0 : txt = "fatal";
402 : : pri = LOG_CRIT;
403 : : break;
404 : : case SYSLOG_LEVEL_ERROR:
405 [ - + ]: 103 : if (!log_on_stderr)
406 : 0 : txt = "error";
407 : : pri = LOG_ERR;
408 : : break;
409 : : case SYSLOG_LEVEL_INFO:
410 : : pri = LOG_INFO;
411 : : break;
412 : : case SYSLOG_LEVEL_VERBOSE:
413 : : pri = LOG_INFO;
414 : : break;
415 : : case SYSLOG_LEVEL_DEBUG1:
416 : 98732 : txt = "debug1";
417 : 98732 : pri = LOG_DEBUG;
418 : 98732 : break;
419 : : case SYSLOG_LEVEL_DEBUG2:
420 : 104911 : txt = "debug2";
421 : 104911 : pri = LOG_DEBUG;
422 : 104911 : break;
423 : : case SYSLOG_LEVEL_DEBUG3:
424 : 111568 : txt = "debug3";
425 : 111568 : pri = LOG_DEBUG;
426 : 111568 : break;
427 : : default:
428 : 0 : txt = "internal error";
429 : 0 : pri = LOG_ERR;
430 : 0 : break;
431 : : }
432 [ + + ][ + + ]: 322858 : if (txt != NULL && log_handler == NULL) {
433 : : snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
434 : : vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
435 : : } else {
436 : : vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
437 : : }
438 [ - + ]: 322858 : strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
439 : 322858 : log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
440 [ + + ]: 322858 : if (log_handler != NULL) {
441 : : /* Avoid recursion */
442 : 62807 : tmp_handler = log_handler;
443 : 62807 : log_handler = NULL;
444 : 62807 : tmp_handler(level, fmtbuf, log_handler_ctx);
445 : 62807 : log_handler = tmp_handler;
446 [ + - ]: 260051 : } else if (log_on_stderr) {
447 : : snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
448 : 260051 : (void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
449 : : } else {
450 : : #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
451 : : openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
452 : : syslog_r(pri, &sdata, "%.500s", fmtbuf);
453 : : closelog_r(&sdata);
454 : : #else
455 [ # # ]: 0 : openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
456 : : syslog(pri, "%.500s", fmtbuf);
457 : 0 : closelog();
458 : : #endif
459 : : }
460 : 322858 : errno = saved_errno;
461 : : }
|