123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- /* $OpenBSD: log.c,v 1.52 2020/07/03 06:46:41 djm Exp $ */
- /*
- * 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".
- */
- /*
- * 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.
- */
- #include "includes.h"
- #include <sys/types.h>
- #include <fcntl.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <syslog.h>
- #include <unistd.h>
- #include <errno.h>
- #include "packet.h" /* needed for host and port look ups */
- #ifdef HAVE_SYS_TIME_H
- # include <sys/time.h> /* to get current time */
- #endif
- #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
- # include <vis.h>
- #endif
- #include "log.h"
- static LogLevel log_level = SYSLOG_LEVEL_INFO;
- static int log_on_stderr = 1;
- static int log_stderr_fd = STDERR_FILENO;
- static int log_facility = LOG_AUTH;
- static const char *argv0;
- static log_handler_fn *log_handler;
- static void *log_handler_ctx;
- extern char *__progname;
- extern struct ssh *active_state;
- #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
- #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL)
- /* 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 },
- #ifdef LOG_AUTHPRIV
- { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV },
- #endif
- { "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 },
- { NULL, SYSLOG_FACILITY_NOT_SET }
- };
- static struct {
- const char *name;
- LogLevel val;
- } log_levels[] =
- {
- { "SILENT", SYSLOG_LEVEL_QUIET }, /* compatibility */
- { "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 },
- { NULL, SYSLOG_LEVEL_NOT_SET }
- };
- LogLevel
- log_level_get(void)
- {
- return log_level;
- }
- SyslogFacility
- log_facility_number(char *name)
- {
- int i;
- if (name != NULL)
- for (i = 0; log_facilities[i].name; i++)
- if (strcasecmp(log_facilities[i].name, name) == 0)
- return log_facilities[i].val;
- return SYSLOG_FACILITY_NOT_SET;
- }
- 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;
- }
- LogLevel
- log_level_number(char *name)
- {
- int i;
- if (name != NULL)
- for (i = 0; log_levels[i].name; i++)
- if (strcasecmp(log_levels[i].name, name) == 0)
- return log_levels[i].val;
- return SYSLOG_LEVEL_NOT_SET;
- }
- 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;
- }
- /* Error messages that should be logged. */
- void
- error(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_ERROR, fmt, args);
- va_end(args);
- }
- void
- sigdie(const char *fmt,...)
- {
- #ifdef DO_LOG_SAFE_IN_SIGHAND
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_FATAL, fmt, args);
- va_end(args);
- #endif
- _exit(1);
- }
- void
- logdie(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_INFO, fmt, args);
- va_end(args);
- cleanup_exit(255);
- }
- /* Log this message (information that usually should go to the log). */
- void
- logit(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_INFO, fmt, args);
- va_end(args);
- }
- /* More detailed messages (information that does not need to go to the log). */
- void
- verbose(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
- va_end(args);
- }
- /* Debugging messages that should not be logged during normal operation. */
- void
- debug(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
- va_end(args);
- }
- void
- debug2(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
- va_end(args);
- }
- void
- debug3(const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
- va_end(args);
- }
- /*
- * Initialize the log.
- */
- void
- log_init(const char *av0, LogLevel level, SyslogFacility facility,
- int on_stderr)
- {
- log_init_handler(av0, level, facility, on_stderr, 1);
- }
- void
- log_init_handler(const char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int reset_handler) {
- #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
- struct syslog_data sdata = SYSLOG_DATA_INIT;
- #endif
- argv0 = av0;
- if (log_change_level(level) != 0) {
- fprintf(stderr, "Unrecognized internal syslog level code %d\n",
- (int) level);
- exit(1);
- }
- if (reset_handler) {
- log_handler = NULL;
- log_handler_ctx = NULL;
- }
- 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;
- #ifdef LOG_AUTHPRIV
- case SYSLOG_FACILITY_AUTHPRIV:
- log_facility = LOG_AUTHPRIV;
- break;
- #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,
- "Unrecognized internal syslog facility code %d\n",
- (int) facility);
- exit(1);
- }
- /*
- * 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
- }
- int
- log_change_level(LogLevel new_log_level)
- {
- /* no-op if log_init has not been called */
- if (argv0 == NULL)
- return 0;
- switch (new_log_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 = new_log_level;
- return 0;
- default:
- return -1;
- }
- }
- int
- log_is_on_stderr(void)
- {
- return log_on_stderr && log_stderr_fd == STDERR_FILENO;
- }
- /* redirect what would usually get written to stderr to specified file */
- void
- log_redirect_stderr_to(const char *logfile)
- {
- int fd;
- if (logfile == NULL) {
- if (log_stderr_fd != STDERR_FILENO) {
- close(log_stderr_fd);
- log_stderr_fd = STDERR_FILENO;
- }
- return;
- }
- 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;
- }
- #define MSGBUFSIZ 1024
- 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);
- }
- void
- do_log(LogLevel level, const char *fmt, va_list args)
- {
- #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
- struct syslog_data sdata = SYSLOG_DATA_INIT;
- #endif
- char msgbuf[MSGBUFSIZ];
- char fmtbuf[MSGBUFSIZ];
- char *txt = NULL;
- int pri = LOG_INFO;
- int saved_errno = errno;
- log_handler_fn *tmp_handler;
- 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;
- }
- if (txt != NULL && log_handler == NULL) {
- snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
- vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
- } else {
- vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
- }
- strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
- log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
- 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) {
- snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n",
- (int)sizeof msgbuf - 3, fmtbuf);
- (void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
- } else {
- #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
- openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
- syslog_r(pri, &sdata, "%.500s", fmtbuf);
- closelog_r(&sdata);
- #else
- openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
- syslog(pri, "%.500s", fmtbuf);
- closelog();
- #endif
- }
- errno = saved_errno;
- }
|