log.c revision 1.25
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.25 2003/01/11 18:29:43 markus 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, SYSLOG_FACILITY_NOT_SET } 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, SYSLOG_LEVEL_NOT_SET } 86}; 87 88SyslogFacility 89log_facility_number(char *name) 90{ 91 int i; 92 93 if (name != NULL) 94 for (i = 0; log_facilities[i].name; i++) 95 if (strcasecmp(log_facilities[i].name, name) == 0) 96 return log_facilities[i].val; 97 return SYSLOG_FACILITY_NOT_SET; 98} 99 100LogLevel 101log_level_number(char *name) 102{ 103 int i; 104 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 SYSLOG_LEVEL_NOT_SET; 110} 111 112/* Error messages that should be logged. */ 113 114void 115error(const char *fmt,...) 116{ 117 va_list args; 118 119 va_start(args, fmt); 120 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 121 va_end(args); 122} 123 124/* Log this message (information that usually should go to the log). */ 125 126void 127log(const char *fmt,...) 128{ 129 va_list args; 130 131 va_start(args, fmt); 132 do_log(SYSLOG_LEVEL_INFO, fmt, args); 133 va_end(args); 134} 135 136/* More detailed messages (information that does not need to go to the log). */ 137 138void 139verbose(const char *fmt,...) 140{ 141 va_list args; 142 143 va_start(args, fmt); 144 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 145 va_end(args); 146} 147 148/* Debugging messages that should not be logged during normal operation. */ 149 150void 151debug(const char *fmt,...) 152{ 153 va_list args; 154 155 va_start(args, fmt); 156 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 157 va_end(args); 158} 159 160void 161debug2(const char *fmt,...) 162{ 163 va_list args; 164 165 va_start(args, fmt); 166 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 167 va_end(args); 168} 169 170void 171debug3(const char *fmt,...) 172{ 173 va_list args; 174 175 va_start(args, fmt); 176 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 177 va_end(args); 178} 179 180/* Fatal cleanup */ 181 182struct fatal_cleanup { 183 struct fatal_cleanup *next; 184 void (*proc) (void *); 185 void *context; 186}; 187 188static struct fatal_cleanup *fatal_cleanups = NULL; 189 190/* Registers a cleanup function to be called by fatal() before exiting. */ 191 192void 193fatal_add_cleanup(void (*proc) (void *), void *context) 194{ 195 struct fatal_cleanup *cu; 196 197 cu = xmalloc(sizeof(*cu)); 198 cu->proc = proc; 199 cu->context = context; 200 cu->next = fatal_cleanups; 201 fatal_cleanups = cu; 202} 203 204/* Removes a cleanup frunction to be called at fatal(). */ 205 206void 207fatal_remove_cleanup(void (*proc) (void *context), void *context) 208{ 209 struct fatal_cleanup **cup, *cu; 210 211 for (cup = &fatal_cleanups; *cup; cup = &cu->next) { 212 cu = *cup; 213 if (cu->proc == proc && cu->context == context) { 214 *cup = cu->next; 215 xfree(cu); 216 return; 217 } 218 } 219 fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", 220 (u_long) proc, (u_long) context); 221} 222 223/* Remove all cleanups, to be called after fork() */ 224void 225fatal_remove_all_cleanups(void) 226{ 227 struct fatal_cleanup *cu, *next_cu; 228 229 for (cu = fatal_cleanups; cu; cu = next_cu) { 230 next_cu = cu->next; 231 xfree(cu); 232 } 233 fatal_cleanups = NULL; 234} 235 236/* Cleanup and exit */ 237void 238fatal_cleanup(void) 239{ 240 struct fatal_cleanup *cu, *next_cu; 241 static int called = 0; 242 243 if (called) 244 exit(255); 245 called = 1; 246 /* Call cleanup functions. */ 247 for (cu = fatal_cleanups; cu; cu = next_cu) { 248 next_cu = cu->next; 249 debug("Calling cleanup 0x%lx(0x%lx)", 250 (u_long) cu->proc, (u_long) cu->context); 251 (*cu->proc) (cu->context); 252 } 253 exit(255); 254} 255 256 257/* 258 * Initialize the log. 259 */ 260 261void 262log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 263{ 264 argv0 = av0; 265 266 switch (level) { 267 case SYSLOG_LEVEL_QUIET: 268 case SYSLOG_LEVEL_FATAL: 269 case SYSLOG_LEVEL_ERROR: 270 case SYSLOG_LEVEL_INFO: 271 case SYSLOG_LEVEL_VERBOSE: 272 case SYSLOG_LEVEL_DEBUG1: 273 case SYSLOG_LEVEL_DEBUG2: 274 case SYSLOG_LEVEL_DEBUG3: 275 log_level = level; 276 break; 277 default: 278 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 279 (int) level); 280 exit(1); 281 } 282 283 log_on_stderr = on_stderr; 284 if (on_stderr) 285 return; 286 287 switch (facility) { 288 case SYSLOG_FACILITY_DAEMON: 289 log_facility = LOG_DAEMON; 290 break; 291 case SYSLOG_FACILITY_USER: 292 log_facility = LOG_USER; 293 break; 294 case SYSLOG_FACILITY_AUTH: 295 log_facility = LOG_AUTH; 296 break; 297 case SYSLOG_FACILITY_LOCAL0: 298 log_facility = LOG_LOCAL0; 299 break; 300 case SYSLOG_FACILITY_LOCAL1: 301 log_facility = LOG_LOCAL1; 302 break; 303 case SYSLOG_FACILITY_LOCAL2: 304 log_facility = LOG_LOCAL2; 305 break; 306 case SYSLOG_FACILITY_LOCAL3: 307 log_facility = LOG_LOCAL3; 308 break; 309 case SYSLOG_FACILITY_LOCAL4: 310 log_facility = LOG_LOCAL4; 311 break; 312 case SYSLOG_FACILITY_LOCAL5: 313 log_facility = LOG_LOCAL5; 314 break; 315 case SYSLOG_FACILITY_LOCAL6: 316 log_facility = LOG_LOCAL6; 317 break; 318 case SYSLOG_FACILITY_LOCAL7: 319 log_facility = LOG_LOCAL7; 320 break; 321 default: 322 fprintf(stderr, 323 "Unrecognized internal syslog facility code %d\n", 324 (int) facility); 325 exit(1); 326 } 327} 328 329#define MSGBUFSIZ 1024 330 331void 332do_log(LogLevel level, const char *fmt, va_list args) 333{ 334 char msgbuf[MSGBUFSIZ]; 335 char fmtbuf[MSGBUFSIZ]; 336 char *txt = NULL; 337 int pri = LOG_INFO; 338 339 if (level > log_level) 340 return; 341 342 switch (level) { 343 case SYSLOG_LEVEL_FATAL: 344 if (!log_on_stderr) 345 txt = "fatal"; 346 pri = LOG_CRIT; 347 break; 348 case SYSLOG_LEVEL_ERROR: 349 if (!log_on_stderr) 350 txt = "error"; 351 pri = LOG_ERR; 352 break; 353 case SYSLOG_LEVEL_INFO: 354 pri = LOG_INFO; 355 break; 356 case SYSLOG_LEVEL_VERBOSE: 357 pri = LOG_INFO; 358 break; 359 case SYSLOG_LEVEL_DEBUG1: 360 txt = "debug1"; 361 pri = LOG_DEBUG; 362 break; 363 case SYSLOG_LEVEL_DEBUG2: 364 txt = "debug2"; 365 pri = LOG_DEBUG; 366 break; 367 case SYSLOG_LEVEL_DEBUG3: 368 txt = "debug3"; 369 pri = LOG_DEBUG; 370 break; 371 default: 372 txt = "internal error"; 373 pri = LOG_ERR; 374 break; 375 } 376 if (txt != NULL) { 377 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 378 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 379 } else { 380 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 381 } 382 if (log_on_stderr) { 383 fprintf(stderr, "%s\r\n", msgbuf); 384 } else { 385 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 386 syslog(pri, "%.500s", msgbuf); 387 closelog(); 388 } 389} 390