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