1 /* $NetBSD: log.c,v 1.17 2017/10/07 19:39:19 christos Exp $ */ 2 /* $OpenBSD: log.c,v 1.50 2017/05/17 01:24:17 djm Exp $ */ 3 /* 4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 6 * All rights reserved 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 */ 14 /* 15 * Copyright (c) 2000 Markus Friedl. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include "includes.h" 39 __RCSID("$NetBSD: log.c,v 1.17 2017/10/07 19:39:19 christos Exp $"); 40 #include <sys/types.h> 41 #include <sys/uio.h> 42 43 #include <fcntl.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <syslog.h> 49 #include <unistd.h> 50 #include <errno.h> 51 #include <vis.h> 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 const char *argv0; 60 static log_handler_fn *log_handler; 61 static void *log_handler_ctx; 62 63 extern char *__progname; 64 65 /* textual representation of log-facilities/levels */ 66 67 static struct { 68 const char *name; 69 SyslogFacility val; 70 } log_facilities[] = { 71 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 72 { "USER", SYSLOG_FACILITY_USER }, 73 { "AUTH", SYSLOG_FACILITY_AUTH }, 74 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 75 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 76 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 77 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 78 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 79 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 80 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 81 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 82 { NULL, SYSLOG_FACILITY_NOT_SET } 83 }; 84 85 static struct { 86 const char *name; 87 LogLevel val; 88 } log_levels[] = 89 { 90 { "QUIET", SYSLOG_LEVEL_QUIET }, 91 { "FATAL", SYSLOG_LEVEL_FATAL }, 92 { "ERROR", SYSLOG_LEVEL_ERROR }, 93 { "INFO", SYSLOG_LEVEL_INFO }, 94 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 95 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 96 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 97 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 98 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 99 { NULL, SYSLOG_LEVEL_NOT_SET } 100 }; 101 102 SyslogFacility 103 log_facility_number(char *name) 104 { 105 int i; 106 107 if (name != NULL) 108 for (i = 0; log_facilities[i].name; i++) 109 if (strcasecmp(log_facilities[i].name, name) == 0) 110 return log_facilities[i].val; 111 return SYSLOG_FACILITY_NOT_SET; 112 } 113 114 const char * 115 log_facility_name(SyslogFacility facility) 116 { 117 u_int i; 118 119 for (i = 0; log_facilities[i].name; i++) 120 if (log_facilities[i].val == facility) 121 return log_facilities[i].name; 122 return NULL; 123 } 124 125 LogLevel 126 log_level_number(char *name) 127 { 128 int i; 129 130 if (name != NULL) 131 for (i = 0; log_levels[i].name; i++) 132 if (strcasecmp(log_levels[i].name, name) == 0) 133 return log_levels[i].val; 134 return SYSLOG_LEVEL_NOT_SET; 135 } 136 137 const char * 138 log_level_name(LogLevel level) 139 { 140 u_int i; 141 142 for (i = 0; log_levels[i].name != NULL; i++) 143 if (log_levels[i].val == level) 144 return log_levels[i].name; 145 return NULL; 146 } 147 148 /* Error messages that should be logged. */ 149 150 void 151 error(const char *fmt,...) 152 { 153 va_list args; 154 155 va_start(args, fmt); 156 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 157 va_end(args); 158 } 159 160 void 161 sigdie(const char *fmt,...) 162 { 163 va_list args; 164 165 va_start(args, fmt); 166 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 167 va_end(args); 168 _exit(1); 169 } 170 171 void 172 logdie(const char *fmt,...) 173 { 174 va_list args; 175 176 va_start(args, fmt); 177 do_log(SYSLOG_LEVEL_INFO, fmt, args); 178 va_end(args); 179 cleanup_exit(255); 180 } 181 182 /* Log this message (information that usually should go to the log). */ 183 184 void 185 logit(const char *fmt,...) 186 { 187 va_list args; 188 189 va_start(args, fmt); 190 do_log(SYSLOG_LEVEL_INFO, fmt, args); 191 va_end(args); 192 } 193 194 /* More detailed messages (information that does not need to go to the log). */ 195 196 void 197 verbose(const char *fmt,...) 198 { 199 va_list args; 200 201 va_start(args, fmt); 202 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 203 va_end(args); 204 } 205 206 /* Debugging messages that should not be logged during normal operation. */ 207 208 void 209 debug(const char *fmt,...) 210 { 211 va_list args; 212 213 va_start(args, fmt); 214 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 215 va_end(args); 216 } 217 218 void 219 debug2(const char *fmt,...) 220 { 221 va_list args; 222 223 va_start(args, fmt); 224 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 225 va_end(args); 226 } 227 228 void 229 debug3(const char *fmt,...) 230 { 231 va_list args; 232 233 va_start(args, fmt); 234 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 235 va_end(args); 236 } 237 238 /* 239 * Initialize the log. 240 */ 241 242 void 243 log_init(const char *av0, LogLevel level, SyslogFacility facility, 244 int on_stderr) 245 { 246 argv0 = av0; 247 248 if (log_change_level(level) != 0) { 249 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 250 (int) level); 251 exit(1); 252 } 253 254 log_handler = NULL; 255 log_handler_ctx = NULL; 256 257 log_on_stderr = on_stderr; 258 if (on_stderr) 259 return; 260 261 switch (facility) { 262 case SYSLOG_FACILITY_DAEMON: 263 log_facility = LOG_DAEMON; 264 break; 265 case SYSLOG_FACILITY_USER: 266 log_facility = LOG_USER; 267 break; 268 case SYSLOG_FACILITY_AUTH: 269 log_facility = LOG_AUTH; 270 break; 271 case SYSLOG_FACILITY_LOCAL0: 272 log_facility = LOG_LOCAL0; 273 break; 274 case SYSLOG_FACILITY_LOCAL1: 275 log_facility = LOG_LOCAL1; 276 break; 277 case SYSLOG_FACILITY_LOCAL2: 278 log_facility = LOG_LOCAL2; 279 break; 280 case SYSLOG_FACILITY_LOCAL3: 281 log_facility = LOG_LOCAL3; 282 break; 283 case SYSLOG_FACILITY_LOCAL4: 284 log_facility = LOG_LOCAL4; 285 break; 286 case SYSLOG_FACILITY_LOCAL5: 287 log_facility = LOG_LOCAL5; 288 break; 289 case SYSLOG_FACILITY_LOCAL6: 290 log_facility = LOG_LOCAL6; 291 break; 292 case SYSLOG_FACILITY_LOCAL7: 293 log_facility = LOG_LOCAL7; 294 break; 295 default: 296 fprintf(stderr, 297 "Unrecognized internal syslog facility code %d\n", 298 (int) facility); 299 exit(1); 300 } 301 } 302 303 int 304 log_change_level(LogLevel new_log_level) 305 { 306 /* no-op if log_init has not been called */ 307 if (argv0 == NULL) 308 return 0; 309 310 switch (new_log_level) { 311 case SYSLOG_LEVEL_QUIET: 312 case SYSLOG_LEVEL_FATAL: 313 case SYSLOG_LEVEL_ERROR: 314 case SYSLOG_LEVEL_INFO: 315 case SYSLOG_LEVEL_VERBOSE: 316 case SYSLOG_LEVEL_DEBUG1: 317 case SYSLOG_LEVEL_DEBUG2: 318 case SYSLOG_LEVEL_DEBUG3: 319 log_level = new_log_level; 320 return 0; 321 default: 322 return -1; 323 } 324 } 325 326 int 327 log_is_on_stderr(void) 328 { 329 return log_on_stderr && log_stderr_fd == STDERR_FILENO; 330 } 331 332 /* redirect what would usually get written to stderr to specified file */ 333 void 334 log_redirect_stderr_to(const char *logfile) 335 { 336 int fd; 337 338 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) { 339 fprintf(stderr, "Couldn't open logfile %s: %s\n", logfile, 340 strerror(errno)); 341 exit(1); 342 } 343 log_stderr_fd = fd; 344 } 345 346 #define MSGBUFSIZ 1024 347 348 void 349 set_log_handler(log_handler_fn *handler, void *ctx) 350 { 351 log_handler = handler; 352 log_handler_ctx = ctx; 353 } 354 355 void 356 do_log2(LogLevel level, const char *fmt,...) 357 { 358 va_list args; 359 360 va_start(args, fmt); 361 do_log(level, fmt, args); 362 va_end(args); 363 } 364 365 void 366 do_log(LogLevel level, const char *fmt, va_list args) 367 { 368 #ifdef SYSLOG_DATA_INIT 369 struct syslog_data sdata = SYSLOG_DATA_INIT; 370 #endif 371 char msgbuf[MSGBUFSIZ], *msgbufp; 372 char visbuf[MSGBUFSIZ * 4 + 1]; 373 size_t len, len2; 374 const char *txt = NULL; 375 int pri = LOG_INFO; 376 int saved_errno = errno; 377 log_handler_fn *tmp_handler; 378 379 if (level > log_level) 380 return; 381 382 switch (level) { 383 case SYSLOG_LEVEL_FATAL: 384 if (!log_on_stderr) 385 txt = "fatal"; 386 pri = LOG_CRIT; 387 break; 388 case SYSLOG_LEVEL_ERROR: 389 if (!log_on_stderr) 390 txt = "error"; 391 pri = LOG_ERR; 392 break; 393 case SYSLOG_LEVEL_INFO: 394 pri = LOG_INFO; 395 break; 396 case SYSLOG_LEVEL_VERBOSE: 397 pri = LOG_INFO; 398 break; 399 case SYSLOG_LEVEL_DEBUG1: 400 txt = "debug1"; 401 pri = LOG_DEBUG; 402 break; 403 case SYSLOG_LEVEL_DEBUG2: 404 txt = "debug2"; 405 pri = LOG_DEBUG; 406 break; 407 case SYSLOG_LEVEL_DEBUG3: 408 txt = "debug3"; 409 pri = LOG_DEBUG; 410 break; 411 default: 412 txt = "internal error"; 413 pri = LOG_ERR; 414 break; 415 } 416 len = sizeof(msgbuf); 417 msgbufp = msgbuf; 418 if (txt != NULL && log_handler == NULL) { 419 len2 = strlen(txt); 420 if (len2 > len - 2) 421 len2 = len - 2; 422 memcpy(msgbufp, txt, len2); 423 msgbufp += len2; 424 *msgbufp++ = ':'; 425 *msgbufp++ = ' '; 426 len -= len2 + 2; 427 } 428 vsnprintf(msgbufp, len, fmt, args); 429 strnvis(visbuf, sizeof(visbuf), msgbuf, VIS_SAFE|VIS_OCTAL); 430 if (log_handler != NULL) { 431 /* Avoid recursion */ 432 tmp_handler = log_handler; 433 log_handler = NULL; 434 tmp_handler(level, visbuf, log_handler_ctx); 435 log_handler = tmp_handler; 436 } else if (log_on_stderr) { 437 snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", 438 (int)sizeof msgbuf - 3, visbuf); 439 (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); 440 } else { 441 #ifdef SYSLOG_DATA_INIT 442 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 443 syslog_r(pri, &sdata, "%.500s", visbuf); 444 closelog_r(&sdata); 445 #else 446 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 447 syslog(pri, "%.500s", visbuf); 448 closelog(); 449 #endif 450 } 451 errno = saved_errno; 452 } 453