1 /* $OpenBSD: log.c,v 1.59 2021/05/07 04:11:51 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 350 if (!force && level > log_level) 351 return; 352 353 switch (level) { 354 case SYSLOG_LEVEL_FATAL: 355 if (!log_on_stderr) 356 txt = "fatal"; 357 pri = LOG_CRIT; 358 break; 359 case SYSLOG_LEVEL_ERROR: 360 if (!log_on_stderr) 361 txt = "error"; 362 pri = LOG_ERR; 363 break; 364 case SYSLOG_LEVEL_INFO: 365 pri = LOG_INFO; 366 break; 367 case SYSLOG_LEVEL_VERBOSE: 368 pri = LOG_INFO; 369 break; 370 case SYSLOG_LEVEL_DEBUG1: 371 txt = "debug1"; 372 pri = LOG_DEBUG; 373 break; 374 case SYSLOG_LEVEL_DEBUG2: 375 txt = "debug2"; 376 pri = LOG_DEBUG; 377 break; 378 case SYSLOG_LEVEL_DEBUG3: 379 txt = "debug3"; 380 pri = LOG_DEBUG; 381 break; 382 default: 383 txt = "internal error"; 384 pri = LOG_ERR; 385 break; 386 } 387 if (txt != NULL && log_handler == NULL) { 388 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 389 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 390 } else { 391 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 392 } 393 if (suffix != NULL) { 394 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", msgbuf, suffix); 395 strlcpy(msgbuf, fmtbuf, sizeof(msgbuf)); 396 } 397 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), 398 log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); 399 if (log_handler != NULL) { 400 /* Avoid recursion */ 401 tmp_handler = log_handler; 402 log_handler = NULL; 403 tmp_handler(level, force, fmtbuf, log_handler_ctx); 404 log_handler = tmp_handler; 405 } else if (log_on_stderr) { 406 snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", 407 (int)sizeof msgbuf - 3, fmtbuf); 408 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 409 } else { 410 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 411 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 412 syslog_r(pri, &sdata, "%.500s", fmtbuf); 413 closelog_r(&sdata); 414 #else 415 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 416 syslog(pri, "%.500s", fmtbuf); 417 closelog(); 418 #endif 419 } 420 errno = saved_errno; 421 } 422 423 void 424 sshlog(const char *file, const char *func, int line, int showfunc, 425 LogLevel level, const char *suffix, const char *fmt, ...) 426 { 427 va_list args; 428 429 va_start(args, fmt); 430 sshlogv(file, func, line, showfunc, level, suffix, fmt, args); 431 va_end(args); 432 } 433 434 void 435 sshlogdie(const char *file, const char *func, int line, int showfunc, 436 LogLevel level, const char *suffix, const char *fmt, ...) 437 { 438 va_list args; 439 440 va_start(args, fmt); 441 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO, 442 suffix, fmt, args); 443 va_end(args); 444 cleanup_exit(255); 445 } 446 447 void 448 sshsigdie(const char *file, const char *func, int line, int showfunc, 449 LogLevel level, const char *suffix, const char *fmt, ...) 450 { 451 va_list args; 452 453 va_start(args, fmt); 454 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, 455 suffix, fmt, args); 456 va_end(args); 457 _exit(1); 458 } 459 460 void 461 sshlogv(const char *file, const char *func, int line, int showfunc, 462 LogLevel level, const char *suffix, const char *fmt, va_list args) 463 { 464 char tag[128], fmt2[MSGBUFSIZ + 128]; 465 int forced = 0; 466 const char *cp; 467 size_t i; 468 469 snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)", 470 (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, 471 (long)getpid()); 472 for (i = 0; i < nlog_verbose; i++) { 473 if (match_pattern_list(tag, log_verbose[i], 0) == 1) { 474 forced = 1; 475 break; 476 } 477 } 478 479 if (forced) 480 snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt); 481 else if (showfunc) 482 snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt); 483 else 484 strlcpy(fmt2, fmt, sizeof(fmt2)); 485 486 do_log(level, forced, suffix, fmt2, args); 487 } 488 489 void 490 sshlogdirect(LogLevel level, int forced, const char *fmt, ...) 491 { 492 va_list args; 493 494 va_start(args, fmt); 495 do_log(level, forced, NULL, fmt, args); 496 va_end(args); 497 } 498