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