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