log.c revision 1.28
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"
37RCSID("$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
45static LogLevel log_level = SYSLOG_LEVEL_INFO;
46static int log_on_stderr = 1;
47static int log_facility = LOG_AUTH;
48static char *argv0;
49
50extern char *__progname;
51
52/* textual representation of log-facilities/levels */
53
54static 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
72static 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
89SyslogFacility
90log_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
101LogLevel
102log_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
115void
116error(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
127void
128logit(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
139void
140verbose(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
151void
152debug(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
161void
162debug2(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
171void
172debug3(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
183struct fatal_cleanup {
184	struct fatal_cleanup *next;
185	void (*proc) (void *);
186	void *context;
187};
188
189static struct fatal_cleanup *fatal_cleanups = NULL;
190
191/* Registers a cleanup function to be called by fatal() before exiting. */
192
193void
194fatal_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
207void
208fatal_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() */
225void
226fatal_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 */
238void
239fatal_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
262void
263log_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
332void
333do_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