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