1 /* $OpenBSD: log.c,v 1.52 2020/07/03 06:46:41 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 <sys/types.h> 38 39 #include <fcntl.h> 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <syslog.h> 45 #include <unistd.h> 46 #include <errno.h> 47 #include <vis.h> 48 49 #include "log.h" 50 51 static LogLevel log_level = SYSLOG_LEVEL_INFO; 52 static int log_on_stderr = 1; 53 static int log_stderr_fd = STDERR_FILENO; 54 static int log_facility = LOG_AUTH; 55 static char *argv0; 56 static log_handler_fn *log_handler; 57 static void *log_handler_ctx; 58 59 extern char *__progname; 60 61 /* textual representation of log-facilities/levels */ 62 63 static struct { 64 const char *name; 65 SyslogFacility val; 66 } log_facilities[] = { 67 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 68 { "USER", SYSLOG_FACILITY_USER }, 69 { "AUTH", SYSLOG_FACILITY_AUTH }, 70 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 71 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 72 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 73 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 74 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 75 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 76 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 77 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 78 { NULL, SYSLOG_FACILITY_NOT_SET } 79 }; 80 81 static struct { 82 const char *name; 83 LogLevel val; 84 } log_levels[] = 85 { 86 { "QUIET", SYSLOG_LEVEL_QUIET }, 87 { "FATAL", SYSLOG_LEVEL_FATAL }, 88 { "ERROR", SYSLOG_LEVEL_ERROR }, 89 { "INFO", SYSLOG_LEVEL_INFO }, 90 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 91 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 92 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 93 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 94 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 95 { NULL, SYSLOG_LEVEL_NOT_SET } 96 }; 97 98 LogLevel 99 log_level_get(void) 100 { 101 return log_level; 102 } 103 104 SyslogFacility 105 log_facility_number(char *name) 106 { 107 int i; 108 109 if (name != NULL) 110 for (i = 0; log_facilities[i].name; i++) 111 if (strcasecmp(log_facilities[i].name, name) == 0) 112 return log_facilities[i].val; 113 return SYSLOG_FACILITY_NOT_SET; 114 } 115 116 const char * 117 log_facility_name(SyslogFacility facility) 118 { 119 u_int i; 120 121 for (i = 0; log_facilities[i].name; i++) 122 if (log_facilities[i].val == facility) 123 return log_facilities[i].name; 124 return NULL; 125 } 126 127 LogLevel 128 log_level_number(char *name) 129 { 130 int i; 131 132 if (name != NULL) 133 for (i = 0; log_levels[i].name; i++) 134 if (strcasecmp(log_levels[i].name, name) == 0) 135 return log_levels[i].val; 136 return SYSLOG_LEVEL_NOT_SET; 137 } 138 139 const char * 140 log_level_name(LogLevel level) 141 { 142 u_int i; 143 144 for (i = 0; log_levels[i].name != NULL; i++) 145 if (log_levels[i].val == level) 146 return log_levels[i].name; 147 return NULL; 148 } 149 150 /* Error messages that should be logged. */ 151 152 void 153 error(const char *fmt,...) 154 { 155 va_list args; 156 157 va_start(args, fmt); 158 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 159 va_end(args); 160 } 161 162 void 163 sigdie(const char *fmt,...) 164 { 165 va_list args; 166 167 va_start(args, fmt); 168 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 169 va_end(args); 170 _exit(1); 171 } 172 173 void 174 logdie(const char *fmt,...) 175 { 176 va_list args; 177 178 va_start(args, fmt); 179 do_log(SYSLOG_LEVEL_INFO, fmt, args); 180 va_end(args); 181 cleanup_exit(255); 182 } 183 184 /* Log this message (information that usually should go to the log). */ 185 186 void 187 logit(const char *fmt,...) 188 { 189 va_list args; 190 191 va_start(args, fmt); 192 do_log(SYSLOG_LEVEL_INFO, fmt, args); 193 va_end(args); 194 } 195 196 /* More detailed messages (information that does not need to go to the log). */ 197 198 void 199 verbose(const char *fmt,...) 200 { 201 va_list args; 202 203 va_start(args, fmt); 204 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 205 va_end(args); 206 } 207 208 /* Debugging messages that should not be logged during normal operation. */ 209 210 void 211 debug(const char *fmt,...) 212 { 213 va_list args; 214 215 va_start(args, fmt); 216 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 217 va_end(args); 218 } 219 220 void 221 debug2(const char *fmt,...) 222 { 223 va_list args; 224 225 va_start(args, fmt); 226 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 227 va_end(args); 228 } 229 230 void 231 debug3(const char *fmt,...) 232 { 233 va_list args; 234 235 va_start(args, fmt); 236 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 237 va_end(args); 238 } 239 240 /* 241 * Initialize the log. 242 */ 243 244 void 245 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 246 { 247 argv0 = av0; 248 249 if (log_change_level(level) != 0) { 250 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 251 (int) level); 252 exit(1); 253 } 254 255 log_handler = NULL; 256 log_handler_ctx = NULL; 257 258 log_on_stderr = on_stderr; 259 if (on_stderr) 260 return; 261 262 switch (facility) { 263 case SYSLOG_FACILITY_DAEMON: 264 log_facility = LOG_DAEMON; 265 break; 266 case SYSLOG_FACILITY_USER: 267 log_facility = LOG_USER; 268 break; 269 case SYSLOG_FACILITY_AUTH: 270 log_facility = LOG_AUTH; 271 break; 272 case SYSLOG_FACILITY_LOCAL0: 273 log_facility = LOG_LOCAL0; 274 break; 275 case SYSLOG_FACILITY_LOCAL1: 276 log_facility = LOG_LOCAL1; 277 break; 278 case SYSLOG_FACILITY_LOCAL2: 279 log_facility = LOG_LOCAL2; 280 break; 281 case SYSLOG_FACILITY_LOCAL3: 282 log_facility = LOG_LOCAL3; 283 break; 284 case SYSLOG_FACILITY_LOCAL4: 285 log_facility = LOG_LOCAL4; 286 break; 287 case SYSLOG_FACILITY_LOCAL5: 288 log_facility = LOG_LOCAL5; 289 break; 290 case SYSLOG_FACILITY_LOCAL6: 291 log_facility = LOG_LOCAL6; 292 break; 293 case SYSLOG_FACILITY_LOCAL7: 294 log_facility = LOG_LOCAL7; 295 break; 296 default: 297 fprintf(stderr, 298 "Unrecognized internal syslog facility code %d\n", 299 (int) facility); 300 exit(1); 301 } 302 } 303 304 int 305 log_change_level(LogLevel new_log_level) 306 { 307 /* no-op if log_init has not been called */ 308 if (argv0 == NULL) 309 return 0; 310 311 switch (new_log_level) { 312 case SYSLOG_LEVEL_QUIET: 313 case SYSLOG_LEVEL_FATAL: 314 case SYSLOG_LEVEL_ERROR: 315 case SYSLOG_LEVEL_INFO: 316 case SYSLOG_LEVEL_VERBOSE: 317 case SYSLOG_LEVEL_DEBUG1: 318 case SYSLOG_LEVEL_DEBUG2: 319 case SYSLOG_LEVEL_DEBUG3: 320 log_level = new_log_level; 321 return 0; 322 default: 323 return -1; 324 } 325 } 326 327 int 328 log_is_on_stderr(void) 329 { 330 return log_on_stderr && log_stderr_fd == STDERR_FILENO; 331 } 332 333 /* redirect what would usually get written to stderr to specified file */ 334 void 335 log_redirect_stderr_to(const char *logfile) 336 { 337 int fd; 338 339 if (logfile == NULL) { 340 if (log_stderr_fd != STDERR_FILENO) { 341 close(log_stderr_fd); 342 log_stderr_fd = STDERR_FILENO; 343 } 344 return; 345 } 346 347 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 348 fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 349 strerror(errno)); 350 exit(1); 351 } 352 log_stderr_fd = fd; 353 } 354 355 #define MSGBUFSIZ 1024 356 357 void 358 set_log_handler(log_handler_fn *handler, void *ctx) 359 { 360 log_handler = handler; 361 log_handler_ctx = ctx; 362 } 363 364 void 365 do_log2(LogLevel level, const char *fmt,...) 366 { 367 va_list args; 368 369 va_start(args, fmt); 370 do_log(level, fmt, args); 371 va_end(args); 372 } 373 374 void 375 do_log(LogLevel level, const char *fmt, va_list args) 376 { 377 struct syslog_data sdata = SYSLOG_DATA_INIT; 378 char msgbuf[MSGBUFSIZ]; 379 char fmtbuf[MSGBUFSIZ]; 380 char *txt = NULL; 381 int pri = LOG_INFO; 382 int saved_errno = errno; 383 log_handler_fn *tmp_handler; 384 385 if (level > log_level) 386 return; 387 388 switch (level) { 389 case SYSLOG_LEVEL_FATAL: 390 if (!log_on_stderr) 391 txt = "fatal"; 392 pri = LOG_CRIT; 393 break; 394 case SYSLOG_LEVEL_ERROR: 395 if (!log_on_stderr) 396 txt = "error"; 397 pri = LOG_ERR; 398 break; 399 case SYSLOG_LEVEL_INFO: 400 pri = LOG_INFO; 401 break; 402 case SYSLOG_LEVEL_VERBOSE: 403 pri = LOG_INFO; 404 break; 405 case SYSLOG_LEVEL_DEBUG1: 406 txt = "debug1"; 407 pri = LOG_DEBUG; 408 break; 409 case SYSLOG_LEVEL_DEBUG2: 410 txt = "debug2"; 411 pri = LOG_DEBUG; 412 break; 413 case SYSLOG_LEVEL_DEBUG3: 414 txt = "debug3"; 415 pri = LOG_DEBUG; 416 break; 417 default: 418 txt = "internal error"; 419 pri = LOG_ERR; 420 break; 421 } 422 if (txt != NULL && log_handler == NULL) { 423 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 424 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 425 } else { 426 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 427 } 428 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL); 429 if (log_handler != NULL) { 430 /* Avoid recursion */ 431 tmp_handler = log_handler; 432 log_handler = NULL; 433 tmp_handler(level, fmtbuf, log_handler_ctx); 434 log_handler = tmp_handler; 435 } else if (log_on_stderr) { 436 snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", 437 (int)sizeof msgbuf - 3, fmtbuf); 438 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 439 } else { 440 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 441 syslog_r(pri, &sdata, "%.500s", fmtbuf); 442 closelog_r(&sdata); 443 } 444 errno = saved_errno; 445 } 446