log.c revision 1.39
1/* $OpenBSD: log.c,v 1.39 2006/08/18 09:13:25 deraadt 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 <sys/types.h>
38
39#include <stdarg.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <syslog.h>
44#include <unistd.h>
45#include <vis.h>
46
47#include "xmalloc.h"
48#include "log.h"
49
50static LogLevel log_level = SYSLOG_LEVEL_INFO;
51static int log_on_stderr = 1;
52static int log_facility = LOG_AUTH;
53static char *argv0;
54
55extern char *__progname;
56
57/* textual representation of log-facilities/levels */
58
59static struct {
60	const char *name;
61	SyslogFacility val;
62} log_facilities[] = {
63	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
64	{ "USER",	SYSLOG_FACILITY_USER },
65	{ "AUTH",	SYSLOG_FACILITY_AUTH },
66	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
67	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
68	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
69	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
70	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
71	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
72	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
73	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
74	{ NULL,		SYSLOG_FACILITY_NOT_SET }
75};
76
77static struct {
78	const char *name;
79	LogLevel val;
80} log_levels[] =
81{
82	{ "QUIET",	SYSLOG_LEVEL_QUIET },
83	{ "FATAL",	SYSLOG_LEVEL_FATAL },
84	{ "ERROR",	SYSLOG_LEVEL_ERROR },
85	{ "INFO",	SYSLOG_LEVEL_INFO },
86	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
87	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
88	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
89	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
90	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
91	{ NULL,		SYSLOG_LEVEL_NOT_SET }
92};
93
94SyslogFacility
95log_facility_number(char *name)
96{
97	int i;
98
99	if (name != NULL)
100		for (i = 0; log_facilities[i].name; i++)
101			if (strcasecmp(log_facilities[i].name, name) == 0)
102				return log_facilities[i].val;
103	return SYSLOG_FACILITY_NOT_SET;
104}
105
106LogLevel
107log_level_number(char *name)
108{
109	int i;
110
111	if (name != NULL)
112		for (i = 0; log_levels[i].name; i++)
113			if (strcasecmp(log_levels[i].name, name) == 0)
114				return log_levels[i].val;
115	return SYSLOG_LEVEL_NOT_SET;
116}
117
118/* Error messages that should be logged. */
119
120void
121error(const char *fmt,...)
122{
123	va_list args;
124
125	va_start(args, fmt);
126	do_log(SYSLOG_LEVEL_ERROR, fmt, args);
127	va_end(args);
128}
129
130void
131sigdie(const char *fmt,...)
132{
133	va_list args;
134
135	va_start(args, fmt);
136	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
137	va_end(args);
138	_exit(1);
139}
140
141
142/* Log this message (information that usually should go to the log). */
143
144void
145logit(const char *fmt,...)
146{
147	va_list args;
148
149	va_start(args, fmt);
150	do_log(SYSLOG_LEVEL_INFO, fmt, args);
151	va_end(args);
152}
153
154/* More detailed messages (information that does not need to go to the log). */
155
156void
157verbose(const char *fmt,...)
158{
159	va_list args;
160
161	va_start(args, fmt);
162	do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
163	va_end(args);
164}
165
166/* Debugging messages that should not be logged during normal operation. */
167
168void
169debug(const char *fmt,...)
170{
171	va_list args;
172
173	va_start(args, fmt);
174	do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
175	va_end(args);
176}
177
178void
179debug2(const char *fmt,...)
180{
181	va_list args;
182
183	va_start(args, fmt);
184	do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
185	va_end(args);
186}
187
188void
189debug3(const char *fmt,...)
190{
191	va_list args;
192
193	va_start(args, fmt);
194	do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
195	va_end(args);
196}
197
198/*
199 * Initialize the log.
200 */
201
202void
203log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
204{
205	argv0 = av0;
206
207	switch (level) {
208	case SYSLOG_LEVEL_QUIET:
209	case SYSLOG_LEVEL_FATAL:
210	case SYSLOG_LEVEL_ERROR:
211	case SYSLOG_LEVEL_INFO:
212	case SYSLOG_LEVEL_VERBOSE:
213	case SYSLOG_LEVEL_DEBUG1:
214	case SYSLOG_LEVEL_DEBUG2:
215	case SYSLOG_LEVEL_DEBUG3:
216		log_level = level;
217		break;
218	default:
219		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
220		    (int) level);
221		exit(1);
222	}
223
224	log_on_stderr = on_stderr;
225	if (on_stderr)
226		return;
227
228	switch (facility) {
229	case SYSLOG_FACILITY_DAEMON:
230		log_facility = LOG_DAEMON;
231		break;
232	case SYSLOG_FACILITY_USER:
233		log_facility = LOG_USER;
234		break;
235	case SYSLOG_FACILITY_AUTH:
236		log_facility = LOG_AUTH;
237		break;
238	case SYSLOG_FACILITY_LOCAL0:
239		log_facility = LOG_LOCAL0;
240		break;
241	case SYSLOG_FACILITY_LOCAL1:
242		log_facility = LOG_LOCAL1;
243		break;
244	case SYSLOG_FACILITY_LOCAL2:
245		log_facility = LOG_LOCAL2;
246		break;
247	case SYSLOG_FACILITY_LOCAL3:
248		log_facility = LOG_LOCAL3;
249		break;
250	case SYSLOG_FACILITY_LOCAL4:
251		log_facility = LOG_LOCAL4;
252		break;
253	case SYSLOG_FACILITY_LOCAL5:
254		log_facility = LOG_LOCAL5;
255		break;
256	case SYSLOG_FACILITY_LOCAL6:
257		log_facility = LOG_LOCAL6;
258		break;
259	case SYSLOG_FACILITY_LOCAL7:
260		log_facility = LOG_LOCAL7;
261		break;
262	default:
263		fprintf(stderr,
264		    "Unrecognized internal syslog facility code %d\n",
265		    (int) facility);
266		exit(1);
267	}
268}
269
270#define MSGBUFSIZ 1024
271
272void
273do_log(LogLevel level, const char *fmt, va_list args)
274{
275	struct syslog_data sdata = SYSLOG_DATA_INIT;
276	char msgbuf[MSGBUFSIZ];
277	char fmtbuf[MSGBUFSIZ];
278	char *txt = NULL;
279	int pri = LOG_INFO;
280
281	if (level > log_level)
282		return;
283
284	switch (level) {
285	case SYSLOG_LEVEL_FATAL:
286		if (!log_on_stderr)
287			txt = "fatal";
288		pri = LOG_CRIT;
289		break;
290	case SYSLOG_LEVEL_ERROR:
291		if (!log_on_stderr)
292			txt = "error";
293		pri = LOG_ERR;
294		break;
295	case SYSLOG_LEVEL_INFO:
296		pri = LOG_INFO;
297		break;
298	case SYSLOG_LEVEL_VERBOSE:
299		pri = LOG_INFO;
300		break;
301	case SYSLOG_LEVEL_DEBUG1:
302		txt = "debug1";
303		pri = LOG_DEBUG;
304		break;
305	case SYSLOG_LEVEL_DEBUG2:
306		txt = "debug2";
307		pri = LOG_DEBUG;
308		break;
309	case SYSLOG_LEVEL_DEBUG3:
310		txt = "debug3";
311		pri = LOG_DEBUG;
312		break;
313	default:
314		txt = "internal error";
315		pri = LOG_ERR;
316		break;
317	}
318	if (txt != NULL) {
319		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
320		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
321	} else {
322		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
323	}
324	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL);
325	if (log_on_stderr) {
326		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
327		write(STDERR_FILENO, msgbuf, strlen(msgbuf));
328	} else {
329		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
330		syslog_r(pri, &sdata, "%.500s", fmtbuf);
331		closelog_r(&sdata);
332	}
333}
334