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