xref: /openbsd-src/usr.bin/ssh/log.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  *
6  * As far as I am concerned, the code I have written for this software
7  * can be used freely for any purpose.  Any derived versions of this
8  * software must be clearly marked as such, and if the derived work is
9  * incompatible with the protocol description in the RFC file, it must be
10  * called by a name other than "ssh" or "Secure Shell".
11  */
12 /*
13  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "includes.h"
37 RCSID("$OpenBSD: log.c,v 1.28 2003/05/24 09:02:22 djm Exp $");
38 
39 #include "log.h"
40 #include "xmalloc.h"
41 
42 #include <syslog.h>
43 #include <vis.h>
44 
45 static LogLevel log_level = SYSLOG_LEVEL_INFO;
46 static int log_on_stderr = 1;
47 static int log_facility = LOG_AUTH;
48 static char *argv0;
49 
50 extern char *__progname;
51 
52 /* textual representation of log-facilities/levels */
53 
54 static struct {
55 	const char *name;
56 	SyslogFacility val;
57 } log_facilities[] = {
58 	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
59 	{ "USER",	SYSLOG_FACILITY_USER },
60 	{ "AUTH",	SYSLOG_FACILITY_AUTH },
61 	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
62 	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
63 	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
64 	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
65 	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
66 	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
67 	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
68 	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
69 	{ NULL,		SYSLOG_FACILITY_NOT_SET }
70 };
71 
72 static struct {
73 	const char *name;
74 	LogLevel val;
75 } log_levels[] =
76 {
77 	{ "QUIET",	SYSLOG_LEVEL_QUIET },
78 	{ "FATAL",	SYSLOG_LEVEL_FATAL },
79 	{ "ERROR",	SYSLOG_LEVEL_ERROR },
80 	{ "INFO",	SYSLOG_LEVEL_INFO },
81 	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
82 	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
83 	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
84 	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
85 	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
86 	{ NULL,		SYSLOG_LEVEL_NOT_SET }
87 };
88 
89 SyslogFacility
90 log_facility_number(char *name)
91 {
92 	int i;
93 
94 	if (name != NULL)
95 		for (i = 0; log_facilities[i].name; i++)
96 			if (strcasecmp(log_facilities[i].name, name) == 0)
97 				return log_facilities[i].val;
98 	return SYSLOG_FACILITY_NOT_SET;
99 }
100 
101 LogLevel
102 log_level_number(char *name)
103 {
104 	int i;
105 
106 	if (name != NULL)
107 		for (i = 0; log_levels[i].name; i++)
108 			if (strcasecmp(log_levels[i].name, name) == 0)
109 				return log_levels[i].val;
110 	return SYSLOG_LEVEL_NOT_SET;
111 }
112 
113 /* Error messages that should be logged. */
114 
115 void
116 error(const char *fmt,...)
117 {
118 	va_list args;
119 
120 	va_start(args, fmt);
121 	do_log(SYSLOG_LEVEL_ERROR, fmt, args);
122 	va_end(args);
123 }
124 
125 /* Log this message (information that usually should go to the log). */
126 
127 void
128 logit(const char *fmt,...)
129 {
130 	va_list args;
131 
132 	va_start(args, fmt);
133 	do_log(SYSLOG_LEVEL_INFO, fmt, args);
134 	va_end(args);
135 }
136 
137 /* More detailed messages (information that does not need to go to the log). */
138 
139 void
140 verbose(const char *fmt,...)
141 {
142 	va_list args;
143 
144 	va_start(args, fmt);
145 	do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
146 	va_end(args);
147 }
148 
149 /* Debugging messages that should not be logged during normal operation. */
150 
151 void
152 debug(const char *fmt,...)
153 {
154 	va_list args;
155 
156 	va_start(args, fmt);
157 	do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
158 	va_end(args);
159 }
160 
161 void
162 debug2(const char *fmt,...)
163 {
164 	va_list args;
165 
166 	va_start(args, fmt);
167 	do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
168 	va_end(args);
169 }
170 
171 void
172 debug3(const char *fmt,...)
173 {
174 	va_list args;
175 
176 	va_start(args, fmt);
177 	do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
178 	va_end(args);
179 }
180 
181 /* Fatal cleanup */
182 
183 struct fatal_cleanup {
184 	struct fatal_cleanup *next;
185 	void (*proc) (void *);
186 	void *context;
187 };
188 
189 static struct fatal_cleanup *fatal_cleanups = NULL;
190 
191 /* Registers a cleanup function to be called by fatal() before exiting. */
192 
193 void
194 fatal_add_cleanup(void (*proc) (void *), void *context)
195 {
196 	struct fatal_cleanup *cu;
197 
198 	cu = xmalloc(sizeof(*cu));
199 	cu->proc = proc;
200 	cu->context = context;
201 	cu->next = fatal_cleanups;
202 	fatal_cleanups = cu;
203 }
204 
205 /* Removes a cleanup frunction to be called at fatal(). */
206 
207 void
208 fatal_remove_cleanup(void (*proc) (void *context), void *context)
209 {
210 	struct fatal_cleanup **cup, *cu;
211 
212 	for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
213 		cu = *cup;
214 		if (cu->proc == proc && cu->context == context) {
215 			*cup = cu->next;
216 			xfree(cu);
217 			return;
218 		}
219 	}
220 	fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
221 	    (u_long) proc, (u_long) context);
222 }
223 
224 /* Remove all cleanups, to be called after fork() */
225 void
226 fatal_remove_all_cleanups(void)
227 {
228 	struct fatal_cleanup *cu, *next_cu;
229 
230 	for (cu = fatal_cleanups; cu; cu = next_cu) {
231 		next_cu = cu->next;
232 		xfree(cu);
233 	}
234 	fatal_cleanups = NULL;
235 }
236 
237 /* Cleanup and exit */
238 void
239 fatal_cleanup(void)
240 {
241 	struct fatal_cleanup *cu, *next_cu;
242 	static int called = 0;
243 
244 	if (called)
245 		exit(255);
246 	called = 1;
247 	/* Call cleanup functions. */
248 	for (cu = fatal_cleanups; cu; cu = next_cu) {
249 		next_cu = cu->next;
250 		debug("Calling cleanup 0x%lx(0x%lx)",
251 		    (u_long) cu->proc, (u_long) cu->context);
252 		(*cu->proc) (cu->context);
253 	}
254 	exit(255);
255 }
256 
257 
258 /*
259  * Initialize the log.
260  */
261 
262 void
263 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
264 {
265 	argv0 = av0;
266 
267 	switch (level) {
268 	case SYSLOG_LEVEL_QUIET:
269 	case SYSLOG_LEVEL_FATAL:
270 	case SYSLOG_LEVEL_ERROR:
271 	case SYSLOG_LEVEL_INFO:
272 	case SYSLOG_LEVEL_VERBOSE:
273 	case SYSLOG_LEVEL_DEBUG1:
274 	case SYSLOG_LEVEL_DEBUG2:
275 	case SYSLOG_LEVEL_DEBUG3:
276 		log_level = level;
277 		break;
278 	default:
279 		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
280 		    (int) level);
281 		exit(1);
282 	}
283 
284 	log_on_stderr = on_stderr;
285 	if (on_stderr)
286 		return;
287 
288 	switch (facility) {
289 	case SYSLOG_FACILITY_DAEMON:
290 		log_facility = LOG_DAEMON;
291 		break;
292 	case SYSLOG_FACILITY_USER:
293 		log_facility = LOG_USER;
294 		break;
295 	case SYSLOG_FACILITY_AUTH:
296 		log_facility = LOG_AUTH;
297 		break;
298 	case SYSLOG_FACILITY_LOCAL0:
299 		log_facility = LOG_LOCAL0;
300 		break;
301 	case SYSLOG_FACILITY_LOCAL1:
302 		log_facility = LOG_LOCAL1;
303 		break;
304 	case SYSLOG_FACILITY_LOCAL2:
305 		log_facility = LOG_LOCAL2;
306 		break;
307 	case SYSLOG_FACILITY_LOCAL3:
308 		log_facility = LOG_LOCAL3;
309 		break;
310 	case SYSLOG_FACILITY_LOCAL4:
311 		log_facility = LOG_LOCAL4;
312 		break;
313 	case SYSLOG_FACILITY_LOCAL5:
314 		log_facility = LOG_LOCAL5;
315 		break;
316 	case SYSLOG_FACILITY_LOCAL6:
317 		log_facility = LOG_LOCAL6;
318 		break;
319 	case SYSLOG_FACILITY_LOCAL7:
320 		log_facility = LOG_LOCAL7;
321 		break;
322 	default:
323 		fprintf(stderr,
324 		    "Unrecognized internal syslog facility code %d\n",
325 		    (int) facility);
326 		exit(1);
327 	}
328 }
329 
330 #define MSGBUFSIZ 1024
331 
332 void
333 do_log(LogLevel level, const char *fmt, va_list args)
334 {
335 	struct syslog_data sdata = SYSLOG_DATA_INIT;
336 	char msgbuf[MSGBUFSIZ];
337 	char fmtbuf[MSGBUFSIZ];
338 	char *txt = NULL;
339 	int pri = LOG_INFO;
340 
341 	if (level > log_level)
342 		return;
343 
344 	switch (level) {
345 	case SYSLOG_LEVEL_FATAL:
346 		if (!log_on_stderr)
347 			txt = "fatal";
348 		pri = LOG_CRIT;
349 		break;
350 	case SYSLOG_LEVEL_ERROR:
351 		if (!log_on_stderr)
352 			txt = "error";
353 		pri = LOG_ERR;
354 		break;
355 	case SYSLOG_LEVEL_INFO:
356 		pri = LOG_INFO;
357 		break;
358 	case SYSLOG_LEVEL_VERBOSE:
359 		pri = LOG_INFO;
360 		break;
361 	case SYSLOG_LEVEL_DEBUG1:
362 		txt = "debug1";
363 		pri = LOG_DEBUG;
364 		break;
365 	case SYSLOG_LEVEL_DEBUG2:
366 		txt = "debug2";
367 		pri = LOG_DEBUG;
368 		break;
369 	case SYSLOG_LEVEL_DEBUG3:
370 		txt = "debug3";
371 		pri = LOG_DEBUG;
372 		break;
373 	default:
374 		txt = "internal error";
375 		pri = LOG_ERR;
376 		break;
377 	}
378 	if (txt != NULL) {
379 		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
380 		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
381 	} else {
382 		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
383 	}
384 	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL);
385 	if (log_on_stderr) {
386 		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
387 		write(STDERR_FILENO, msgbuf, strlen(msgbuf));
388 	} else {
389 		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
390 		syslog_r(pri, &sdata, "%.500s", fmtbuf);
391 		closelog_r(&sdata);
392 	}
393 }
394