1323124Sdes/* $OpenBSD: log.c,v 1.48 2016/07/15 05:01:58 dtucker Exp $ */
257429Smarkm/*
365668Skris * Author: Tatu Ylonen <ylo@cs.hut.fi>
465668Skris * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
565668Skris *                    All rights reserved
665668Skris *
765668Skris * As far as I am concerned, the code I have written for this software
865668Skris * can be used freely for any purpose.  Any derived versions of this
965668Skris * software must be clearly marked as such, and if the derived work is
1065668Skris * incompatible with the protocol description in the RFC file, it must be
1165668Skris * called by a name other than "ssh" or "Secure Shell".
1265668Skris */
1365668Skris/*
1465668Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1565668Skris *
1665668Skris * Redistribution and use in source and binary forms, with or without
1765668Skris * modification, are permitted provided that the following conditions
1865668Skris * are met:
1965668Skris * 1. Redistributions of source code must retain the above copyright
2065668Skris *    notice, this list of conditions and the following disclaimer.
2165668Skris * 2. Redistributions in binary form must reproduce the above copyright
2265668Skris *    notice, this list of conditions and the following disclaimer in the
2365668Skris *    documentation and/or other materials provided with the distribution.
2465668Skris *
2565668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2665668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2765668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2865668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2965668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3065668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3165668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3265668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3365668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3465668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3557429Smarkm */
3657429Smarkm
3757429Smarkm#include "includes.h"
3857429Smarkm
39162852Sdes#include <sys/types.h>
4057429Smarkm
41255767Sdes#include <fcntl.h>
42162852Sdes#include <stdarg.h>
43162852Sdes#include <stdio.h>
44162852Sdes#include <stdlib.h>
45162852Sdes#include <string.h>
4676259Sgreen#include <syslog.h>
47162852Sdes#include <unistd.h>
48181111Sdes#include <errno.h>
49248619Sdes#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
50124208Sdes# include <vis.h>
51124208Sdes#endif
5276259Sgreen
53162852Sdes#include "log.h"
54162852Sdes
5576259Sgreenstatic LogLevel log_level = SYSLOG_LEVEL_INFO;
5676259Sgreenstatic int log_on_stderr = 1;
57255767Sdesstatic int log_stderr_fd = STDERR_FILENO;
5876259Sgreenstatic int log_facility = LOG_AUTH;
5976259Sgreenstatic char *argv0;
60226046Sdesstatic log_handler_fn *log_handler;
61226046Sdesstatic void *log_handler_ctx;
6276259Sgreen
6376259Sgreenextern char *__progname;
6476259Sgreen
65137015Sdes#define LOG_SYSLOG_VIS	(VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
66137015Sdes#define LOG_STDERR_VIS	(VIS_SAFE|VIS_OCTAL)
67137015Sdes
6876259Sgreen/* textual representation of log-facilities/levels */
6976259Sgreen
7076259Sgreenstatic struct {
7176259Sgreen	const char *name;
7276259Sgreen	SyslogFacility val;
7376259Sgreen} log_facilities[] = {
7476259Sgreen	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
7576259Sgreen	{ "USER",	SYSLOG_FACILITY_USER },
7676259Sgreen	{ "AUTH",	SYSLOG_FACILITY_AUTH },
7798937Sdes#ifdef LOG_AUTHPRIV
7898937Sdes	{ "AUTHPRIV",	SYSLOG_FACILITY_AUTHPRIV },
7998937Sdes#endif
8076259Sgreen	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
8176259Sgreen	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
8276259Sgreen	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
8376259Sgreen	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
8476259Sgreen	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
8576259Sgreen	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
8676259Sgreen	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
8776259Sgreen	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
8892555Sdes	{ NULL,		SYSLOG_FACILITY_NOT_SET }
8976259Sgreen};
9076259Sgreen
9176259Sgreenstatic struct {
9276259Sgreen	const char *name;
9376259Sgreen	LogLevel val;
9476259Sgreen} log_levels[] =
9576259Sgreen{
9676259Sgreen	{ "QUIET",	SYSLOG_LEVEL_QUIET },
9776259Sgreen	{ "FATAL",	SYSLOG_LEVEL_FATAL },
9876259Sgreen	{ "ERROR",	SYSLOG_LEVEL_ERROR },
9976259Sgreen	{ "INFO",	SYSLOG_LEVEL_INFO },
10076259Sgreen	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
10176259Sgreen	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
10276259Sgreen	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
10376259Sgreen	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
10476259Sgreen	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
10592555Sdes	{ NULL,		SYSLOG_LEVEL_NOT_SET }
10676259Sgreen};
10776259Sgreen
10876259SgreenSyslogFacility
10976259Sgreenlog_facility_number(char *name)
11076259Sgreen{
11176259Sgreen	int i;
112106121Sdes
11376259Sgreen	if (name != NULL)
11476259Sgreen		for (i = 0; log_facilities[i].name; i++)
11576259Sgreen			if (strcasecmp(log_facilities[i].name, name) == 0)
11676259Sgreen				return log_facilities[i].val;
11792555Sdes	return SYSLOG_FACILITY_NOT_SET;
11876259Sgreen}
11976259Sgreen
120181111Sdesconst char *
121181111Sdeslog_facility_name(SyslogFacility facility)
122181111Sdes{
123181111Sdes	u_int i;
124181111Sdes
125181111Sdes	for (i = 0;  log_facilities[i].name; i++)
126181111Sdes		if (log_facilities[i].val == facility)
127181111Sdes			return log_facilities[i].name;
128181111Sdes	return NULL;
129181111Sdes}
130181111Sdes
13176259SgreenLogLevel
13276259Sgreenlog_level_number(char *name)
13376259Sgreen{
13476259Sgreen	int i;
135106121Sdes
13676259Sgreen	if (name != NULL)
13776259Sgreen		for (i = 0; log_levels[i].name; i++)
13876259Sgreen			if (strcasecmp(log_levels[i].name, name) == 0)
13976259Sgreen				return log_levels[i].val;
14092555Sdes	return SYSLOG_LEVEL_NOT_SET;
14176259Sgreen}
14257429Smarkm
143181111Sdesconst char *
144181111Sdeslog_level_name(LogLevel level)
145181111Sdes{
146181111Sdes	u_int i;
147181111Sdes
148181111Sdes	for (i = 0; log_levels[i].name != NULL; i++)
149181111Sdes		if (log_levels[i].val == level)
150181111Sdes			return log_levels[i].name;
151181111Sdes	return NULL;
152181111Sdes}
153181111Sdes
15457429Smarkm/* Error messages that should be logged. */
15557429Smarkm
15657429Smarkmvoid
15757429Smarkmerror(const char *fmt,...)
15857429Smarkm{
15957429Smarkm	va_list args;
160106121Sdes
16157429Smarkm	va_start(args, fmt);
16257429Smarkm	do_log(SYSLOG_LEVEL_ERROR, fmt, args);
16357429Smarkm	va_end(args);
16457429Smarkm}
16557429Smarkm
166162852Sdesvoid
167162852Sdessigdie(const char *fmt,...)
168162852Sdes{
169162852Sdes#ifdef DO_LOG_SAFE_IN_SIGHAND
170162852Sdes	va_list args;
171162852Sdes
172162852Sdes	va_start(args, fmt);
173162852Sdes	do_log(SYSLOG_LEVEL_FATAL, fmt, args);
174162852Sdes	va_end(args);
175162852Sdes#endif
176162852Sdes	_exit(1);
177162852Sdes}
178162852Sdes
179323124Sdesvoid
180323124Sdeslogdie(const char *fmt,...)
181323124Sdes{
182323124Sdes	va_list args;
183162852Sdes
184323124Sdes	va_start(args, fmt);
185323124Sdes	do_log(SYSLOG_LEVEL_INFO, fmt, args);
186323124Sdes	va_end(args);
187323124Sdes	cleanup_exit(255);
188323124Sdes}
189323124Sdes
19057429Smarkm/* Log this message (information that usually should go to the log). */
19157429Smarkm
19257429Smarkmvoid
193124208Sdeslogit(const char *fmt,...)
19457429Smarkm{
19557429Smarkm	va_list args;
196106121Sdes
19757429Smarkm	va_start(args, fmt);
19857429Smarkm	do_log(SYSLOG_LEVEL_INFO, fmt, args);
19957429Smarkm	va_end(args);
20057429Smarkm}
20157429Smarkm
20257429Smarkm/* More detailed messages (information that does not need to go to the log). */
20357429Smarkm
20457429Smarkmvoid
20557429Smarkmverbose(const char *fmt,...)
20657429Smarkm{
20757429Smarkm	va_list args;
208106121Sdes
20957429Smarkm	va_start(args, fmt);
21057429Smarkm	do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
21157429Smarkm	va_end(args);
21257429Smarkm}
21357429Smarkm
21457429Smarkm/* Debugging messages that should not be logged during normal operation. */
21557429Smarkm
21657429Smarkmvoid
21757429Smarkmdebug(const char *fmt,...)
21857429Smarkm{
21957429Smarkm	va_list args;
220106121Sdes
22157429Smarkm	va_start(args, fmt);
22269587Sgreen	do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
22357429Smarkm	va_end(args);
22457429Smarkm}
22557429Smarkm
22669587Sgreenvoid
22769587Sgreendebug2(const char *fmt,...)
22869587Sgreen{
22969587Sgreen	va_list args;
230106121Sdes
23169587Sgreen	va_start(args, fmt);
23269587Sgreen	do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
23369587Sgreen	va_end(args);
23469587Sgreen}
23569587Sgreen
23669587Sgreenvoid
23769587Sgreendebug3(const char *fmt,...)
23869587Sgreen{
23969587Sgreen	va_list args;
240106121Sdes
24169587Sgreen	va_start(args, fmt);
24269587Sgreen	do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
24369587Sgreen	va_end(args);
24469587Sgreen}
24569587Sgreen
24676259Sgreen/*
24776259Sgreen * Initialize the log.
24876259Sgreen */
24957429Smarkm
25076259Sgreenvoid
25176259Sgreenlog_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
25257429Smarkm{
253146998Sdes#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
254146998Sdes	struct syslog_data sdata = SYSLOG_DATA_INIT;
255146998Sdes#endif
256147001Sdes
25776259Sgreen	argv0 = av0;
25857429Smarkm
25976259Sgreen	switch (level) {
26076259Sgreen	case SYSLOG_LEVEL_QUIET:
26176259Sgreen	case SYSLOG_LEVEL_FATAL:
26276259Sgreen	case SYSLOG_LEVEL_ERROR:
26376259Sgreen	case SYSLOG_LEVEL_INFO:
26476259Sgreen	case SYSLOG_LEVEL_VERBOSE:
26576259Sgreen	case SYSLOG_LEVEL_DEBUG1:
26676259Sgreen	case SYSLOG_LEVEL_DEBUG2:
26776259Sgreen	case SYSLOG_LEVEL_DEBUG3:
26876259Sgreen		log_level = level;
26976259Sgreen		break;
27076259Sgreen	default:
27176259Sgreen		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
27276259Sgreen		    (int) level);
27376259Sgreen		exit(1);
27476259Sgreen	}
27576259Sgreen
276226046Sdes	log_handler = NULL;
277226046Sdes	log_handler_ctx = NULL;
278226046Sdes
27976259Sgreen	log_on_stderr = on_stderr;
28076259Sgreen	if (on_stderr)
28176259Sgreen		return;
28276259Sgreen
28376259Sgreen	switch (facility) {
28476259Sgreen	case SYSLOG_FACILITY_DAEMON:
28576259Sgreen		log_facility = LOG_DAEMON;
28676259Sgreen		break;
28776259Sgreen	case SYSLOG_FACILITY_USER:
28876259Sgreen		log_facility = LOG_USER;
28976259Sgreen		break;
29076259Sgreen	case SYSLOG_FACILITY_AUTH:
29176259Sgreen		log_facility = LOG_AUTH;
29276259Sgreen		break;
29398937Sdes#ifdef LOG_AUTHPRIV
29498937Sdes	case SYSLOG_FACILITY_AUTHPRIV:
29598937Sdes		log_facility = LOG_AUTHPRIV;
29698937Sdes		break;
29798937Sdes#endif
29876259Sgreen	case SYSLOG_FACILITY_LOCAL0:
29976259Sgreen		log_facility = LOG_LOCAL0;
30076259Sgreen		break;
30176259Sgreen	case SYSLOG_FACILITY_LOCAL1:
30276259Sgreen		log_facility = LOG_LOCAL1;
30376259Sgreen		break;
30476259Sgreen	case SYSLOG_FACILITY_LOCAL2:
30576259Sgreen		log_facility = LOG_LOCAL2;
30676259Sgreen		break;
30776259Sgreen	case SYSLOG_FACILITY_LOCAL3:
30876259Sgreen		log_facility = LOG_LOCAL3;
30976259Sgreen		break;
31076259Sgreen	case SYSLOG_FACILITY_LOCAL4:
31176259Sgreen		log_facility = LOG_LOCAL4;
31276259Sgreen		break;
31376259Sgreen	case SYSLOG_FACILITY_LOCAL5:
31476259Sgreen		log_facility = LOG_LOCAL5;
31576259Sgreen		break;
31676259Sgreen	case SYSLOG_FACILITY_LOCAL6:
31776259Sgreen		log_facility = LOG_LOCAL6;
31876259Sgreen		break;
31976259Sgreen	case SYSLOG_FACILITY_LOCAL7:
32076259Sgreen		log_facility = LOG_LOCAL7;
32176259Sgreen		break;
32276259Sgreen	default:
32376259Sgreen		fprintf(stderr,
32476259Sgreen		    "Unrecognized internal syslog facility code %d\n",
32576259Sgreen		    (int) facility);
32676259Sgreen		exit(1);
32776259Sgreen	}
328146998Sdes
329146998Sdes	/*
330146998Sdes	 * If an external library (eg libwrap) attempts to use syslog
331146998Sdes	 * immediately after reexec, syslog may be pointing to the wrong
332146998Sdes	 * facility, so we force an open/close of syslog here.
333146998Sdes	 */
334146998Sdes#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
335146998Sdes	openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
336146998Sdes	closelog_r(&sdata);
337146998Sdes#else
338146998Sdes	openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
339146998Sdes	closelog();
340146998Sdes#endif
34157429Smarkm}
34257429Smarkm
343248619Sdesvoid
344248619Sdeslog_change_level(LogLevel new_log_level)
345248619Sdes{
346248619Sdes	/* no-op if log_init has not been called */
347248619Sdes	if (argv0 == NULL)
348248619Sdes		return;
349248619Sdes	log_init(argv0, new_log_level, log_facility, log_on_stderr);
350248619Sdes}
351248619Sdes
352248619Sdesint
353248619Sdeslog_is_on_stderr(void)
354248619Sdes{
355323124Sdes	return log_on_stderr && log_stderr_fd == STDERR_FILENO;
356248619Sdes}
357248619Sdes
358255767Sdes/* redirect what would usually get written to stderr to specified file */
359255767Sdesvoid
360255767Sdeslog_redirect_stderr_to(const char *logfile)
361255767Sdes{
362255767Sdes	int fd;
363255767Sdes
364255767Sdes	if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
365255767Sdes		fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile,
366255767Sdes		     strerror(errno));
367255767Sdes		exit(1);
368255767Sdes	}
369255767Sdes	log_stderr_fd = fd;
370255767Sdes}
371255767Sdes
37276259Sgreen#define MSGBUFSIZ 1024
37376259Sgreen
37476259Sgreenvoid
375226046Sdesset_log_handler(log_handler_fn *handler, void *ctx)
376226046Sdes{
377226046Sdes	log_handler = handler;
378226046Sdes	log_handler_ctx = ctx;
379226046Sdes}
380226046Sdes
381226046Sdesvoid
382226046Sdesdo_log2(LogLevel level, const char *fmt,...)
383226046Sdes{
384226046Sdes	va_list args;
385226046Sdes
386226046Sdes	va_start(args, fmt);
387226046Sdes	do_log(level, fmt, args);
388226046Sdes	va_end(args);
389226046Sdes}
390226046Sdes
391226046Sdesvoid
39276259Sgreendo_log(LogLevel level, const char *fmt, va_list args)
39357429Smarkm{
394126274Sdes#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
395124208Sdes	struct syslog_data sdata = SYSLOG_DATA_INIT;
396124208Sdes#endif
39776259Sgreen	char msgbuf[MSGBUFSIZ];
39876259Sgreen	char fmtbuf[MSGBUFSIZ];
39976259Sgreen	char *txt = NULL;
40076259Sgreen	int pri = LOG_INFO;
401181111Sdes	int saved_errno = errno;
402226046Sdes	log_handler_fn *tmp_handler;
40376259Sgreen
40476259Sgreen	if (level > log_level)
40576259Sgreen		return;
40676259Sgreen
40776259Sgreen	switch (level) {
40876259Sgreen	case SYSLOG_LEVEL_FATAL:
40976259Sgreen		if (!log_on_stderr)
41076259Sgreen			txt = "fatal";
41176259Sgreen		pri = LOG_CRIT;
41276259Sgreen		break;
41376259Sgreen	case SYSLOG_LEVEL_ERROR:
41476259Sgreen		if (!log_on_stderr)
41576259Sgreen			txt = "error";
41676259Sgreen		pri = LOG_ERR;
41776259Sgreen		break;
41876259Sgreen	case SYSLOG_LEVEL_INFO:
41976259Sgreen		pri = LOG_INFO;
42076259Sgreen		break;
42176259Sgreen	case SYSLOG_LEVEL_VERBOSE:
42276259Sgreen		pri = LOG_INFO;
42376259Sgreen		break;
42476259Sgreen	case SYSLOG_LEVEL_DEBUG1:
42576259Sgreen		txt = "debug1";
42676259Sgreen		pri = LOG_DEBUG;
42776259Sgreen		break;
42876259Sgreen	case SYSLOG_LEVEL_DEBUG2:
42976259Sgreen		txt = "debug2";
43076259Sgreen		pri = LOG_DEBUG;
43176259Sgreen		break;
43276259Sgreen	case SYSLOG_LEVEL_DEBUG3:
43376259Sgreen		txt = "debug3";
43476259Sgreen		pri = LOG_DEBUG;
43576259Sgreen		break;
43676259Sgreen	default:
43776259Sgreen		txt = "internal error";
43876259Sgreen		pri = LOG_ERR;
43976259Sgreen		break;
44076259Sgreen	}
441226046Sdes	if (txt != NULL && log_handler == NULL) {
44276259Sgreen		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
44376259Sgreen		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
44476259Sgreen	} else {
44576259Sgreen		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
44676259Sgreen	}
447137015Sdes	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
448137015Sdes	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
449226046Sdes	if (log_handler != NULL) {
450226046Sdes		/* Avoid recursion */
451226046Sdes		tmp_handler = log_handler;
452226046Sdes		log_handler = NULL;
453226046Sdes		tmp_handler(level, fmtbuf, log_handler_ctx);
454226046Sdes		log_handler = tmp_handler;
455226046Sdes	} else if (log_on_stderr) {
456124208Sdes		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
457255767Sdes		(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
45876259Sgreen	} else {
459126274Sdes#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
460124208Sdes		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
461124208Sdes		syslog_r(pri, &sdata, "%.500s", fmtbuf);
462124208Sdes		closelog_r(&sdata);
463124208Sdes#else
46476259Sgreen		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
465113908Sdes		syslog(pri, "%.500s", fmtbuf);
46676259Sgreen		closelog();
467124208Sdes#endif
46876259Sgreen	}
469181111Sdes	errno = saved_errno;
47057429Smarkm}
471