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