1/* $NetBSD: log.c,v 1.6 2011/09/16 15:36:00 joerg Exp $ */ 2/* $OpenBSD: log.c,v 1.42 2011/06/17 21:44:30 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.6 2011/09/16 15:36:00 joerg Exp $"); 40#include <sys/types.h> 41#include <sys/uio.h> 42 43#include <stdarg.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <syslog.h> 48#include <unistd.h> 49#include <errno.h> 50#include <vis.h> 51 52#include "xmalloc.h" 53#include "log.h" 54 55static LogLevel log_level = SYSLOG_LEVEL_INFO; 56static int log_on_stderr = 1; 57static int log_facility = LOG_AUTH; 58static const char *argv0; 59static log_handler_fn *log_handler; 60static void *log_handler_ctx; 61 62extern char *__progname; 63 64/* textual representation of log-facilities/levels */ 65 66static struct { 67 const char *name; 68 SyslogFacility val; 69} log_facilities[] = { 70 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 71 { "USER", SYSLOG_FACILITY_USER }, 72 { "AUTH", SYSLOG_FACILITY_AUTH }, 73 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 74 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 75 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 76 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 77 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 78 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 79 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 80 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 81 { NULL, SYSLOG_FACILITY_NOT_SET } 82}; 83 84static struct { 85 const char *name; 86 LogLevel val; 87} log_levels[] = 88{ 89 { "QUIET", SYSLOG_LEVEL_QUIET }, 90 { "FATAL", SYSLOG_LEVEL_FATAL }, 91 { "ERROR", SYSLOG_LEVEL_ERROR }, 92 { "INFO", SYSLOG_LEVEL_INFO }, 93 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 94 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 95 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 96 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 97 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 98 { NULL, SYSLOG_LEVEL_NOT_SET } 99}; 100 101SyslogFacility 102log_facility_number(char *name) 103{ 104 int i; 105 106 if (name != NULL) 107 for (i = 0; log_facilities[i].name; i++) 108 if (strcasecmp(log_facilities[i].name, name) == 0) 109 return log_facilities[i].val; 110 return SYSLOG_FACILITY_NOT_SET; 111} 112 113const char * 114log_facility_name(SyslogFacility facility) 115{ 116 u_int i; 117 118 for (i = 0; log_facilities[i].name; i++) 119 if (log_facilities[i].val == facility) 120 return log_facilities[i].name; 121 return NULL; 122} 123 124LogLevel 125log_level_number(char *name) 126{ 127 int i; 128 129 if (name != NULL) 130 for (i = 0; log_levels[i].name; i++) 131 if (strcasecmp(log_levels[i].name, name) == 0) 132 return log_levels[i].val; 133 return SYSLOG_LEVEL_NOT_SET; 134} 135 136const char * 137log_level_name(LogLevel level) 138{ 139 u_int i; 140 141 for (i = 0; log_levels[i].name != NULL; i++) 142 if (log_levels[i].val == level) 143 return log_levels[i].name; 144 return NULL; 145} 146 147/* Error messages that should be logged. */ 148 149void 150error(const char *fmt,...) 151{ 152 va_list args; 153 154 va_start(args, fmt); 155 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 156 va_end(args); 157} 158 159void 160sigdie(const char *fmt,...) 161{ 162 va_list args; 163 164 va_start(args, fmt); 165 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 166 va_end(args); 167 _exit(1); 168} 169 170 171/* Log this message (information that usually should go to the log). */ 172 173void 174logit(const char *fmt,...) 175{ 176 va_list args; 177 178 va_start(args, fmt); 179 do_log(SYSLOG_LEVEL_INFO, fmt, args); 180 va_end(args); 181} 182 183/* More detailed messages (information that does not need to go to the log). */ 184 185void 186verbose(const char *fmt,...) 187{ 188 va_list args; 189 190 va_start(args, fmt); 191 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 192 va_end(args); 193} 194 195/* Debugging messages that should not be logged during normal operation. */ 196 197void 198debug(const char *fmt,...) 199{ 200 va_list args; 201 202 va_start(args, fmt); 203 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 204 va_end(args); 205} 206 207void 208debug2(const char *fmt,...) 209{ 210 va_list args; 211 212 va_start(args, fmt); 213 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 214 va_end(args); 215} 216 217void 218debug3(const char *fmt,...) 219{ 220 va_list args; 221 222 va_start(args, fmt); 223 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 224 va_end(args); 225} 226 227/* 228 * Initialize the log. 229 */ 230 231void 232log_init(const char *av0, LogLevel level, SyslogFacility facility, 233 int on_stderr) 234{ 235 argv0 = av0; 236 237 switch (level) { 238 case SYSLOG_LEVEL_QUIET: 239 case SYSLOG_LEVEL_FATAL: 240 case SYSLOG_LEVEL_ERROR: 241 case SYSLOG_LEVEL_INFO: 242 case SYSLOG_LEVEL_VERBOSE: 243 case SYSLOG_LEVEL_DEBUG1: 244 case SYSLOG_LEVEL_DEBUG2: 245 case SYSLOG_LEVEL_DEBUG3: 246 log_level = level; 247 break; 248 default: 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#define MSGBUFSIZ 1024 304 305void 306set_log_handler(log_handler_fn *handler, void *ctx) 307{ 308 log_handler = handler; 309 log_handler_ctx = ctx; 310} 311 312void 313do_log2(LogLevel level, const char *fmt,...) 314{ 315 va_list args; 316 317 va_start(args, fmt); 318 do_log(level, fmt, args); 319 va_end(args); 320} 321 322void 323do_log(LogLevel level, const char *fmt, va_list args) 324{ 325#ifdef SYSLOG_DATA_INIT 326 struct syslog_data sdata = SYSLOG_DATA_INIT; 327#endif 328 char msgbuf[MSGBUFSIZ], *msgbufp; 329 char visbuf[MSGBUFSIZ * 4 + 1]; 330 size_t len, len2; 331 int len3; 332 const char *txt = NULL; 333 int pri = LOG_INFO; 334 int saved_errno = errno; 335 log_handler_fn *tmp_handler; 336 337 if (level > log_level) 338 return; 339 340 switch (level) { 341 case SYSLOG_LEVEL_FATAL: 342 if (!log_on_stderr) 343 txt = "fatal"; 344 pri = LOG_CRIT; 345 break; 346 case SYSLOG_LEVEL_ERROR: 347 if (!log_on_stderr) 348 txt = "error"; 349 pri = LOG_ERR; 350 break; 351 case SYSLOG_LEVEL_INFO: 352 pri = LOG_INFO; 353 break; 354 case SYSLOG_LEVEL_VERBOSE: 355 pri = LOG_INFO; 356 break; 357 case SYSLOG_LEVEL_DEBUG1: 358 txt = "debug1"; 359 pri = LOG_DEBUG; 360 break; 361 case SYSLOG_LEVEL_DEBUG2: 362 txt = "debug2"; 363 pri = LOG_DEBUG; 364 break; 365 case SYSLOG_LEVEL_DEBUG3: 366 txt = "debug3"; 367 pri = LOG_DEBUG; 368 break; 369 default: 370 txt = "internal error"; 371 pri = LOG_ERR; 372 break; 373 } 374 len = sizeof(msgbuf); 375 msgbufp = msgbuf; 376 if (txt != NULL && log_handler == NULL) { 377 len2 = strlen(txt); 378 if (len2 > len - 2) 379 len2 = len - 2; 380 memcpy(msgbufp, txt, len2); 381 msgbufp += len2; 382 *msgbufp++ = ':'; 383 *msgbufp++ = ' '; 384 len -= len2 + 2; 385 } 386 vsnprintf(msgbufp, len, fmt, args); 387 len3 = strnvis(visbuf, sizeof(visbuf), msgbuf, VIS_SAFE|VIS_OCTAL); 388 if (log_handler != NULL) { 389 /* Avoid recursion */ 390 tmp_handler = log_handler; 391 log_handler = NULL; 392 tmp_handler(level, visbuf, log_handler_ctx); 393 log_handler = tmp_handler; 394 } else if (log_on_stderr) { 395 struct iovec iov[] = { 396 { visbuf, len3 }, 397 { __UNCONST("\r\n"), 2 }, 398 }; 399 writev(STDERR_FILENO, iov, __arraycount(iov)); 400 } else { 401#ifdef SYSLOG_DATA_INIT 402 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 403 syslog_r(pri, &sdata, "%.500s", visbuf); 404 closelog_r(&sdata); 405#else 406 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 407 syslog(pri, "%.500s", visbuf); 408 closelog(); 409#endif 410 } 411 errno = saved_errno; 412} 413