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 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 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 402 void 403 sshlog(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 413 void 414 sshlogdie(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 426 void 427 sshsigdie(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 439 void 440 sshlogv(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 467 void 468 sshlogdirect(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