1/* $OpenBSD: log.c,v 1.61 2023/12/06 21:06:48 djm Exp $ */ 2/* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * 7 * As far as I am concerned, the code I have written for this software 8 * can be used freely for any purpose. Any derived versions of this 9 * software must be clearly marked as such, and if the derived work is 10 * incompatible with the protocol description in the RFC file, it must be 11 * called by a name other than "ssh" or "Secure Shell". 12 */ 13/* 14 * Copyright (c) 2000 Markus Friedl. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37#include "includes.h" 38 39#include <sys/types.h> 40 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# include <vis.h> 51#endif 52 53#include "log.h" 54#include "match.h" 55 56static LogLevel log_level = SYSLOG_LEVEL_INFO; 57static int log_on_stderr = 1; 58static int log_stderr_fd = STDERR_FILENO; 59static int log_facility = LOG_AUTH; 60static const char *argv0; 61static log_handler_fn *log_handler; 62static void *log_handler_ctx; 63static char **log_verbose; 64static size_t nlog_verbose; 65 66extern char *__progname; 67 68#define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) 69#define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) 70 71/* textual representation of log-facilities/levels */ 72 73static struct { 74 const char *name; 75 SyslogFacility val; 76} log_facilities[] = { 77 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 78 { "USER", SYSLOG_FACILITY_USER }, 79 { "AUTH", SYSLOG_FACILITY_AUTH }, 80#ifdef LOG_AUTHPRIV 81 { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, 82#endif 83 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 84 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 85 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 86 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 87 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 88 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 89 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 90 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 91 { NULL, SYSLOG_FACILITY_NOT_SET } 92}; 93 94static struct { 95 const char *name; 96 LogLevel val; 97} log_levels[] = 98{ 99 { "QUIET", SYSLOG_LEVEL_QUIET }, 100 { "FATAL", SYSLOG_LEVEL_FATAL }, 101 { "ERROR", SYSLOG_LEVEL_ERROR }, 102 { "INFO", SYSLOG_LEVEL_INFO }, 103 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 104 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 105 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 106 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 107 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 108 { NULL, SYSLOG_LEVEL_NOT_SET } 109}; 110 111LogLevel 112log_level_get(void) 113{ 114 return log_level; 115} 116 117SyslogFacility 118log_facility_number(char *name) 119{ 120 int i; 121 122 if (name != NULL) 123 for (i = 0; log_facilities[i].name; i++) 124 if (strcasecmp(log_facilities[i].name, name) == 0) 125 return log_facilities[i].val; 126 return SYSLOG_FACILITY_NOT_SET; 127} 128 129const char * 130log_facility_name(SyslogFacility facility) 131{ 132 u_int i; 133 134 for (i = 0; log_facilities[i].name; i++) 135 if (log_facilities[i].val == facility) 136 return log_facilities[i].name; 137 return NULL; 138} 139 140LogLevel 141log_level_number(char *name) 142{ 143 int i; 144 145 if (name != NULL) 146 for (i = 0; log_levels[i].name; i++) 147 if (strcasecmp(log_levels[i].name, name) == 0) 148 return log_levels[i].val; 149 return SYSLOG_LEVEL_NOT_SET; 150} 151 152const char * 153log_level_name(LogLevel level) 154{ 155 u_int i; 156 157 for (i = 0; log_levels[i].name != NULL; i++) 158 if (log_levels[i].val == level) 159 return log_levels[i].name; 160 return NULL; 161} 162 163void 164log_verbose_add(const char *s) 165{ 166 char **tmp; 167 168 /* Ignore failures here */ 169 if ((tmp = recallocarray(log_verbose, nlog_verbose, nlog_verbose + 1, 170 sizeof(*log_verbose))) != NULL) { 171 log_verbose = tmp; 172 if ((log_verbose[nlog_verbose] = strdup(s)) != NULL) 173 nlog_verbose++; 174 } 175} 176 177void 178log_verbose_reset(void) 179{ 180 size_t i; 181 182 for (i = 0; i < nlog_verbose; i++) 183 free(log_verbose[i]); 184 free(log_verbose); 185 log_verbose = NULL; 186 nlog_verbose = 0; 187} 188 189/* 190 * Initialize the log. 191 */ 192 193void 194log_init(const char *av0, LogLevel level, SyslogFacility facility, 195 int on_stderr) 196{ 197#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 198 struct syslog_data sdata = SYSLOG_DATA_INIT; 199#endif 200 201 argv0 = av0; 202 203 if (log_change_level(level) != 0) { 204 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 205 (int) level); 206 exit(1); 207 } 208 209 log_handler = NULL; 210 log_handler_ctx = NULL; 211 212 log_on_stderr = on_stderr; 213 if (on_stderr) 214 return; 215 216 switch (facility) { 217 case SYSLOG_FACILITY_DAEMON: 218 log_facility = LOG_DAEMON; 219 break; 220 case SYSLOG_FACILITY_USER: 221 log_facility = LOG_USER; 222 break; 223 case SYSLOG_FACILITY_AUTH: 224 log_facility = LOG_AUTH; 225 break; 226#ifdef LOG_AUTHPRIV 227 case SYSLOG_FACILITY_AUTHPRIV: 228 log_facility = LOG_AUTHPRIV; 229 break; 230#endif 231 case SYSLOG_FACILITY_LOCAL0: 232 log_facility = LOG_LOCAL0; 233 break; 234 case SYSLOG_FACILITY_LOCAL1: 235 log_facility = LOG_LOCAL1; 236 break; 237 case SYSLOG_FACILITY_LOCAL2: 238 log_facility = LOG_LOCAL2; 239 break; 240 case SYSLOG_FACILITY_LOCAL3: 241 log_facility = LOG_LOCAL3; 242 break; 243 case SYSLOG_FACILITY_LOCAL4: 244 log_facility = LOG_LOCAL4; 245 break; 246 case SYSLOG_FACILITY_LOCAL5: 247 log_facility = LOG_LOCAL5; 248 break; 249 case SYSLOG_FACILITY_LOCAL6: 250 log_facility = LOG_LOCAL6; 251 break; 252 case SYSLOG_FACILITY_LOCAL7: 253 log_facility = LOG_LOCAL7; 254 break; 255 default: 256 fprintf(stderr, 257 "Unrecognized internal syslog facility code %d\n", 258 (int) facility); 259 exit(1); 260 } 261 262 /* 263 * If an external library (eg libwrap) attempts to use syslog 264 * immediately after reexec, syslog may be pointing to the wrong 265 * facility, so we force an open/close of syslog here. 266 */ 267#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 268 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 269 closelog_r(&sdata); 270#else 271 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 272 closelog(); 273#endif 274} 275 276int 277log_change_level(LogLevel new_log_level) 278{ 279 /* no-op if log_init has not been called */ 280 if (argv0 == NULL) 281 return 0; 282 283 switch (new_log_level) { 284 case SYSLOG_LEVEL_QUIET: 285 case SYSLOG_LEVEL_FATAL: 286 case SYSLOG_LEVEL_ERROR: 287 case SYSLOG_LEVEL_INFO: 288 case SYSLOG_LEVEL_VERBOSE: 289 case SYSLOG_LEVEL_DEBUG1: 290 case SYSLOG_LEVEL_DEBUG2: 291 case SYSLOG_LEVEL_DEBUG3: 292 log_level = new_log_level; 293 return 0; 294 default: 295 return -1; 296 } 297} 298 299int 300log_is_on_stderr(void) 301{ 302 return log_on_stderr && log_stderr_fd == STDERR_FILENO; 303} 304 305/* redirect what would usually get written to stderr to specified file */ 306void 307log_redirect_stderr_to(const char *logfile) 308{ 309 int fd; 310 311 if (logfile == NULL) { 312 if (log_stderr_fd != STDERR_FILENO) { 313 close(log_stderr_fd); 314 log_stderr_fd = STDERR_FILENO; 315 } 316 return; 317 } 318 319 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 320 fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 321 strerror(errno)); 322 exit(1); 323 } 324 log_stderr_fd = fd; 325} 326 327#define MSGBUFSIZ 1024 328 329void 330set_log_handler(log_handler_fn *handler, void *ctx) 331{ 332 log_handler = handler; 333 log_handler_ctx = ctx; 334} 335 336static void 337do_log(LogLevel level, int force, const char *suffix, const char *fmt, 338 va_list args) 339{ 340#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 341 struct syslog_data sdata = SYSLOG_DATA_INIT; 342#endif 343 char msgbuf[MSGBUFSIZ]; 344 char fmtbuf[MSGBUFSIZ]; 345 char *txt = NULL; 346 int pri = LOG_INFO; 347 int saved_errno = errno; 348 log_handler_fn *tmp_handler; 349 const char *progname = argv0 != NULL ? argv0 : __progname; 350 351 if (!force && level > log_level) 352 return; 353 354 switch (level) { 355 case SYSLOG_LEVEL_FATAL: 356 if (!log_on_stderr) 357 txt = "fatal"; 358 pri = LOG_CRIT; 359 break; 360 case SYSLOG_LEVEL_ERROR: 361 if (!log_on_stderr) 362 txt = "error"; 363 pri = LOG_ERR; 364 break; 365 case SYSLOG_LEVEL_INFO: 366 pri = LOG_INFO; 367 break; 368 case SYSLOG_LEVEL_VERBOSE: 369 pri = LOG_INFO; 370 break; 371 case SYSLOG_LEVEL_DEBUG1: 372 txt = "debug1"; 373 pri = LOG_DEBUG; 374 break; 375 case SYSLOG_LEVEL_DEBUG2: 376 txt = "debug2"; 377 pri = LOG_DEBUG; 378 break; 379 case SYSLOG_LEVEL_DEBUG3: 380 txt = "debug3"; 381 pri = LOG_DEBUG; 382 break; 383 default: 384 txt = "internal error"; 385 pri = LOG_ERR; 386 break; 387 } 388 if (txt != NULL && log_handler == NULL) { 389 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 390 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 391 } else { 392 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 393 } 394 if (suffix != NULL) { 395 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", msgbuf, suffix); 396 strlcpy(msgbuf, fmtbuf, sizeof(msgbuf)); 397 } 398 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), 399 log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); 400 if (log_handler != NULL) { 401 /* Avoid recursion */ 402 tmp_handler = log_handler; 403 log_handler = NULL; 404 tmp_handler(level, force, fmtbuf, log_handler_ctx); 405 log_handler = tmp_handler; 406 } else if (log_on_stderr) { 407 snprintf(msgbuf, sizeof msgbuf, "%s%s%.*s\r\n", 408 (log_on_stderr > 1) ? progname : "", 409 (log_on_stderr > 1) ? ": " : "", 410 (int)sizeof msgbuf - 3, fmtbuf); 411 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 412 } else { 413#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 414 openlog_r(progname, LOG_PID, log_facility, &sdata); 415 syslog_r(pri, &sdata, "%.500s", fmtbuf); 416 closelog_r(&sdata); 417#else 418 openlog(progname, LOG_PID, log_facility); 419 syslog(pri, "%.500s", fmtbuf); 420 closelog(); 421#endif 422 } 423 errno = saved_errno; 424} 425 426void 427sshlog(const char *file, const char *func, int line, int showfunc, 428 LogLevel level, const char *suffix, const char *fmt, ...) 429{ 430 va_list args; 431 432 va_start(args, fmt); 433 sshlogv(file, func, line, showfunc, level, suffix, fmt, args); 434 va_end(args); 435} 436 437void 438sshlogdie(const char *file, const char *func, int line, int showfunc, 439 LogLevel level, const char *suffix, const char *fmt, ...) 440{ 441 va_list args; 442 443 va_start(args, fmt); 444 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO, 445 suffix, fmt, args); 446 va_end(args); 447 cleanup_exit(255); 448} 449 450void 451sshsigdie(const char *file, const char *func, int line, int showfunc, 452 LogLevel level, const char *suffix, const char *fmt, ...) 453{ 454 va_list args; 455 456 va_start(args, fmt); 457 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, 458 suffix, fmt, args); 459 va_end(args); 460 _exit(1); 461} 462 463void 464sshlogv(const char *file, const char *func, int line, int showfunc, 465 LogLevel level, const char *suffix, const char *fmt, va_list args) 466{ 467 char tag[128], fmt2[MSGBUFSIZ + 128]; 468 int forced = 0; 469 const char *cp; 470 size_t i; 471 472 /* short circuit processing early if we're not going to log anything */ 473 if (nlog_verbose == 0 && level > log_level) 474 return; 475 476 snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)", 477 (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, 478 (long)getpid()); 479 for (i = 0; i < nlog_verbose; i++) { 480 if (match_pattern_list(tag, log_verbose[i], 0) == 1) { 481 forced = 1; 482 break; 483 } 484 } 485 486 if (forced) 487 snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt); 488 else if (showfunc) 489 snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt); 490 else 491 strlcpy(fmt2, fmt, sizeof(fmt2)); 492 493 do_log(level, forced, suffix, fmt2, args); 494} 495 496void 497sshlogdirect(LogLevel level, int forced, const char *fmt, ...) 498{ 499 va_list args; 500 501 va_start(args, fmt); 502 do_log(level, forced, NULL, fmt, args); 503 va_end(args); 504} 505