1 /* $NetBSD: log.c,v 1.25 2021/09/27 17:03:13 christos Exp $ */ 2 /* $OpenBSD: log.c,v 1.60 2021/09/16 15:11:19 djm 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.25 2021/09/27 17:03:13 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 57 static LogLevel log_level = SYSLOG_LEVEL_INFO; 58 static int log_on_stderr = 1; 59 static int log_stderr_fd = STDERR_FILENO; 60 static int log_facility = LOG_AUTH; 61 static const char *argv0; 62 static log_handler_fn *log_handler; 63 static void *log_handler_ctx; 64 static char **log_verbose; 65 static size_t nlog_verbose; 66 extern char *__progname; 67 68 /* textual representation of log-facilities/levels */ 69 70 static 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 88 static 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 105 LogLevel 106 log_level_get(void) 107 { 108 return log_level; 109 } 110 111 SyslogFacility 112 log_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 123 const char * 124 log_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 134 LogLevel 135 log_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 146 const char * 147 log_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 157 void 158 log_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 171 void 172 log_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 187 void 188 log_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 248 int 249 log_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 271 int 272 log_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 */ 278 void 279 log_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 301 void 302 set_log_handler(log_handler_fn *handler, void *ctx) 303 { 304 log_handler = handler; 305 log_handler_ctx = ctx; 306 } 307 308 static void 309 do_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 const char *progname = argv0 != NULL ? argv0 : __progname; 323 324 if (!force && level > log_level) 325 return; 326 327 switch (level) { 328 case SYSLOG_LEVEL_FATAL: 329 if (!log_on_stderr) 330 txt = "fatal"; 331 pri = LOG_CRIT; 332 break; 333 case SYSLOG_LEVEL_ERROR: 334 if (!log_on_stderr) 335 txt = "error"; 336 pri = LOG_ERR; 337 break; 338 case SYSLOG_LEVEL_INFO: 339 pri = LOG_INFO; 340 break; 341 case SYSLOG_LEVEL_VERBOSE: 342 pri = LOG_INFO; 343 break; 344 case SYSLOG_LEVEL_DEBUG1: 345 txt = "debug1"; 346 pri = LOG_DEBUG; 347 break; 348 case SYSLOG_LEVEL_DEBUG2: 349 txt = "debug2"; 350 pri = LOG_DEBUG; 351 break; 352 case SYSLOG_LEVEL_DEBUG3: 353 txt = "debug3"; 354 pri = LOG_DEBUG; 355 break; 356 default: 357 txt = "internal error"; 358 pri = LOG_ERR; 359 break; 360 } 361 len = sizeof(msgbuf); 362 msgbufp = msgbuf; 363 if (txt != NULL && log_handler == NULL) { 364 len2 = strlen(txt); 365 if (len2 > len - 2) 366 len2 = len - 2; 367 memcpy(msgbufp, txt, len2); 368 msgbufp += len2; 369 *msgbufp++ = ':'; 370 *msgbufp++ = ' '; 371 len -= len2 + 2; 372 } 373 vsnprintf(msgbufp, len, fmt, args); 374 if (suffix != NULL) { 375 snprintf(visbuf, sizeof(visbuf), "%s: %s", msgbuf, suffix); 376 strlcpy(msgbuf, visbuf, sizeof(msgbuf)); 377 } 378 strnvis(visbuf, sizeof(visbuf), msgbuf, VIS_SAFE|VIS_OCTAL); 379 if (log_handler != NULL) { 380 /* Avoid recursion */ 381 tmp_handler = log_handler; 382 log_handler = NULL; 383 tmp_handler(level, force, visbuf, log_handler_ctx); 384 log_handler = tmp_handler; 385 } else if (log_on_stderr) { 386 snprintf(msgbuf, sizeof msgbuf, "%s%s%.*s\r\n", 387 (log_on_stderr > 1) ? progname : "", 388 (log_on_stderr > 1) ? ": " : "", 389 (int)sizeof msgbuf - 10, visbuf); 390 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 391 } else { 392 #ifdef SYSLOG_DATA_INIT 393 openlog_r(progname, LOG_PID, log_facility, &sdata); 394 syslog_r(pri, &sdata, "%.500s", visbuf); 395 closelog_r(&sdata); 396 #else 397 openlog(progname, LOG_PID, log_facility); 398 syslog(pri, "%.500s", visbuf); 399 closelog(); 400 #endif 401 } 402 errno = saved_errno; 403 } 404 405 void 406 sshlog(const char *file, const char *func, int line, int showfunc, 407 LogLevel level, const char *suffix, const char *fmt, ...) 408 { 409 va_list args; 410 411 va_start(args, fmt); 412 sshlogv(file, func, line, showfunc, level, suffix, fmt, args); 413 va_end(args); 414 } 415 416 void 417 sshlogdie(const char *file, const char *func, int line, int showfunc, 418 LogLevel level, const char *suffix, const char *fmt, ...) 419 { 420 va_list args; 421 422 va_start(args, fmt); 423 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_INFO, 424 suffix, fmt, args); 425 va_end(args); 426 cleanup_exit(255); 427 } 428 429 void 430 sshsigdie(const char *file, const char *func, int line, int showfunc, 431 LogLevel level, const char *suffix, const char *fmt, ...) 432 { 433 va_list args; 434 435 va_start(args, fmt); 436 sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, 437 suffix, fmt, args); 438 va_end(args); 439 _exit(1); 440 } 441 442 void 443 sshlogv(const char *file, const char *func, int line, int showfunc, 444 LogLevel level, const char *suffix, const char *fmt, va_list args) 445 { 446 char tag[128], fmt2[MSGBUFSIZ + 128]; 447 int forced = 0; 448 const char *cp; 449 size_t i; 450 451 snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)", 452 (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, 453 (long)getpid()); 454 for (i = 0; i < nlog_verbose; i++) { 455 if (match_pattern_list(tag, log_verbose[i], 0) == 1) { 456 forced = 1; 457 break; 458 } 459 } 460 461 if (forced) 462 snprintf(fmt2, sizeof(fmt2), "%s: %s", tag, fmt); 463 else if (showfunc) 464 snprintf(fmt2, sizeof(fmt2), "%s: %s", func, fmt); 465 else 466 strlcpy(fmt2, fmt, sizeof(fmt2)); 467 468 do_log(level, forced, suffix, fmt2, args); 469 } 470 471 void 472 sshlogdirect(LogLevel level, int forced, const char *fmt, ...) 473 { 474 va_list args; 475 476 va_start(args, fmt); 477 do_log(level, forced, NULL, fmt, args); 478 va_end(args); 479 } 480