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