jcs's openbsd hax
openbsd
at jcs 615 lines 16 kB view raw
1/* $OpenBSD: log.c,v 1.67 2026/02/14 00:18:34 jsg 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 <sys/types.h> 38 39#include <errno.h> 40#include <fcntl.h> 41#include <limits.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 <vis.h> 49 50#include "log.h" 51#include "match.h" 52 53static LogLevel log_level = SYSLOG_LEVEL_INFO; 54static int log_on_stderr = 1; 55static int log_stderr_fd = STDERR_FILENO; 56static int log_facility = LOG_AUTH; 57static const char *argv0; 58static log_handler_fn *log_handler; 59static void *log_handler_ctx; 60static char **log_verbose; 61static size_t nlog_verbose; 62extern char *__progname; 63 64/* textual representation of log-facilities/levels */ 65 66static struct { 67 const char *name; 68 SyslogFacility val; 69} log_facilities[] = { 70 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 71 { "USER", SYSLOG_FACILITY_USER }, 72 { "AUTH", SYSLOG_FACILITY_AUTH }, 73 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 74 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 75 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 76 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 77 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 78 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 79 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 80 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 81 { NULL, SYSLOG_FACILITY_NOT_SET } 82}; 83 84static struct { 85 const char *name; 86 LogLevel val; 87} log_levels[] = 88{ 89 { "QUIET", SYSLOG_LEVEL_QUIET }, 90 { "FATAL", SYSLOG_LEVEL_FATAL }, 91 { "ERROR", SYSLOG_LEVEL_ERROR }, 92 { "INFO", SYSLOG_LEVEL_INFO }, 93 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 94 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 95 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 96 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 97 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 98 { NULL, SYSLOG_LEVEL_NOT_SET } 99}; 100 101LogLevel 102log_level_get(void) 103{ 104 return log_level; 105} 106 107SyslogFacility 108log_facility_number(char *name) 109{ 110 int i; 111 112 if (name != NULL) 113 for (i = 0; log_facilities[i].name; i++) 114 if (strcasecmp(log_facilities[i].name, name) == 0) 115 return log_facilities[i].val; 116 return SYSLOG_FACILITY_NOT_SET; 117} 118 119const char * 120log_facility_name(SyslogFacility facility) 121{ 122 u_int i; 123 124 for (i = 0; log_facilities[i].name; i++) 125 if (log_facilities[i].val == facility) 126 return log_facilities[i].name; 127 return NULL; 128} 129 130LogLevel 131log_level_number(char *name) 132{ 133 int i; 134 135 if (name != NULL) 136 for (i = 0; log_levels[i].name; i++) 137 if (strcasecmp(log_levels[i].name, name) == 0) 138 return log_levels[i].val; 139 return SYSLOG_LEVEL_NOT_SET; 140} 141 142const char * 143log_level_name(LogLevel level) 144{ 145 u_int i; 146 147 for (i = 0; log_levels[i].name != NULL; i++) 148 if (log_levels[i].val == level) 149 return log_levels[i].name; 150 return NULL; 151} 152 153void 154log_verbose_add(const char *s) 155{ 156 char **tmp; 157 158 /* Ignore failures here */ 159 if ((tmp = recallocarray(log_verbose, nlog_verbose, nlog_verbose + 1, 160 sizeof(*log_verbose))) != NULL) { 161 log_verbose = tmp; 162 if ((log_verbose[nlog_verbose] = strdup(s)) != NULL) 163 nlog_verbose++; 164 } 165} 166 167void 168log_verbose_reset(void) 169{ 170 size_t i; 171 172 for (i = 0; i < nlog_verbose; i++) 173 free(log_verbose[i]); 174 free(log_verbose); 175 log_verbose = NULL; 176 nlog_verbose = 0; 177} 178 179/* 180 * Initialize the log. 181 */ 182 183void 184log_init(const char *av0, LogLevel level, SyslogFacility facility, 185 int on_stderr) 186{ 187 argv0 = av0; 188 189 if (log_change_level(level) != 0) { 190 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 191 (int) level); 192 exit(1); 193 } 194 195 log_handler = NULL; 196 log_handler_ctx = NULL; 197 198 log_on_stderr = on_stderr; 199 if (on_stderr) 200 return; 201 202 switch (facility) { 203 case SYSLOG_FACILITY_DAEMON: 204 log_facility = LOG_DAEMON; 205 break; 206 case SYSLOG_FACILITY_USER: 207 log_facility = LOG_USER; 208 break; 209 case SYSLOG_FACILITY_AUTH: 210 log_facility = LOG_AUTH; 211 break; 212 case SYSLOG_FACILITY_LOCAL0: 213 log_facility = LOG_LOCAL0; 214 break; 215 case SYSLOG_FACILITY_LOCAL1: 216 log_facility = LOG_LOCAL1; 217 break; 218 case SYSLOG_FACILITY_LOCAL2: 219 log_facility = LOG_LOCAL2; 220 break; 221 case SYSLOG_FACILITY_LOCAL3: 222 log_facility = LOG_LOCAL3; 223 break; 224 case SYSLOG_FACILITY_LOCAL4: 225 log_facility = LOG_LOCAL4; 226 break; 227 case SYSLOG_FACILITY_LOCAL5: 228 log_facility = LOG_LOCAL5; 229 break; 230 case SYSLOG_FACILITY_LOCAL6: 231 log_facility = LOG_LOCAL6; 232 break; 233 case SYSLOG_FACILITY_LOCAL7: 234 log_facility = LOG_LOCAL7; 235 break; 236 default: 237 fprintf(stderr, 238 "Unrecognized internal syslog facility code %d\n", 239 (int) facility); 240 exit(1); 241 } 242} 243 244int 245log_change_level(LogLevel new_log_level) 246{ 247 /* no-op if log_init has not been called */ 248 if (argv0 == NULL) 249 return 0; 250 251 switch (new_log_level) { 252 case SYSLOG_LEVEL_QUIET: 253 case SYSLOG_LEVEL_FATAL: 254 case SYSLOG_LEVEL_ERROR: 255 case SYSLOG_LEVEL_INFO: 256 case SYSLOG_LEVEL_VERBOSE: 257 case SYSLOG_LEVEL_DEBUG1: 258 case SYSLOG_LEVEL_DEBUG2: 259 case SYSLOG_LEVEL_DEBUG3: 260 log_level = new_log_level; 261 return 0; 262 default: 263 return -1; 264 } 265} 266 267int 268log_is_on_stderr(void) 269{ 270 return log_on_stderr && log_stderr_fd == STDERR_FILENO; 271} 272 273/* redirect what would usually get written to stderr to specified file */ 274void 275log_redirect_stderr_to(const char *logfile) 276{ 277 int fd; 278 279 if (logfile == NULL) { 280 if (log_stderr_fd != STDERR_FILENO) { 281 close(log_stderr_fd); 282 log_stderr_fd = STDERR_FILENO; 283 } 284 return; 285 } 286 287 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 288 fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 289 strerror(errno)); 290 exit(1); 291 } 292 log_stderr_fd = fd; 293} 294 295#define MSGBUFSIZ 1024 296 297void 298set_log_handler(log_handler_fn *handler, void *ctx) 299{ 300 log_handler = handler; 301 log_handler_ctx = ctx; 302} 303 304static void 305do_log(LogLevel level, int force, const char *suffix, const char *fmt, 306 va_list args) 307{ 308 struct syslog_data sdata = SYSLOG_DATA_INIT; 309 char msgbuf[MSGBUFSIZ]; 310 char fmtbuf[MSGBUFSIZ]; 311 char *txt = NULL; 312 int pri = LOG_INFO; 313 int saved_errno = errno; 314 log_handler_fn *tmp_handler; 315 const char *progname = argv0 != NULL ? argv0 : __progname; 316 317 if (!force && level > log_level) 318 return; 319 320 switch (level) { 321 case SYSLOG_LEVEL_FATAL: 322 if (!log_on_stderr) 323 txt = "fatal"; 324 pri = LOG_CRIT; 325 break; 326 case SYSLOG_LEVEL_ERROR: 327 if (!log_on_stderr) 328 txt = "error"; 329 pri = LOG_ERR; 330 break; 331 case SYSLOG_LEVEL_INFO: 332 pri = LOG_INFO; 333 break; 334 case SYSLOG_LEVEL_VERBOSE: 335 pri = LOG_INFO; 336 break; 337 case SYSLOG_LEVEL_DEBUG1: 338 txt = "debug1"; 339 pri = LOG_DEBUG; 340 break; 341 case SYSLOG_LEVEL_DEBUG2: 342 txt = "debug2"; 343 pri = LOG_DEBUG; 344 break; 345 case SYSLOG_LEVEL_DEBUG3: 346 txt = "debug3"; 347 pri = LOG_DEBUG; 348 break; 349 default: 350 txt = "internal error"; 351 pri = LOG_ERR; 352 break; 353 } 354 if (txt != NULL && log_handler == NULL) { 355 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 356 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 357 } else { 358 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 359 } 360 if (suffix != NULL) { 361 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", msgbuf, suffix); 362 strlcpy(msgbuf, fmtbuf, sizeof(msgbuf)); 363 } 364 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL); 365 if (log_handler != NULL) { 366 /* Avoid recursion */ 367 tmp_handler = log_handler; 368 log_handler = NULL; 369 /* Note: this sends the raw (i.e. no strnvis) log message */ 370 tmp_handler(level, force, msgbuf, log_handler_ctx); 371 log_handler = tmp_handler; 372 } else if (log_on_stderr) { 373 snprintf(msgbuf, sizeof msgbuf, "%s%s%.*s\r\n", 374 (log_on_stderr > 1) ? progname : "", 375 (log_on_stderr > 1) ? ": " : "", 376 (int)sizeof msgbuf - 3, fmtbuf); 377 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 378 } else { 379 openlog_r(progname, LOG_PID, log_facility, &sdata); 380 syslog_r(pri, &sdata, "%.500s", fmtbuf); 381 closelog_r(&sdata); 382 } 383 errno = saved_errno; 384} 385 386void 387sshlog(const char *file, const char *func, int line, int showfunc, 388 LogLevel level, const char *suffix, const char *fmt, ...) 389{ 390 va_list args; 391 392 va_start(args, fmt); 393 sshlogv(file, func, line, showfunc, level, suffix, fmt, args); 394 va_end(args); 395} 396 397void 398sshlogdie(const char *file, const char *func, int line, int showfunc, 399 LogLevel level, const char *suffix, const char *fmt, ...) 400{ 401 va_list args; 402 403 va_start(args, fmt); 404 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO, 405 suffix, fmt, args); 406 va_end(args); 407 cleanup_exit(255); 408} 409 410void 411sshlogv(const char *file, const char *func, int line, int showfunc, 412 LogLevel level, const char *suffix, const char *fmt, va_list args) 413{ 414 char tag[128], fmt2[MSGBUFSIZ + 128]; 415 int forced = 0; 416 const char *cp; 417 size_t i; 418 419 /* short circuit processing early if we're not going to log anything */ 420 if (nlog_verbose == 0 && level > log_level) 421 return; 422 423 snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (bin=%s, pid=%ld)", 424 (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, 425 argv0 == NULL ? "UNKNOWN" : argv0, (long)getpid()); 426 for (i = 0; i < nlog_verbose; i++) { 427 if (match_pattern_list(tag, log_verbose[i], 0) == 1) { 428 forced = 1; 429 break; 430 } 431 } 432 433 if (forced) 434 snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt); 435 else if (showfunc) 436 snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt); 437 else 438 strlcpy(fmt2, fmt, sizeof(fmt2)); 439 440 do_log(level, forced, suffix, fmt2, args); 441} 442 443void 444sshlogdirect(LogLevel level, int forced, const char *fmt, ...) 445{ 446 va_list args; 447 448 va_start(args, fmt); 449 do_log(level, forced, NULL, fmt, args); 450 va_end(args); 451} 452 453 454/* 455 * A simple system for ratelimiting aperiodic events such as logs, without 456 * needing to be hooked into a mainloop/timer. A running total of events is 457 * maintained and when it exceeds a threshold further events are dropped 458 * until the rate falls back below that threshold. 459 * 460 * To prevent flipping in and out of rate-limiting, there is a hysteresis 461 * timer that delays leaving the rate-limited state. 462 * 463 * While in the rate-limited state, events can be periodically allowed through 464 * and the number of dropped events since the last log obtained. 465 * 466 * XXX a moving average rate of events might be a better approach here rather 467 * than linear decay, which can suppress events for a while after large 468 * bursts. 469 */ 470 471/* #define RATELIMIT_DEBUG 1 */ 472 473#ifdef RATELIMIT_DEBUG 474# define RLDBG(x) do { \ 475 printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \ 476 printf x; \ 477 printf("\n"); \ 478 fflush(stdout); \ 479 } while (0) 480#else 481# define RLDBG(x) 482#endif 483 484/* set up a ratelimit */ 485void 486log_ratelimit_init(struct log_ratelimit_ctx *rl, u_int threshold, 487 u_int max_accum, u_int hysteresis, u_int log_every) 488{ 489 memset(rl, 0, sizeof(*rl)); 490 rl->threshold = threshold; 491 rl->max_accum = max_accum; 492 rl->hysteresis = hysteresis; 493 rl->log_every = log_every; 494 RLDBG(("called: rl=%p thresh=%u max=%u hys=%u log_every=%u", 495 rl, rl->threshold, rl->max_accum, rl->hysteresis, rl->log_every)); 496} 497 498/* 499 * check whether a log event should be dropped because of rate-limiting. 500 * returns non-zero if the event should be dropped. If events_since_last 501 * is supplied then, for periodic logs, it will be set to the number of 502 * dropped events since the last message. 503 */ 504int 505log_ratelimit(struct log_ratelimit_ctx *rl, time_t now, int *active, 506 u_int *events_dropped) 507{ 508 time_t olast_event; 509 510 RLDBG(("called: rl=%p thresh=%u max=%u hys=%u log_every=%u " 511 "accum=%u since=%ld since_last=%u", rl, rl->threshold, 512 rl->max_accum, rl->hysteresis, 513 rl->log_every, rl->accumulated_events, 514 rl->last_event == 0 ? -1 : (long)(now - rl->last_event), 515 rl->ratelimited_events)); 516 517 if (now < 0) 518 return 0; 519 if (events_dropped != NULL) 520 *events_dropped = 0; 521 if (active != NULL) 522 *active = rl->ratelimit_active; 523 524 /* First, decay accumulated events */ 525 if (rl->last_event <= 0) 526 rl->last_event = now; 527 if (now > rl->last_event) { 528 uint64_t n = now - rl->last_event; 529 530 if (n > UINT_MAX) 531 n = UINT_MAX; 532 if (rl->accumulated_events < (u_int)n) 533 rl->accumulated_events = 0; 534 else 535 rl->accumulated_events -= (u_int)n; 536 RLDBG(("decay: accum=%u", rl->accumulated_events)); 537 } 538 rl->accumulated_events++; /* add this event */ 539 if (rl->accumulated_events > rl->max_accum) 540 rl->accumulated_events = rl->max_accum; 541 olast_event = rl->last_event; 542 rl->last_event = now; 543 RLDBG(("check threshold: accum=%u vs thresh=%u", 544 rl->accumulated_events, rl->threshold)); 545 546 /* Are we under threshold? */ 547 if (rl->accumulated_events < rl->threshold) { 548 if (!rl->ratelimit_active) 549 return 0; 550 RLDBG(("under threshold: hys=%u since_hys=%ld since_last=%ld", 551 rl->hysteresis, rl->hysteresis_start == 0 ? -1 : 552 (long)(now - rl->hysteresis_start), 553 olast_event == 0 ? -1 : (long)(now - olast_event))); 554 if (rl->hysteresis_start == 0) { 555 /* active, but under threshold; hysteresis */ 556 if (olast_event + rl->hysteresis < now) { 557 /* hysteresis expired before this event */ 558 RLDBG(("hysteresis preexpired")); 559 goto inactive; 560 } 561 RLDBG(("start hysteresis")); 562 rl->hysteresis_start = now; 563 } else if (rl->hysteresis_start + rl->hysteresis < now) { 564 /* Hysteresis period expired, transition to inactive */ 565 RLDBG(("complete hysteresis")); 566 inactive: 567 if (events_dropped != NULL) 568 *events_dropped = rl->ratelimited_events; 569 if (active != NULL) 570 *active = 0; 571 rl->ratelimit_active = 0; 572 rl->ratelimit_start = 0; 573 rl->last_log = 0; 574 rl->hysteresis_start = 0; 575 rl->ratelimited_events = 0; 576 return 0; 577 } 578 /* ratelimiting active, but in hysteresis period */ 579 } else if (!rl->ratelimit_active) { 580 /* Transition to rate-limiting */ 581 RLDBG(("start ratelimit")); 582 rl->ratelimit_active = 1; 583 rl->ratelimit_start = now; 584 rl->last_log = now; 585 rl->hysteresis_start = 0; 586 rl->ratelimited_events = 1; 587 if (active != NULL) 588 *active = 1; 589 return 1; 590 } else if (rl->hysteresis_start != 0) { 591 /* active and over threshold; reset hysteresis timer */ 592 RLDBG(("clear hysteresis")); 593 rl->hysteresis_start = 0; 594 } 595 596 /* over threshold or in hysteresis period; log periodically */ 597 if (active != NULL) 598 *active = 1; 599 RLDBG(("log_every=%u since_log=%ld", rl->log_every, 600 (long)(now - rl->last_log))); 601 if (rl->log_every > 0 && now >= rl->last_log + rl->log_every) { 602 RLDBG(("periodic: since_last=%u", rl->ratelimited_events)); 603 rl->last_log = now; 604 if (events_dropped != NULL) { 605 *events_dropped = rl->ratelimited_events; 606 rl->ratelimited_events = 0; 607 } 608 return 0; 609 } 610 611 /* drop event */ 612 rl->ratelimited_events++; 613 RLDBG(("drop: ratelimited_events=%u", rl->ratelimited_events)); 614 return 1; 615}