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