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 56 static LogLevel log_level = SYSLOG_LEVEL_INFO; 57 static int log_on_stderr = 1; 58 static int log_stderr_fd = STDERR_FILENO; 59 static int log_facility = LOG_AUTH; 60 static const char *argv0; 61 static log_handler_fn *log_handler; 62 static void *log_handler_ctx; 63 static char **log_verbose; 64 static size_t nlog_verbose; 65 66 extern 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 73 static 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 94 static 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 111 LogLevel 112 log_level_get(void) 113 { 114 return log_level; 115 } 116 117 SyslogFacility 118 log_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 129 const char * 130 log_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 140 LogLevel 141 log_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 152 const char * 153 log_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 163 void 164 log_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 177 void 178 log_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 193 void 194 log_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 276 int 277 log_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 299 int 300 log_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 */ 306 void 307 log_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 329 void 330 set_log_handler(log_handler_fn *handler, void *ctx) 331 { 332 log_handler = handler; 333 log_handler_ctx = ctx; 334 } 335 336 static void 337 do_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 426 void 427 sshlog(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 437 void 438 sshlogdie(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 450 void 451 sshsigdie(const char *file, const char *func, int line, int showfunc, 452 LogLevel level, const char *suffix, const char *fmt, ...) 453 { 454 #if 0 455 va_list args; 456 457 va_start(args, fmt); 458 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, 459 suffix, fmt, args); 460 va_end(args); 461 #endif 462 _exit(1); 463 } 464 465 void 466 sshlogv(const char *file, const char *func, int line, int showfunc, 467 LogLevel level, const char *suffix, const char *fmt, va_list args) 468 { 469 char tag[128], fmt2[MSGBUFSIZ + 128]; 470 int forced = 0; 471 const char *cp; 472 size_t i; 473 474 /* short circuit processing early if we're not going to log anything */ 475 if (nlog_verbose == 0 && level > log_level) 476 return; 477 478 snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)", 479 (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, 480 (long)getpid()); 481 for (i = 0; i < nlog_verbose; i++) { 482 if (match_pattern_list(tag, log_verbose[i], 0) == 1) { 483 forced = 1; 484 break; 485 } 486 } 487 488 if (forced) 489 snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt); 490 else if (showfunc) 491 snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt); 492 else 493 strlcpy(fmt2, fmt, sizeof(fmt2)); 494 495 do_log(level, forced, suffix, fmt2, args); 496 } 497 498 void 499 sshlogdirect(LogLevel level, int forced, const char *fmt, ...) 500 { 501 va_list args; 502 503 va_start(args, fmt); 504 do_log(level, forced, NULL, fmt, args); 505 va_end(args); 506 } 507