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