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