xref: /openbsd-src/usr.bin/ssh/log.c (revision 33b4f39fbeffad07bc3206f173cff9f3c9901cd1)
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.29 2003/09/23 20:17:11 markus 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 /*
182  * Initialize the log.
183  */
184 
185 void
186 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
187 {
188 	argv0 = av0;
189 
190 	switch (level) {
191 	case SYSLOG_LEVEL_QUIET:
192 	case SYSLOG_LEVEL_FATAL:
193 	case SYSLOG_LEVEL_ERROR:
194 	case SYSLOG_LEVEL_INFO:
195 	case SYSLOG_LEVEL_VERBOSE:
196 	case SYSLOG_LEVEL_DEBUG1:
197 	case SYSLOG_LEVEL_DEBUG2:
198 	case SYSLOG_LEVEL_DEBUG3:
199 		log_level = level;
200 		break;
201 	default:
202 		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
203 		    (int) level);
204 		exit(1);
205 	}
206 
207 	log_on_stderr = on_stderr;
208 	if (on_stderr)
209 		return;
210 
211 	switch (facility) {
212 	case SYSLOG_FACILITY_DAEMON:
213 		log_facility = LOG_DAEMON;
214 		break;
215 	case SYSLOG_FACILITY_USER:
216 		log_facility = LOG_USER;
217 		break;
218 	case SYSLOG_FACILITY_AUTH:
219 		log_facility = LOG_AUTH;
220 		break;
221 	case SYSLOG_FACILITY_LOCAL0:
222 		log_facility = LOG_LOCAL0;
223 		break;
224 	case SYSLOG_FACILITY_LOCAL1:
225 		log_facility = LOG_LOCAL1;
226 		break;
227 	case SYSLOG_FACILITY_LOCAL2:
228 		log_facility = LOG_LOCAL2;
229 		break;
230 	case SYSLOG_FACILITY_LOCAL3:
231 		log_facility = LOG_LOCAL3;
232 		break;
233 	case SYSLOG_FACILITY_LOCAL4:
234 		log_facility = LOG_LOCAL4;
235 		break;
236 	case SYSLOG_FACILITY_LOCAL5:
237 		log_facility = LOG_LOCAL5;
238 		break;
239 	case SYSLOG_FACILITY_LOCAL6:
240 		log_facility = LOG_LOCAL6;
241 		break;
242 	case SYSLOG_FACILITY_LOCAL7:
243 		log_facility = LOG_LOCAL7;
244 		break;
245 	default:
246 		fprintf(stderr,
247 		    "Unrecognized internal syslog facility code %d\n",
248 		    (int) facility);
249 		exit(1);
250 	}
251 }
252 
253 #define MSGBUFSIZ 1024
254 
255 void
256 do_log(LogLevel level, const char *fmt, va_list args)
257 {
258 	struct syslog_data sdata = SYSLOG_DATA_INIT;
259 	char msgbuf[MSGBUFSIZ];
260 	char fmtbuf[MSGBUFSIZ];
261 	char *txt = NULL;
262 	int pri = LOG_INFO;
263 
264 	if (level > log_level)
265 		return;
266 
267 	switch (level) {
268 	case SYSLOG_LEVEL_FATAL:
269 		if (!log_on_stderr)
270 			txt = "fatal";
271 		pri = LOG_CRIT;
272 		break;
273 	case SYSLOG_LEVEL_ERROR:
274 		if (!log_on_stderr)
275 			txt = "error";
276 		pri = LOG_ERR;
277 		break;
278 	case SYSLOG_LEVEL_INFO:
279 		pri = LOG_INFO;
280 		break;
281 	case SYSLOG_LEVEL_VERBOSE:
282 		pri = LOG_INFO;
283 		break;
284 	case SYSLOG_LEVEL_DEBUG1:
285 		txt = "debug1";
286 		pri = LOG_DEBUG;
287 		break;
288 	case SYSLOG_LEVEL_DEBUG2:
289 		txt = "debug2";
290 		pri = LOG_DEBUG;
291 		break;
292 	case SYSLOG_LEVEL_DEBUG3:
293 		txt = "debug3";
294 		pri = LOG_DEBUG;
295 		break;
296 	default:
297 		txt = "internal error";
298 		pri = LOG_ERR;
299 		break;
300 	}
301 	if (txt != NULL) {
302 		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
303 		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
304 	} else {
305 		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
306 	}
307 	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL);
308 	if (log_on_stderr) {
309 		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
310 		write(STDERR_FILENO, msgbuf, strlen(msgbuf));
311 	} else {
312 		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
313 		syslog_r(pri, &sdata, "%.500s", fmtbuf);
314 		closelog_r(&sdata);
315 	}
316 }
317