log.c 10.4 KB
Newer Older
1
/* $OpenBSD: log.c,v 1.45 2013/05/16 09:08:41 dtucker Exp $ */
2 3 4 5 6 7 8 9 10 11 12
/*
 * Author: Tatu Ylonen <ylo@cs.hut.fi>
 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 *                    All rights reserved
 *
 * As far as I am concerned, the code I have written for this software
 * can be used freely for any purpose.  Any derived versions of this
 * software must be clearly marked as such, and if the derived work is
 * incompatible with the protocol description in the RFC file, it must be
 * called by a name other than "ssh" or "Secure Shell".
 */
13
/*
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
 */
36 37 38

#include "includes.h"

39 40
#include <sys/types.h>

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 51
# include <vis.h>
#endif
52

53
#include "xmalloc.h"
54
#include "log.h"
55

56 57
static LogLevel log_level = SYSLOG_LEVEL_INFO;
static int log_on_stderr = 1;
58
static int log_stderr_fd = STDERR_FILENO;
59 60
static int log_facility = LOG_AUTH;
static char *argv0;
61 62
static log_handler_fn *log_handler;
static void *log_handler_ctx;
63 64 65

extern char *__progname;

66 67 68
#define LOG_SYSLOG_VIS	(VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
#define LOG_STDERR_VIS	(VIS_SAFE|VIS_OCTAL)

69 70 71 72 73 74 75 76 77
/* textual representation of log-facilities/levels */

static struct {
	const char *name;
	SyslogFacility val;
} log_facilities[] = {
	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
	{ "USER",	SYSLOG_FACILITY_USER },
	{ "AUTH",	SYSLOG_FACILITY_AUTH },
78 79 80
#ifdef LOG_AUTHPRIV
	{ "AUTHPRIV",	SYSLOG_FACILITY_AUTHPRIV },
#endif
81 82 83 84 85 86 87 88
	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
89
	{ NULL,		SYSLOG_FACILITY_NOT_SET }
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
};

static struct {
	const char *name;
	LogLevel val;
} log_levels[] =
{
	{ "QUIET",	SYSLOG_LEVEL_QUIET },
	{ "FATAL",	SYSLOG_LEVEL_FATAL },
	{ "ERROR",	SYSLOG_LEVEL_ERROR },
	{ "INFO",	SYSLOG_LEVEL_INFO },
	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
106
	{ NULL,		SYSLOG_LEVEL_NOT_SET }
107 108 109 110 111 112
};

SyslogFacility
log_facility_number(char *name)
{
	int i;
113

114 115 116 117
	if (name != NULL)
		for (i = 0; log_facilities[i].name; i++)
			if (strcasecmp(log_facilities[i].name, name) == 0)
				return log_facilities[i].val;
118
	return SYSLOG_FACILITY_NOT_SET;
119 120
}

121 122 123 124 125 126 127 128 129 130 131
const char *
log_facility_name(SyslogFacility facility)
{
	u_int i;

	for (i = 0;  log_facilities[i].name; i++)
		if (log_facilities[i].val == facility)
			return log_facilities[i].name;
	return NULL;
}

132 133 134 135
LogLevel
log_level_number(char *name)
{
	int i;
136

137 138 139 140
	if (name != NULL)
		for (i = 0; log_levels[i].name; i++)
			if (strcasecmp(log_levels[i].name, name) == 0)
				return log_levels[i].val;
141
	return SYSLOG_LEVEL_NOT_SET;
142
}
143

144 145 146 147 148 149 150 151 152 153 154
const char *
log_level_name(LogLevel level)
{
	u_int i;

	for (i = 0; log_levels[i].name != NULL; i++)
		if (log_levels[i].val == level)
			return log_levels[i].name;
	return NULL;
}

155 156 157
/* Error messages that should be logged. */

void
158
error(const char *fmt,...)
159
{
160
	va_list args;
161

162 163 164
	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_ERROR, fmt, args);
	va_end(args);
165 166
}

167 168 169
void
sigdie(const char *fmt,...)
{
170
#ifdef DO_LOG_SAFE_IN_SIGHAND
171 172 173 174 175
	va_list args;

	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
	va_end(args);
176
#endif
177 178 179 180
	_exit(1);
}


181 182 183
/* Log this message (information that usually should go to the log). */

void
184
logit(const char *fmt,...)
185
{
186
	va_list args;
187

188
	va_start(args, fmt);
189
	do_log(SYSLOG_LEVEL_INFO, fmt, args);
190
	va_end(args);
191 192 193 194 195
}

/* More detailed messages (information that does not need to go to the log). */

void
196
verbose(const char *fmt,...)
197
{
198
	va_list args;
199

200 201 202
	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
	va_end(args);
203 204 205 206 207
}

/* Debugging messages that should not be logged during normal operation. */

void
208
debug(const char *fmt,...)
209
{
210
	va_list args;
211

212
	va_start(args, fmt);
213 214 215 216 217 218 219 220
	do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
	va_end(args);
}

void
debug2(const char *fmt,...)
{
	va_list args;
221

222 223 224 225 226 227 228 229 230
	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
	va_end(args);
}

void
debug3(const char *fmt,...)
{
	va_list args;
231

232 233
	va_start(args, fmt);
	do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
234
	va_end(args);
235 236
}

237 238 239
/*
 * Initialize the log.
 */
Damien Miller's avatar
Damien Miller committed
240

241 242
void
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
Damien Miller's avatar
Damien Miller committed
243
{
244 245 246
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
Damien Miller's avatar
Damien Miller committed
247

248 249
	argv0 = av0;

250 251 252 253 254 255 256 257 258 259 260 261
	switch (level) {
	case SYSLOG_LEVEL_QUIET:
	case SYSLOG_LEVEL_FATAL:
	case SYSLOG_LEVEL_ERROR:
	case SYSLOG_LEVEL_INFO:
	case SYSLOG_LEVEL_VERBOSE:
	case SYSLOG_LEVEL_DEBUG1:
	case SYSLOG_LEVEL_DEBUG2:
	case SYSLOG_LEVEL_DEBUG3:
		log_level = level;
		break;
	default:
262
		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
263 264 265 266
		    (int) level);
		exit(1);
	}

267 268 269
	log_handler = NULL;
	log_handler_ctx = NULL;

270 271 272 273 274 275 276 277 278 279 280 281 282 283
	log_on_stderr = on_stderr;
	if (on_stderr)
		return;

	switch (facility) {
	case SYSLOG_FACILITY_DAEMON:
		log_facility = LOG_DAEMON;
		break;
	case SYSLOG_FACILITY_USER:
		log_facility = LOG_USER;
		break;
	case SYSLOG_FACILITY_AUTH:
		log_facility = LOG_AUTH;
		break;
284 285 286 287
#ifdef LOG_AUTHPRIV
	case SYSLOG_FACILITY_AUTHPRIV:
		log_facility = LOG_AUTHPRIV;
		break;
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
#endif
	case SYSLOG_FACILITY_LOCAL0:
		log_facility = LOG_LOCAL0;
		break;
	case SYSLOG_FACILITY_LOCAL1:
		log_facility = LOG_LOCAL1;
		break;
	case SYSLOG_FACILITY_LOCAL2:
		log_facility = LOG_LOCAL2;
		break;
	case SYSLOG_FACILITY_LOCAL3:
		log_facility = LOG_LOCAL3;
		break;
	case SYSLOG_FACILITY_LOCAL4:
		log_facility = LOG_LOCAL4;
		break;
	case SYSLOG_FACILITY_LOCAL5:
		log_facility = LOG_LOCAL5;
		break;
	case SYSLOG_FACILITY_LOCAL6:
		log_facility = LOG_LOCAL6;
		break;
	case SYSLOG_FACILITY_LOCAL7:
		log_facility = LOG_LOCAL7;
		break;
	default:
		fprintf(stderr,
315
		    "Unrecognized internal syslog facility code %d\n",
316 317 318
		    (int) facility);
		exit(1);
	}
319 320 321 322 323 324 325 326 327 328 329 330 331

	/*
	 * If an external library (eg libwrap) attempts to use syslog
	 * immediately after reexec, syslog may be pointing to the wrong
	 * facility, so we force an open/close of syslog here.
	 */
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
	closelog_r(&sdata);
#else
	openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
	closelog();
#endif
Damien Miller's avatar
Damien Miller committed
332 333
}

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
void
log_change_level(LogLevel new_log_level)
{
	/* no-op if log_init has not been called */
	if (argv0 == NULL)
		return;
	log_init(argv0, new_log_level, log_facility, log_on_stderr);
}

int
log_is_on_stderr(void)
{
	return log_on_stderr;
}

349 350 351 352 353 354 355 356 357 358 359 360 361 362
/* redirect what would usually get written to stderr to specified file */
void
log_redirect_stderr_to(const char *logfile)
{
	int fd;

	if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
		fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile,
		     strerror(errno));
		exit(1);
	}
	log_stderr_fd = fd;
}

363 364
#define MSGBUFSIZ 1024

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
void
set_log_handler(log_handler_fn *handler, void *ctx)
{
	log_handler = handler;
	log_handler_ctx = ctx;
}

void
do_log2(LogLevel level, const char *fmt,...)
{
	va_list args;

	va_start(args, fmt);
	do_log(level, fmt, args);
	va_end(args);
}

382
void
383
do_log(LogLevel level, const char *fmt, va_list args)
Damien Miller's avatar
Damien Miller committed
384
{
385
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
386 387
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
388 389 390 391
	char msgbuf[MSGBUFSIZ];
	char fmtbuf[MSGBUFSIZ];
	char *txt = NULL;
	int pri = LOG_INFO;
392
	int saved_errno = errno;
393
	log_handler_fn *tmp_handler;
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431

	if (level > log_level)
		return;

	switch (level) {
	case SYSLOG_LEVEL_FATAL:
		if (!log_on_stderr)
			txt = "fatal";
		pri = LOG_CRIT;
		break;
	case SYSLOG_LEVEL_ERROR:
		if (!log_on_stderr)
			txt = "error";
		pri = LOG_ERR;
		break;
	case SYSLOG_LEVEL_INFO:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_VERBOSE:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_DEBUG1:
		txt = "debug1";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG2:
		txt = "debug2";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG3:
		txt = "debug3";
		pri = LOG_DEBUG;
		break;
	default:
		txt = "internal error";
		pri = LOG_ERR;
		break;
	}
432
	if (txt != NULL && log_handler == NULL) {
433 434 435 436 437
		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
	} else {
		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	}
438 439
	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
440 441 442 443 444 445 446
	if (log_handler != NULL) {
		/* Avoid recursion */
		tmp_handler = log_handler;
		log_handler = NULL;
		tmp_handler(level, fmtbuf, log_handler_ctx);
		log_handler = tmp_handler;
	} else if (log_on_stderr) {
Damien Miller's avatar
Damien Miller committed
447
		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
448
		(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);
Damien Miller's avatar
Damien Miller committed
452
		syslog_r(pri, &sdata, "%.500s", fmtbuf);
453 454
		closelog_r(&sdata);
#else
455
		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
456
		syslog(pri, "%.500s", fmtbuf);
457
		closelog();
458
#endif
459
	}
460
	errno = saved_errno;
Damien Miller's avatar
Damien Miller committed
461
}