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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include "includes.h" 41 RCSID("$OpenBSD: log.c,v 1.24 2002/07/19 15:43:33 markus Exp $"); 42 43 #pragma ident "%Z%%M% %I% %E% SMI" 44 45 #include "log.h" 46 #include "xmalloc.h" 47 48 #include <atomic.h> 49 #include <syslog.h> 50 51 static LogLevel log_level = SYSLOG_LEVEL_INFO; 52 static int log_on_stderr = 1; 53 static int log_facility = LOG_AUTH; 54 static char *argv0; 55 56 extern char *__progname; 57 58 static const char *log_txt_prefix = ""; 59 60 /* textual representation of log-facilities/levels */ 61 62 static struct { 63 const char *name; 64 SyslogFacility val; 65 } log_facilities[] = { 66 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 67 { "USER", SYSLOG_FACILITY_USER }, 68 { "AUTH", SYSLOG_FACILITY_AUTH }, 69 #ifdef LOG_AUTHPRIV 70 { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, 71 #endif 72 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 73 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 74 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 75 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 76 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 77 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 78 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 79 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 80 { NULL, SYSLOG_FACILITY_NOT_SET } 81 }; 82 83 static struct { 84 const char *name; 85 LogLevel val; 86 } log_levels[] = 87 { 88 { "QUIET", SYSLOG_LEVEL_QUIET }, 89 { "FATAL", SYSLOG_LEVEL_FATAL }, 90 { "ERROR", SYSLOG_LEVEL_ERROR }, 91 { "NOTICE", SYSLOG_LEVEL_NOTICE }, 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 101 SyslogFacility 102 log_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 113 LogLevel 114 log_level_number(char *name) 115 { 116 int i; 117 118 if (name != NULL) 119 for (i = 0; log_levels[i].name; i++) 120 if (strcasecmp(log_levels[i].name, name) == 0) 121 return log_levels[i].val; 122 return SYSLOG_LEVEL_NOT_SET; 123 } 124 125 void 126 set_log_txt_prefix(const char *txt) 127 { 128 log_txt_prefix = txt; 129 } 130 131 /* Error messages that should be logged. */ 132 133 void 134 error(const char *fmt,...) 135 { 136 va_list args; 137 138 va_start(args, fmt); 139 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 140 va_end(args); 141 } 142 143 void 144 notice(const char *fmt,...) 145 { 146 va_list args; 147 148 va_start(args, fmt); 149 do_log(SYSLOG_LEVEL_NOTICE, fmt, args); 150 va_end(args); 151 } 152 153 /* Log this message (information that usually should go to the log). */ 154 155 void 156 log(const char *fmt,...) 157 { 158 va_list args; 159 160 va_start(args, fmt); 161 do_log(SYSLOG_LEVEL_INFO, fmt, args); 162 va_end(args); 163 } 164 165 /* More detailed messages (information that does not need to go to the log). */ 166 167 void 168 verbose(const char *fmt,...) 169 { 170 va_list args; 171 172 va_start(args, fmt); 173 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 174 va_end(args); 175 } 176 177 /* Debugging messages that should not be logged during normal operation. */ 178 179 void 180 debug(const char *fmt,...) 181 { 182 va_list args; 183 184 va_start(args, fmt); 185 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 186 va_end(args); 187 } 188 189 void 190 debug2(const char *fmt,...) 191 { 192 va_list args; 193 194 va_start(args, fmt); 195 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 196 va_end(args); 197 } 198 199 void 200 debug3(const char *fmt,...) 201 { 202 va_list args; 203 204 va_start(args, fmt); 205 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 206 va_end(args); 207 } 208 209 /* Fatal cleanup */ 210 211 struct fatal_cleanup { 212 struct fatal_cleanup *next; 213 void (*proc) (void *); 214 void *context; 215 }; 216 217 static struct fatal_cleanup *fatal_cleanups = NULL; 218 219 /* Registers a cleanup function to be called by fatal() before exiting. */ 220 221 void 222 fatal_add_cleanup(void (*proc) (void *), void *context) 223 { 224 struct fatal_cleanup *cu; 225 226 cu = xmalloc(sizeof(*cu)); 227 cu->proc = proc; 228 cu->context = context; 229 cu->next = fatal_cleanups; 230 fatal_cleanups = cu; 231 } 232 233 /* Removes a cleanup function to be called at fatal(). */ 234 235 void 236 fatal_remove_cleanup(void (*proc) (void *context), void *context) 237 { 238 struct fatal_cleanup **cup, *cu; 239 240 for (cup = &fatal_cleanups; *cup; cup = &cu->next) { 241 cu = *cup; 242 if (cu->proc == proc && cu->context == context) { 243 *cup = cu->next; 244 xfree(cu); 245 return; 246 } 247 } 248 debug3("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", 249 (u_long) proc, (u_long) context); 250 } 251 252 /* Remove all cleanups, to be called after fork() */ 253 void 254 fatal_remove_all_cleanups(void) 255 { 256 struct fatal_cleanup *cu, *next_cu; 257 258 for (cu = fatal_cleanups; cu; cu = next_cu) { 259 next_cu = cu->next; 260 xfree(cu); 261 } 262 263 fatal_cleanups = NULL; 264 } 265 266 /* Cleanup and exit. Make sure each cleanup is called only once. */ 267 void 268 fatal_cleanup(void) 269 { 270 struct fatal_cleanup *cu, *next_cu; 271 static volatile u_int called = 0; 272 273 if (atomic_cas_uint(&called, 0, 1) == 1) 274 exit(255); 275 /* Call cleanup functions. */ 276 for (cu = fatal_cleanups; cu; cu = next_cu) { 277 next_cu = cu->next; 278 debug("Calling cleanup 0x%lx(0x%lx)", 279 (u_long) cu->proc, (u_long) cu->context); 280 (*cu->proc) (cu->context); 281 } 282 exit(255); 283 } 284 285 286 /* 287 * Initialize the log. 288 */ 289 290 void 291 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 292 { 293 argv0 = av0; 294 295 switch (level) { 296 case SYSLOG_LEVEL_QUIET: 297 case SYSLOG_LEVEL_FATAL: 298 case SYSLOG_LEVEL_ERROR: 299 case SYSLOG_LEVEL_NOTICE: 300 case SYSLOG_LEVEL_INFO: 301 case SYSLOG_LEVEL_VERBOSE: 302 case SYSLOG_LEVEL_DEBUG1: 303 case SYSLOG_LEVEL_DEBUG2: 304 case SYSLOG_LEVEL_DEBUG3: 305 log_level = level; 306 break; 307 default: 308 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 309 (int) level); 310 exit(1); 311 } 312 313 log_on_stderr = on_stderr; 314 if (on_stderr) 315 return; 316 317 switch (facility) { 318 case SYSLOG_FACILITY_DAEMON: 319 log_facility = LOG_DAEMON; 320 break; 321 case SYSLOG_FACILITY_USER: 322 log_facility = LOG_USER; 323 break; 324 case SYSLOG_FACILITY_AUTH: 325 log_facility = LOG_AUTH; 326 break; 327 #ifdef LOG_AUTHPRIV 328 case SYSLOG_FACILITY_AUTHPRIV: 329 log_facility = LOG_AUTHPRIV; 330 break; 331 #endif 332 case SYSLOG_FACILITY_LOCAL0: 333 log_facility = LOG_LOCAL0; 334 break; 335 case SYSLOG_FACILITY_LOCAL1: 336 log_facility = LOG_LOCAL1; 337 break; 338 case SYSLOG_FACILITY_LOCAL2: 339 log_facility = LOG_LOCAL2; 340 break; 341 case SYSLOG_FACILITY_LOCAL3: 342 log_facility = LOG_LOCAL3; 343 break; 344 case SYSLOG_FACILITY_LOCAL4: 345 log_facility = LOG_LOCAL4; 346 break; 347 case SYSLOG_FACILITY_LOCAL5: 348 log_facility = LOG_LOCAL5; 349 break; 350 case SYSLOG_FACILITY_LOCAL6: 351 log_facility = LOG_LOCAL6; 352 break; 353 case SYSLOG_FACILITY_LOCAL7: 354 log_facility = LOG_LOCAL7; 355 break; 356 default: 357 fprintf(stderr, 358 "Unrecognized internal syslog facility code %d\n", 359 (int) facility); 360 exit(1); 361 } 362 } 363 364 #define MSGBUFSIZ 1024 365 366 /* PRINTFLIKE2 */ 367 void 368 do_log(LogLevel level, const char *fmt, va_list args) 369 { 370 char msgbuf[MSGBUFSIZ]; 371 char fmtbuf[MSGBUFSIZ]; 372 char *txt = NULL; 373 int pri = LOG_INFO; 374 int do_gettext = log_on_stderr; /* 375 * Localize user messages - not 376 * syslog()ed messages. 377 */ 378 379 if (level > log_level) 380 return; 381 382 switch (level) { 383 case SYSLOG_LEVEL_FATAL: 384 if (!log_on_stderr) 385 txt = "fatal"; 386 pri = LOG_CRIT; 387 break; 388 case SYSLOG_LEVEL_ERROR: 389 if (!log_on_stderr) 390 txt = "error"; 391 pri = LOG_ERR; 392 break; 393 case SYSLOG_LEVEL_NOTICE: 394 pri = LOG_NOTICE; 395 break; 396 case SYSLOG_LEVEL_INFO: 397 pri = LOG_INFO; 398 break; 399 case SYSLOG_LEVEL_VERBOSE: 400 pri = LOG_INFO; 401 break; 402 case SYSLOG_LEVEL_DEBUG1: 403 txt = "debug1"; 404 pri = LOG_DEBUG; 405 /* 406 * Don't localize debug messages - such are not intended 407 * for users but for support staff whose preferred 408 * language is unknown, therefore we default to the 409 * language used in the source code: English. 410 */ 411 do_gettext = 0; 412 break; 413 case SYSLOG_LEVEL_DEBUG2: 414 txt = "debug2"; 415 pri = LOG_DEBUG; 416 do_gettext = 0; /* Don't localize debug messages. */ 417 break; 418 case SYSLOG_LEVEL_DEBUG3: 419 txt = "debug3"; 420 pri = LOG_DEBUG; 421 do_gettext = 0; /* Don't localize debug messages. */ 422 break; 423 default: 424 txt = "internal error"; 425 pri = LOG_ERR; 426 break; 427 } 428 if (txt != NULL) { 429 snprintf(fmtbuf, sizeof(fmtbuf), "%s%s: %s", log_txt_prefix, 430 do_gettext ? gettext(txt) : txt, 431 do_gettext ? gettext(fmt) : fmt); 432 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 433 } else { 434 vsnprintf(msgbuf, sizeof(msgbuf), 435 do_gettext ? gettext(fmt) : fmt, 436 args); 437 } 438 if (log_on_stderr) { 439 fprintf(stderr, "%s\r\n", msgbuf); 440 } else { 441 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 442 syslog(pri, "%.500s", msgbuf); 443 closelog(); 444 } 445 } 446