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