xref: /dragonfly/crypto/openssh/log.c (revision 50a69bb5)
150a69bb5SSascha Wildner /* $OpenBSD: log.c,v 1.60 2021/09/16 15:11:19 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  *
718de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
818de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
918de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1018de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1118de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1218de8d7fSPeter Avalos  */
1318de8d7fSPeter Avalos /*
1418de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1518de8d7fSPeter Avalos  *
1618de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
1718de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
1818de8d7fSPeter Avalos  * are met:
1918de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
2018de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
2118de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
2218de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
2318de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
2418de8d7fSPeter Avalos  *
2518de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2618de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2718de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2818de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2918de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3018de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3118de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3218de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3318de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3418de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3518de8d7fSPeter Avalos  */
3618de8d7fSPeter Avalos 
3718de8d7fSPeter Avalos #include "includes.h"
3818de8d7fSPeter Avalos 
3918de8d7fSPeter Avalos #include <sys/types.h>
4018de8d7fSPeter Avalos 
4136e94dc5SPeter Avalos #include <fcntl.h>
4218de8d7fSPeter Avalos #include <stdarg.h>
4318de8d7fSPeter Avalos #include <stdio.h>
4418de8d7fSPeter Avalos #include <stdlib.h>
4518de8d7fSPeter Avalos #include <string.h>
4618de8d7fSPeter Avalos #include <syslog.h>
4718de8d7fSPeter Avalos #include <unistd.h>
4818de8d7fSPeter Avalos #include <errno.h>
4936e94dc5SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
5018de8d7fSPeter Avalos # include <vis.h>
5118de8d7fSPeter Avalos #endif
5218de8d7fSPeter Avalos 
5318de8d7fSPeter Avalos #include "log.h"
5450a69bb5SSascha Wildner #include "match.h"
5518de8d7fSPeter Avalos 
5618de8d7fSPeter Avalos static LogLevel log_level = SYSLOG_LEVEL_INFO;
5718de8d7fSPeter Avalos static int log_on_stderr = 1;
5836e94dc5SPeter Avalos static int log_stderr_fd = STDERR_FILENO;
5918de8d7fSPeter Avalos static int log_facility = LOG_AUTH;
6050a69bb5SSascha Wildner static const char *argv0;
611c188a7fSPeter Avalos static log_handler_fn *log_handler;
621c188a7fSPeter Avalos static void *log_handler_ctx;
6350a69bb5SSascha Wildner static char **log_verbose;
6450a69bb5SSascha Wildner static size_t nlog_verbose;
6518de8d7fSPeter Avalos 
6618de8d7fSPeter Avalos extern char *__progname;
6718de8d7fSPeter Avalos 
6818de8d7fSPeter Avalos #define LOG_SYSLOG_VIS	(VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
6918de8d7fSPeter Avalos #define LOG_STDERR_VIS	(VIS_SAFE|VIS_OCTAL)
7018de8d7fSPeter Avalos 
7118de8d7fSPeter Avalos /* textual representation of log-facilities/levels */
7218de8d7fSPeter Avalos 
7318de8d7fSPeter Avalos static struct {
7418de8d7fSPeter Avalos 	const char *name;
7518de8d7fSPeter Avalos 	SyslogFacility val;
7618de8d7fSPeter Avalos } log_facilities[] = {
7718de8d7fSPeter Avalos 	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
7818de8d7fSPeter Avalos 	{ "USER",	SYSLOG_FACILITY_USER },
7918de8d7fSPeter Avalos 	{ "AUTH",	SYSLOG_FACILITY_AUTH },
8018de8d7fSPeter Avalos #ifdef LOG_AUTHPRIV
8118de8d7fSPeter Avalos 	{ "AUTHPRIV",	SYSLOG_FACILITY_AUTHPRIV },
8218de8d7fSPeter Avalos #endif
8318de8d7fSPeter Avalos 	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
8418de8d7fSPeter Avalos 	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
8518de8d7fSPeter Avalos 	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
8618de8d7fSPeter Avalos 	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
8718de8d7fSPeter Avalos 	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
8818de8d7fSPeter Avalos 	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
8918de8d7fSPeter Avalos 	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
9018de8d7fSPeter Avalos 	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
9118de8d7fSPeter Avalos 	{ NULL,		SYSLOG_FACILITY_NOT_SET }
9218de8d7fSPeter Avalos };
9318de8d7fSPeter Avalos 
9418de8d7fSPeter Avalos static struct {
9518de8d7fSPeter Avalos 	const char *name;
9618de8d7fSPeter Avalos 	LogLevel val;
9718de8d7fSPeter Avalos } log_levels[] =
9818de8d7fSPeter Avalos {
9918de8d7fSPeter Avalos 	{ "QUIET",	SYSLOG_LEVEL_QUIET },
10018de8d7fSPeter Avalos 	{ "FATAL",	SYSLOG_LEVEL_FATAL },
10118de8d7fSPeter Avalos 	{ "ERROR",	SYSLOG_LEVEL_ERROR },
10218de8d7fSPeter Avalos 	{ "INFO",	SYSLOG_LEVEL_INFO },
10318de8d7fSPeter Avalos 	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
10418de8d7fSPeter Avalos 	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
10518de8d7fSPeter Avalos 	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
10618de8d7fSPeter Avalos 	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
10718de8d7fSPeter Avalos 	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
10818de8d7fSPeter Avalos 	{ NULL,		SYSLOG_LEVEL_NOT_SET }
10918de8d7fSPeter Avalos };
11018de8d7fSPeter Avalos 
111664f4763Szrj LogLevel
log_level_get(void)112664f4763Szrj log_level_get(void)
113664f4763Szrj {
114664f4763Szrj 	return log_level;
115664f4763Szrj }
116664f4763Szrj 
11718de8d7fSPeter Avalos SyslogFacility
log_facility_number(char * name)11818de8d7fSPeter Avalos log_facility_number(char *name)
11918de8d7fSPeter Avalos {
12018de8d7fSPeter Avalos 	int i;
12118de8d7fSPeter Avalos 
12218de8d7fSPeter Avalos 	if (name != NULL)
12318de8d7fSPeter Avalos 		for (i = 0; log_facilities[i].name; i++)
12418de8d7fSPeter Avalos 			if (strcasecmp(log_facilities[i].name, name) == 0)
12518de8d7fSPeter Avalos 				return log_facilities[i].val;
12618de8d7fSPeter Avalos 	return SYSLOG_FACILITY_NOT_SET;
12718de8d7fSPeter Avalos }
12818de8d7fSPeter Avalos 
12918de8d7fSPeter Avalos const char *
log_facility_name(SyslogFacility facility)13018de8d7fSPeter Avalos log_facility_name(SyslogFacility facility)
13118de8d7fSPeter Avalos {
13218de8d7fSPeter Avalos 	u_int i;
13318de8d7fSPeter Avalos 
13418de8d7fSPeter Avalos 	for (i = 0;  log_facilities[i].name; i++)
13518de8d7fSPeter Avalos 		if (log_facilities[i].val == facility)
13618de8d7fSPeter Avalos 			return log_facilities[i].name;
13718de8d7fSPeter Avalos 	return NULL;
13818de8d7fSPeter Avalos }
13918de8d7fSPeter Avalos 
14018de8d7fSPeter Avalos LogLevel
log_level_number(char * name)14118de8d7fSPeter Avalos log_level_number(char *name)
14218de8d7fSPeter Avalos {
14318de8d7fSPeter Avalos 	int i;
14418de8d7fSPeter Avalos 
14518de8d7fSPeter Avalos 	if (name != NULL)
14618de8d7fSPeter Avalos 		for (i = 0; log_levels[i].name; i++)
14718de8d7fSPeter Avalos 			if (strcasecmp(log_levels[i].name, name) == 0)
14818de8d7fSPeter Avalos 				return log_levels[i].val;
14918de8d7fSPeter Avalos 	return SYSLOG_LEVEL_NOT_SET;
15018de8d7fSPeter Avalos }
15118de8d7fSPeter Avalos 
15218de8d7fSPeter Avalos const char *
log_level_name(LogLevel level)15318de8d7fSPeter Avalos log_level_name(LogLevel level)
15418de8d7fSPeter Avalos {
15518de8d7fSPeter Avalos 	u_int i;
15618de8d7fSPeter Avalos 
15718de8d7fSPeter Avalos 	for (i = 0; log_levels[i].name != NULL; i++)
15818de8d7fSPeter Avalos 		if (log_levels[i].val == level)
15918de8d7fSPeter Avalos 			return log_levels[i].name;
16018de8d7fSPeter Avalos 	return NULL;
16118de8d7fSPeter Avalos }
16218de8d7fSPeter Avalos 
16318de8d7fSPeter Avalos void
log_verbose_add(const char * s)16450a69bb5SSascha Wildner log_verbose_add(const char *s)
16518de8d7fSPeter Avalos {
16650a69bb5SSascha Wildner 	char **tmp;
16718de8d7fSPeter Avalos 
16850a69bb5SSascha Wildner 	/* Ignore failures here */
16950a69bb5SSascha Wildner 	if ((tmp = recallocarray(log_verbose, nlog_verbose, nlog_verbose + 1,
17050a69bb5SSascha Wildner 	    sizeof(*log_verbose))) != NULL) {
17150a69bb5SSascha Wildner 		log_verbose = tmp;
17250a69bb5SSascha Wildner 		if ((log_verbose[nlog_verbose] = strdup(s)) != NULL)
17350a69bb5SSascha Wildner 			nlog_verbose++;
17450a69bb5SSascha Wildner 	}
17518de8d7fSPeter Avalos }
17618de8d7fSPeter Avalos 
17718de8d7fSPeter Avalos void
log_verbose_reset(void)17850a69bb5SSascha Wildner log_verbose_reset(void)
17918de8d7fSPeter Avalos {
18050a69bb5SSascha Wildner 	size_t i;
18118de8d7fSPeter Avalos 
18250a69bb5SSascha Wildner 	for (i = 0; i < nlog_verbose; i++)
18350a69bb5SSascha Wildner 		free(log_verbose[i]);
18450a69bb5SSascha Wildner 	free(log_verbose);
18550a69bb5SSascha Wildner 	log_verbose = NULL;
18650a69bb5SSascha Wildner 	nlog_verbose = 0;
18718de8d7fSPeter Avalos }
18818de8d7fSPeter Avalos 
18918de8d7fSPeter Avalos /*
19018de8d7fSPeter Avalos  * Initialize the log.
19118de8d7fSPeter Avalos  */
19218de8d7fSPeter Avalos 
19318de8d7fSPeter Avalos void
log_init(const char * av0,LogLevel level,SyslogFacility facility,int on_stderr)19450a69bb5SSascha Wildner log_init(const char *av0, LogLevel level, SyslogFacility facility,
19550a69bb5SSascha Wildner     int on_stderr)
19618de8d7fSPeter Avalos {
19718de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
19818de8d7fSPeter Avalos 	struct syslog_data sdata = SYSLOG_DATA_INIT;
19918de8d7fSPeter Avalos #endif
20018de8d7fSPeter Avalos 
20118de8d7fSPeter Avalos 	argv0 = av0;
20218de8d7fSPeter Avalos 
203ce74bacaSMatthew Dillon 	if (log_change_level(level) != 0) {
20418de8d7fSPeter Avalos 		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
20518de8d7fSPeter Avalos 		    (int) level);
20618de8d7fSPeter Avalos 		exit(1);
20718de8d7fSPeter Avalos 	}
20818de8d7fSPeter Avalos 
2091c188a7fSPeter Avalos 	log_handler = NULL;
2101c188a7fSPeter Avalos 	log_handler_ctx = NULL;
2111c188a7fSPeter Avalos 
21218de8d7fSPeter Avalos 	log_on_stderr = on_stderr;
21318de8d7fSPeter Avalos 	if (on_stderr)
21418de8d7fSPeter Avalos 		return;
21518de8d7fSPeter Avalos 
21618de8d7fSPeter Avalos 	switch (facility) {
21718de8d7fSPeter Avalos 	case SYSLOG_FACILITY_DAEMON:
21818de8d7fSPeter Avalos 		log_facility = LOG_DAEMON;
21918de8d7fSPeter Avalos 		break;
22018de8d7fSPeter Avalos 	case SYSLOG_FACILITY_USER:
22118de8d7fSPeter Avalos 		log_facility = LOG_USER;
22218de8d7fSPeter Avalos 		break;
22318de8d7fSPeter Avalos 	case SYSLOG_FACILITY_AUTH:
22418de8d7fSPeter Avalos 		log_facility = LOG_AUTH;
22518de8d7fSPeter Avalos 		break;
22618de8d7fSPeter Avalos #ifdef LOG_AUTHPRIV
22718de8d7fSPeter Avalos 	case SYSLOG_FACILITY_AUTHPRIV:
22818de8d7fSPeter Avalos 		log_facility = LOG_AUTHPRIV;
22918de8d7fSPeter Avalos 		break;
23018de8d7fSPeter Avalos #endif
23118de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL0:
23218de8d7fSPeter Avalos 		log_facility = LOG_LOCAL0;
23318de8d7fSPeter Avalos 		break;
23418de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL1:
23518de8d7fSPeter Avalos 		log_facility = LOG_LOCAL1;
23618de8d7fSPeter Avalos 		break;
23718de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL2:
23818de8d7fSPeter Avalos 		log_facility = LOG_LOCAL2;
23918de8d7fSPeter Avalos 		break;
24018de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL3:
24118de8d7fSPeter Avalos 		log_facility = LOG_LOCAL3;
24218de8d7fSPeter Avalos 		break;
24318de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL4:
24418de8d7fSPeter Avalos 		log_facility = LOG_LOCAL4;
24518de8d7fSPeter Avalos 		break;
24618de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL5:
24718de8d7fSPeter Avalos 		log_facility = LOG_LOCAL5;
24818de8d7fSPeter Avalos 		break;
24918de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL6:
25018de8d7fSPeter Avalos 		log_facility = LOG_LOCAL6;
25118de8d7fSPeter Avalos 		break;
25218de8d7fSPeter Avalos 	case SYSLOG_FACILITY_LOCAL7:
25318de8d7fSPeter Avalos 		log_facility = LOG_LOCAL7;
25418de8d7fSPeter Avalos 		break;
25518de8d7fSPeter Avalos 	default:
25618de8d7fSPeter Avalos 		fprintf(stderr,
25718de8d7fSPeter Avalos 		    "Unrecognized internal syslog facility code %d\n",
25818de8d7fSPeter Avalos 		    (int) facility);
25918de8d7fSPeter Avalos 		exit(1);
26018de8d7fSPeter Avalos 	}
26118de8d7fSPeter Avalos 
26218de8d7fSPeter Avalos 	/*
26318de8d7fSPeter Avalos 	 * If an external library (eg libwrap) attempts to use syslog
26418de8d7fSPeter Avalos 	 * immediately after reexec, syslog may be pointing to the wrong
26518de8d7fSPeter Avalos 	 * facility, so we force an open/close of syslog here.
26618de8d7fSPeter Avalos 	 */
26718de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
26818de8d7fSPeter Avalos 	openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
26918de8d7fSPeter Avalos 	closelog_r(&sdata);
27018de8d7fSPeter Avalos #else
27118de8d7fSPeter Avalos 	openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
27218de8d7fSPeter Avalos 	closelog();
27318de8d7fSPeter Avalos #endif
27418de8d7fSPeter Avalos }
27518de8d7fSPeter Avalos 
276ce74bacaSMatthew Dillon int
log_change_level(LogLevel new_log_level)27736e94dc5SPeter Avalos log_change_level(LogLevel new_log_level)
27836e94dc5SPeter Avalos {
27936e94dc5SPeter Avalos 	/* no-op if log_init has not been called */
28036e94dc5SPeter Avalos 	if (argv0 == NULL)
281ce74bacaSMatthew Dillon 		return 0;
282ce74bacaSMatthew Dillon 
283ce74bacaSMatthew Dillon 	switch (new_log_level) {
284ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_QUIET:
285ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_FATAL:
286ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_ERROR:
287ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_INFO:
288ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_VERBOSE:
289ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_DEBUG1:
290ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_DEBUG2:
291ce74bacaSMatthew Dillon 	case SYSLOG_LEVEL_DEBUG3:
292ce74bacaSMatthew Dillon 		log_level = new_log_level;
293ce74bacaSMatthew Dillon 		return 0;
294ce74bacaSMatthew Dillon 	default:
295ce74bacaSMatthew Dillon 		return -1;
296ce74bacaSMatthew Dillon 	}
29736e94dc5SPeter Avalos }
29836e94dc5SPeter Avalos 
29936e94dc5SPeter Avalos int
log_is_on_stderr(void)30036e94dc5SPeter Avalos log_is_on_stderr(void)
30136e94dc5SPeter Avalos {
302e9778795SPeter Avalos 	return log_on_stderr && log_stderr_fd == STDERR_FILENO;
30336e94dc5SPeter Avalos }
30436e94dc5SPeter Avalos 
30536e94dc5SPeter Avalos /* redirect what would usually get written to stderr to specified file */
30636e94dc5SPeter Avalos void
log_redirect_stderr_to(const char * logfile)30736e94dc5SPeter Avalos log_redirect_stderr_to(const char *logfile)
30836e94dc5SPeter Avalos {
30936e94dc5SPeter Avalos 	int fd;
31036e94dc5SPeter Avalos 
31150a69bb5SSascha Wildner 	if (logfile == NULL) {
31250a69bb5SSascha Wildner 		if (log_stderr_fd != STDERR_FILENO) {
31350a69bb5SSascha Wildner 			close(log_stderr_fd);
31450a69bb5SSascha Wildner 			log_stderr_fd = STDERR_FILENO;
31550a69bb5SSascha Wildner 		}
31650a69bb5SSascha Wildner 		return;
31750a69bb5SSascha Wildner 	}
31850a69bb5SSascha Wildner 
31936e94dc5SPeter Avalos 	if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
32036e94dc5SPeter Avalos 		fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile,
32136e94dc5SPeter Avalos 		    strerror(errno));
32236e94dc5SPeter Avalos 		exit(1);
32336e94dc5SPeter Avalos 	}
32436e94dc5SPeter Avalos 	log_stderr_fd = fd;
32536e94dc5SPeter Avalos }
32636e94dc5SPeter Avalos 
32718de8d7fSPeter Avalos #define MSGBUFSIZ 1024
32818de8d7fSPeter Avalos 
32918de8d7fSPeter Avalos void
set_log_handler(log_handler_fn * handler,void * ctx)3301c188a7fSPeter Avalos set_log_handler(log_handler_fn *handler, void *ctx)
3311c188a7fSPeter Avalos {
3321c188a7fSPeter Avalos 	log_handler = handler;
3331c188a7fSPeter Avalos 	log_handler_ctx = ctx;
3341c188a7fSPeter Avalos }
3351c188a7fSPeter Avalos 
33650a69bb5SSascha Wildner static void
do_log(LogLevel level,int force,const char * suffix,const char * fmt,va_list args)33750a69bb5SSascha Wildner do_log(LogLevel level, int force, const char *suffix, const char *fmt,
33850a69bb5SSascha Wildner     va_list args)
33918de8d7fSPeter Avalos {
34018de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
34118de8d7fSPeter Avalos 	struct syslog_data sdata = SYSLOG_DATA_INIT;
34218de8d7fSPeter Avalos #endif
34318de8d7fSPeter Avalos 	char msgbuf[MSGBUFSIZ];
34418de8d7fSPeter Avalos 	char fmtbuf[MSGBUFSIZ];
34518de8d7fSPeter Avalos 	char *txt = NULL;
34618de8d7fSPeter Avalos 	int pri = LOG_INFO;
34718de8d7fSPeter Avalos 	int saved_errno = errno;
3481c188a7fSPeter Avalos 	log_handler_fn *tmp_handler;
34950a69bb5SSascha Wildner 	const char *progname = argv0 != NULL ? argv0 : __progname;
35018de8d7fSPeter Avalos 
35150a69bb5SSascha Wildner 	if (!force && level > log_level)
35218de8d7fSPeter Avalos 		return;
35318de8d7fSPeter Avalos 
35418de8d7fSPeter Avalos 	switch (level) {
35518de8d7fSPeter Avalos 	case SYSLOG_LEVEL_FATAL:
35618de8d7fSPeter Avalos 		if (!log_on_stderr)
35718de8d7fSPeter Avalos 			txt = "fatal";
35818de8d7fSPeter Avalos 		pri = LOG_CRIT;
35918de8d7fSPeter Avalos 		break;
36018de8d7fSPeter Avalos 	case SYSLOG_LEVEL_ERROR:
36118de8d7fSPeter Avalos 		if (!log_on_stderr)
36218de8d7fSPeter Avalos 			txt = "error";
36318de8d7fSPeter Avalos 		pri = LOG_ERR;
36418de8d7fSPeter Avalos 		break;
36518de8d7fSPeter Avalos 	case SYSLOG_LEVEL_INFO:
36618de8d7fSPeter Avalos 		pri = LOG_INFO;
36718de8d7fSPeter Avalos 		break;
36818de8d7fSPeter Avalos 	case SYSLOG_LEVEL_VERBOSE:
36918de8d7fSPeter Avalos 		pri = LOG_INFO;
37018de8d7fSPeter Avalos 		break;
37118de8d7fSPeter Avalos 	case SYSLOG_LEVEL_DEBUG1:
37218de8d7fSPeter Avalos 		txt = "debug1";
37318de8d7fSPeter Avalos 		pri = LOG_DEBUG;
37418de8d7fSPeter Avalos 		break;
37518de8d7fSPeter Avalos 	case SYSLOG_LEVEL_DEBUG2:
37618de8d7fSPeter Avalos 		txt = "debug2";
37718de8d7fSPeter Avalos 		pri = LOG_DEBUG;
37818de8d7fSPeter Avalos 		break;
37918de8d7fSPeter Avalos 	case SYSLOG_LEVEL_DEBUG3:
38018de8d7fSPeter Avalos 		txt = "debug3";
38118de8d7fSPeter Avalos 		pri = LOG_DEBUG;
38218de8d7fSPeter Avalos 		break;
38318de8d7fSPeter Avalos 	default:
38418de8d7fSPeter Avalos 		txt = "internal error";
38518de8d7fSPeter Avalos 		pri = LOG_ERR;
38618de8d7fSPeter Avalos 		break;
38718de8d7fSPeter Avalos 	}
3881c188a7fSPeter Avalos 	if (txt != NULL && log_handler == NULL) {
38918de8d7fSPeter Avalos 		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
39018de8d7fSPeter Avalos 		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
39118de8d7fSPeter Avalos 	} else {
39218de8d7fSPeter Avalos 		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
39318de8d7fSPeter Avalos 	}
39450a69bb5SSascha Wildner 	if (suffix != NULL) {
39550a69bb5SSascha Wildner 		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", msgbuf, suffix);
39650a69bb5SSascha Wildner 		strlcpy(msgbuf, fmtbuf, sizeof(msgbuf));
39750a69bb5SSascha Wildner 	}
39818de8d7fSPeter Avalos 	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
39918de8d7fSPeter Avalos 	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
4001c188a7fSPeter Avalos 	if (log_handler != NULL) {
4011c188a7fSPeter Avalos 		/* Avoid recursion */
4021c188a7fSPeter Avalos 		tmp_handler = log_handler;
4031c188a7fSPeter Avalos 		log_handler = NULL;
40450a69bb5SSascha Wildner 		tmp_handler(level, force, fmtbuf, log_handler_ctx);
4051c188a7fSPeter Avalos 		log_handler = tmp_handler;
4061c188a7fSPeter Avalos 	} else if (log_on_stderr) {
40750a69bb5SSascha Wildner 		snprintf(msgbuf, sizeof msgbuf, "%s%s%.*s\r\n",
40850a69bb5SSascha Wildner 		    (log_on_stderr > 1) ? progname : "",
40950a69bb5SSascha Wildner 		    (log_on_stderr > 1) ? ": " : "",
410ce74bacaSMatthew Dillon 		    (int)sizeof msgbuf - 3, fmtbuf);
41136e94dc5SPeter Avalos 		(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
41218de8d7fSPeter Avalos 	} else {
41318de8d7fSPeter Avalos #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
41450a69bb5SSascha Wildner 		openlog_r(progname, LOG_PID, log_facility, &sdata);
41518de8d7fSPeter Avalos 		syslog_r(pri, &sdata, "%.500s", fmtbuf);
41618de8d7fSPeter Avalos 		closelog_r(&sdata);
41718de8d7fSPeter Avalos #else
41850a69bb5SSascha Wildner 		openlog(progname, LOG_PID, log_facility);
41918de8d7fSPeter Avalos 		syslog(pri, "%.500s", fmtbuf);
42018de8d7fSPeter Avalos 		closelog();
42118de8d7fSPeter Avalos #endif
42218de8d7fSPeter Avalos 	}
42318de8d7fSPeter Avalos 	errno = saved_errno;
42418de8d7fSPeter Avalos }
42550a69bb5SSascha Wildner 
42650a69bb5SSascha Wildner void
sshlog(const char * file,const char * func,int line,int showfunc,LogLevel level,const char * suffix,const char * fmt,...)42750a69bb5SSascha Wildner sshlog(const char *file, const char *func, int line, int showfunc,
42850a69bb5SSascha Wildner     LogLevel level, const char *suffix, const char *fmt, ...)
42950a69bb5SSascha Wildner {
43050a69bb5SSascha Wildner 	va_list args;
43150a69bb5SSascha Wildner 
43250a69bb5SSascha Wildner 	va_start(args, fmt);
43350a69bb5SSascha Wildner 	sshlogv(file, func, line, showfunc, level, suffix, fmt, args);
43450a69bb5SSascha Wildner 	va_end(args);
43550a69bb5SSascha Wildner }
43650a69bb5SSascha Wildner 
43750a69bb5SSascha Wildner void
sshlogdie(const char * file,const char * func,int line,int showfunc,LogLevel level,const char * suffix,const char * fmt,...)43850a69bb5SSascha Wildner sshlogdie(const char *file, const char *func, int line, int showfunc,
43950a69bb5SSascha Wildner     LogLevel level, const char *suffix, const char *fmt, ...)
44050a69bb5SSascha Wildner {
44150a69bb5SSascha Wildner 	va_list args;
44250a69bb5SSascha Wildner 
44350a69bb5SSascha Wildner 	va_start(args, fmt);
44450a69bb5SSascha Wildner 	sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO,
44550a69bb5SSascha Wildner 	    suffix, fmt, args);
44650a69bb5SSascha Wildner 	va_end(args);
44750a69bb5SSascha Wildner 	cleanup_exit(255);
44850a69bb5SSascha Wildner }
44950a69bb5SSascha Wildner 
45050a69bb5SSascha Wildner void
sshsigdie(const char * file,const char * func,int line,int showfunc,LogLevel level,const char * suffix,const char * fmt,...)45150a69bb5SSascha Wildner sshsigdie(const char *file, const char *func, int line, int showfunc,
45250a69bb5SSascha Wildner     LogLevel level, const char *suffix, const char *fmt, ...)
45350a69bb5SSascha Wildner {
45450a69bb5SSascha Wildner 	va_list args;
45550a69bb5SSascha Wildner 
45650a69bb5SSascha Wildner 	va_start(args, fmt);
45750a69bb5SSascha Wildner 	sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL,
45850a69bb5SSascha Wildner 	    suffix, fmt, args);
45950a69bb5SSascha Wildner 	va_end(args);
46050a69bb5SSascha Wildner 	_exit(1);
46150a69bb5SSascha Wildner }
46250a69bb5SSascha Wildner 
46350a69bb5SSascha Wildner void
sshlogv(const char * file,const char * func,int line,int showfunc,LogLevel level,const char * suffix,const char * fmt,va_list args)46450a69bb5SSascha Wildner sshlogv(const char *file, const char *func, int line, int showfunc,
46550a69bb5SSascha Wildner     LogLevel level, const char *suffix, const char *fmt, va_list args)
46650a69bb5SSascha Wildner {
46750a69bb5SSascha Wildner 	char tag[128], fmt2[MSGBUFSIZ + 128];
46850a69bb5SSascha Wildner 	int forced = 0;
46950a69bb5SSascha Wildner 	const char *cp;
47050a69bb5SSascha Wildner 	size_t i;
47150a69bb5SSascha Wildner 
47250a69bb5SSascha Wildner 	snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)",
47350a69bb5SSascha Wildner 	    (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line,
47450a69bb5SSascha Wildner 	    (long)getpid());
47550a69bb5SSascha Wildner 	for (i = 0; i < nlog_verbose; i++) {
47650a69bb5SSascha Wildner 		if (match_pattern_list(tag, log_verbose[i], 0) == 1) {
47750a69bb5SSascha Wildner 			forced = 1;
47850a69bb5SSascha Wildner 			break;
47950a69bb5SSascha Wildner 		}
48050a69bb5SSascha Wildner 	}
48150a69bb5SSascha Wildner 
48250a69bb5SSascha Wildner 	if (forced)
48350a69bb5SSascha Wildner 		snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt);
48450a69bb5SSascha Wildner 	else if (showfunc)
48550a69bb5SSascha Wildner 		snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt);
48650a69bb5SSascha Wildner 	else
48750a69bb5SSascha Wildner 		strlcpy(fmt2, fmt, sizeof(fmt2));
48850a69bb5SSascha Wildner 
48950a69bb5SSascha Wildner 	do_log(level, forced, suffix, fmt2, args);
49050a69bb5SSascha Wildner }
49150a69bb5SSascha Wildner 
49250a69bb5SSascha Wildner void
sshlogdirect(LogLevel level,int forced,const char * fmt,...)49350a69bb5SSascha Wildner sshlogdirect(LogLevel level, int forced, const char *fmt, ...)
49450a69bb5SSascha Wildner {
49550a69bb5SSascha Wildner 	va_list args;
49650a69bb5SSascha Wildner 
49750a69bb5SSascha Wildner 	va_start(args, fmt);
49850a69bb5SSascha Wildner 	do_log(level, forced, NULL, fmt, args);
49950a69bb5SSascha Wildner 	va_end(args);
50050a69bb5SSascha Wildner }
501