log.c revision 1.20
1/* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * 6 * As far as I am concerned, the code I have written for this software 7 * can be used freely for any purpose. Any derived versions of this 8 * software must be clearly marked as such, and if the derived work is 9 * incompatible with the protocol description in the RFC file, it must be 10 * called by a name other than "ssh" or "Secure Shell". 11 */ 12/* 13 * Copyright (c) 2000 Markus Friedl. All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#include "includes.h" 37RCSID("$OpenBSD: log.c,v 1.20 2002/01/17 04:27:37 stevesk Exp $"); 38 39#include "log.h" 40#include "xmalloc.h" 41 42#include <syslog.h> 43 44static LogLevel log_level = SYSLOG_LEVEL_INFO; 45static int log_on_stderr = 1; 46static int log_facility = LOG_AUTH; 47static char *argv0; 48 49extern char *__progname; 50 51/* textual representation of log-facilities/levels */ 52 53static struct { 54 const char *name; 55 SyslogFacility val; 56} log_facilities[] = { 57 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 58 { "USER", SYSLOG_FACILITY_USER }, 59 { "AUTH", SYSLOG_FACILITY_AUTH }, 60 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 61 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 62 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 63 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 64 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 65 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 66 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 67 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 68 { NULL, (SyslogFacility)0 } 69}; 70 71static struct { 72 const char *name; 73 LogLevel val; 74} log_levels[] = 75{ 76 { "QUIET", SYSLOG_LEVEL_QUIET }, 77 { "FATAL", SYSLOG_LEVEL_FATAL }, 78 { "ERROR", SYSLOG_LEVEL_ERROR }, 79 { "INFO", SYSLOG_LEVEL_INFO }, 80 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 81 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 82 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 83 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 84 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 85 { NULL, (LogLevel)0 } 86}; 87 88static void do_log(LogLevel level, const char *fmt, va_list args); 89 90SyslogFacility 91log_facility_number(char *name) 92{ 93 int i; 94 if (name != NULL) 95 for (i = 0; log_facilities[i].name; i++) 96 if (strcasecmp(log_facilities[i].name, name) == 0) 97 return log_facilities[i].val; 98 return (SyslogFacility) - 1; 99} 100 101LogLevel 102log_level_number(char *name) 103{ 104 int i; 105 if (name != NULL) 106 for (i = 0; log_levels[i].name; i++) 107 if (strcasecmp(log_levels[i].name, name) == 0) 108 return log_levels[i].val; 109 return (LogLevel) - 1; 110} 111/* Fatal messages. This function never returns. */ 112 113void 114fatal(const char *fmt,...) 115{ 116 va_list args; 117 va_start(args, fmt); 118 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 119 va_end(args); 120 fatal_cleanup(); 121} 122 123/* Error messages that should be logged. */ 124 125void 126error(const char *fmt,...) 127{ 128 va_list args; 129 va_start(args, fmt); 130 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 131 va_end(args); 132} 133 134/* Log this message (information that usually should go to the log). */ 135 136void 137log(const char *fmt,...) 138{ 139 va_list args; 140 va_start(args, fmt); 141 do_log(SYSLOG_LEVEL_INFO, fmt, args); 142 va_end(args); 143} 144 145/* More detailed messages (information that does not need to go to the log). */ 146 147void 148verbose(const char *fmt,...) 149{ 150 va_list args; 151 va_start(args, fmt); 152 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 153 va_end(args); 154} 155 156/* Debugging messages that should not be logged during normal operation. */ 157 158void 159debug(const char *fmt,...) 160{ 161 va_list args; 162 va_start(args, fmt); 163 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 164 va_end(args); 165} 166 167void 168debug2(const char *fmt,...) 169{ 170 va_list args; 171 va_start(args, fmt); 172 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 173 va_end(args); 174} 175 176void 177debug3(const char *fmt,...) 178{ 179 va_list args; 180 va_start(args, fmt); 181 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 182 va_end(args); 183} 184 185/* Fatal cleanup */ 186 187struct fatal_cleanup { 188 struct fatal_cleanup *next; 189 void (*proc) (void *); 190 void *context; 191}; 192 193static struct fatal_cleanup *fatal_cleanups = NULL; 194 195/* Registers a cleanup function to be called by fatal() before exiting. */ 196 197void 198fatal_add_cleanup(void (*proc) (void *), void *context) 199{ 200 struct fatal_cleanup *cu; 201 202 cu = xmalloc(sizeof(*cu)); 203 cu->proc = proc; 204 cu->context = context; 205 cu->next = fatal_cleanups; 206 fatal_cleanups = cu; 207} 208 209/* Removes a cleanup frunction to be called at fatal(). */ 210 211void 212fatal_remove_cleanup(void (*proc) (void *context), void *context) 213{ 214 struct fatal_cleanup **cup, *cu; 215 216 for (cup = &fatal_cleanups; *cup; cup = &cu->next) { 217 cu = *cup; 218 if (cu->proc == proc && cu->context == context) { 219 *cup = cu->next; 220 xfree(cu); 221 return; 222 } 223 } 224 fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", 225 (u_long) proc, (u_long) context); 226} 227 228/* Cleanup and exit */ 229void 230fatal_cleanup(void) 231{ 232 struct fatal_cleanup *cu, *next_cu; 233 static int called = 0; 234 235 if (called) 236 exit(255); 237 called = 1; 238 /* Call cleanup functions. */ 239 for (cu = fatal_cleanups; cu; cu = next_cu) { 240 next_cu = cu->next; 241 debug("Calling cleanup 0x%lx(0x%lx)", 242 (u_long) cu->proc, (u_long) cu->context); 243 (*cu->proc) (cu->context); 244 } 245 exit(255); 246} 247 248 249/* 250 * Initialize the log. 251 */ 252 253void 254log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 255{ 256 argv0 = av0; 257 258 switch (level) { 259 case SYSLOG_LEVEL_QUIET: 260 case SYSLOG_LEVEL_FATAL: 261 case SYSLOG_LEVEL_ERROR: 262 case SYSLOG_LEVEL_INFO: 263 case SYSLOG_LEVEL_VERBOSE: 264 case SYSLOG_LEVEL_DEBUG1: 265 case SYSLOG_LEVEL_DEBUG2: 266 case SYSLOG_LEVEL_DEBUG3: 267 log_level = level; 268 break; 269 default: 270 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 271 (int) level); 272 exit(1); 273 } 274 275 log_on_stderr = on_stderr; 276 if (on_stderr) 277 return; 278 279 switch (facility) { 280 case SYSLOG_FACILITY_DAEMON: 281 log_facility = LOG_DAEMON; 282 break; 283 case SYSLOG_FACILITY_USER: 284 log_facility = LOG_USER; 285 break; 286 case SYSLOG_FACILITY_AUTH: 287 log_facility = LOG_AUTH; 288 break; 289 case SYSLOG_FACILITY_LOCAL0: 290 log_facility = LOG_LOCAL0; 291 break; 292 case SYSLOG_FACILITY_LOCAL1: 293 log_facility = LOG_LOCAL1; 294 break; 295 case SYSLOG_FACILITY_LOCAL2: 296 log_facility = LOG_LOCAL2; 297 break; 298 case SYSLOG_FACILITY_LOCAL3: 299 log_facility = LOG_LOCAL3; 300 break; 301 case SYSLOG_FACILITY_LOCAL4: 302 log_facility = LOG_LOCAL4; 303 break; 304 case SYSLOG_FACILITY_LOCAL5: 305 log_facility = LOG_LOCAL5; 306 break; 307 case SYSLOG_FACILITY_LOCAL6: 308 log_facility = LOG_LOCAL6; 309 break; 310 case SYSLOG_FACILITY_LOCAL7: 311 log_facility = LOG_LOCAL7; 312 break; 313 default: 314 fprintf(stderr, 315 "Unrecognized internal syslog facility code %d\n", 316 (int) facility); 317 exit(1); 318 } 319} 320 321#define MSGBUFSIZ 1024 322 323static void 324do_log(LogLevel level, const char *fmt, va_list args) 325{ 326 char msgbuf[MSGBUFSIZ]; 327 char fmtbuf[MSGBUFSIZ]; 328 char *txt = NULL; 329 int pri = LOG_INFO; 330 331 if (level > log_level) 332 return; 333 334 switch (level) { 335 case SYSLOG_LEVEL_FATAL: 336 if (!log_on_stderr) 337 txt = "fatal"; 338 pri = LOG_CRIT; 339 break; 340 case SYSLOG_LEVEL_ERROR: 341 if (!log_on_stderr) 342 txt = "error"; 343 pri = LOG_ERR; 344 break; 345 case SYSLOG_LEVEL_INFO: 346 pri = LOG_INFO; 347 break; 348 case SYSLOG_LEVEL_VERBOSE: 349 pri = LOG_INFO; 350 break; 351 case SYSLOG_LEVEL_DEBUG1: 352 txt = "debug1"; 353 pri = LOG_DEBUG; 354 break; 355 case SYSLOG_LEVEL_DEBUG2: 356 txt = "debug2"; 357 pri = LOG_DEBUG; 358 break; 359 case SYSLOG_LEVEL_DEBUG3: 360 txt = "debug3"; 361 pri = LOG_DEBUG; 362 break; 363 default: 364 txt = "internal error"; 365 pri = LOG_ERR; 366 break; 367 } 368 if (txt != NULL) { 369 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 370 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 371 } else { 372 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 373 } 374 if (log_on_stderr) { 375 fprintf(stderr, "%s\r\n", msgbuf); 376 } else { 377 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 378 syslog(pri, "%.500s", msgbuf); 379 closelog(); 380 } 381} 382