1 /* $OpenBSD: log.c,v 1.39 2006/08/18 09:13:25 deraadt Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * 7 * As far as I am concerned, the code I have written for this software 8 * can be used freely for any purpose. Any derived versions of this 9 * software must be clearly marked as such, and if the derived work is 10 * incompatible with the protocol description in the RFC file, it must be 11 * called by a name other than "ssh" or "Secure Shell". 12 */ 13 /* 14 * Copyright (c) 2000 Markus Friedl. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include "includes.h" 38 39 #include <sys/types.h> 40 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) 48 # include <vis.h> 49 #endif 50 51 #include "xmalloc.h" 52 #include "log.h" 53 54 static LogLevel log_level = SYSLOG_LEVEL_INFO; 55 static int log_on_stderr = 1; 56 static int log_facility = LOG_AUTH; 57 static char *argv0; 58 59 extern char *__progname; 60 61 #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) 62 #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) 63 64 /* textual representation of log-facilities/levels */ 65 66 static struct { 67 const char *name; 68 SyslogFacility val; 69 } log_facilities[] = { 70 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 71 { "USER", SYSLOG_FACILITY_USER }, 72 { "AUTH", SYSLOG_FACILITY_AUTH }, 73 #ifdef LOG_AUTHPRIV 74 { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, 75 #endif 76 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 77 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 78 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 79 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 80 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 81 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 82 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 83 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 84 { NULL, SYSLOG_FACILITY_NOT_SET } 85 }; 86 87 static struct { 88 const char *name; 89 LogLevel val; 90 } log_levels[] = 91 { 92 { "QUIET", SYSLOG_LEVEL_QUIET }, 93 { "FATAL", SYSLOG_LEVEL_FATAL }, 94 { "ERROR", SYSLOG_LEVEL_ERROR }, 95 { "INFO", SYSLOG_LEVEL_INFO }, 96 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 97 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 98 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 99 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 100 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 101 { NULL, SYSLOG_LEVEL_NOT_SET } 102 }; 103 104 SyslogFacility 105 log_facility_number(char *name) 106 { 107 int i; 108 109 if (name != NULL) 110 for (i = 0; log_facilities[i].name; i++) 111 if (strcasecmp(log_facilities[i].name, name) == 0) 112 return log_facilities[i].val; 113 return SYSLOG_FACILITY_NOT_SET; 114 } 115 116 LogLevel 117 log_level_number(char *name) 118 { 119 int i; 120 121 if (name != NULL) 122 for (i = 0; log_levels[i].name; i++) 123 if (strcasecmp(log_levels[i].name, name) == 0) 124 return log_levels[i].val; 125 return SYSLOG_LEVEL_NOT_SET; 126 } 127 128 /* Error messages that should be logged. */ 129 130 void 131 error(const char *fmt,...) 132 { 133 va_list args; 134 135 va_start(args, fmt); 136 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 137 va_end(args); 138 } 139 140 void 141 sigdie(const char *fmt,...) 142 { 143 #ifdef DO_LOG_SAFE_IN_SIGHAND 144 va_list args; 145 146 va_start(args, fmt); 147 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 148 va_end(args); 149 #endif 150 _exit(1); 151 } 152 153 154 /* Log this message (information that usually should go to the log). */ 155 156 void 157 logit(const char *fmt,...) 158 { 159 va_list args; 160 161 va_start(args, fmt); 162 do_log(SYSLOG_LEVEL_INFO, fmt, args); 163 va_end(args); 164 } 165 166 /* More detailed messages (information that does not need to go to the log). */ 167 168 void 169 verbose(const char *fmt,...) 170 { 171 va_list args; 172 173 va_start(args, fmt); 174 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 175 va_end(args); 176 } 177 178 /* Debugging messages that should not be logged during normal operation. */ 179 180 void 181 debug(const char *fmt,...) 182 { 183 va_list args; 184 185 va_start(args, fmt); 186 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 187 va_end(args); 188 } 189 190 void 191 debug2(const char *fmt,...) 192 { 193 va_list args; 194 195 va_start(args, fmt); 196 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 197 va_end(args); 198 } 199 200 void 201 debug3(const char *fmt,...) 202 { 203 va_list args; 204 205 va_start(args, fmt); 206 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 207 va_end(args); 208 } 209 210 /* 211 * Initialize the log. 212 */ 213 214 void 215 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 216 { 217 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 218 struct syslog_data sdata = SYSLOG_DATA_INIT; 219 #endif 220 221 argv0 = av0; 222 223 switch (level) { 224 case SYSLOG_LEVEL_QUIET: 225 case SYSLOG_LEVEL_FATAL: 226 case SYSLOG_LEVEL_ERROR: 227 case SYSLOG_LEVEL_INFO: 228 case SYSLOG_LEVEL_VERBOSE: 229 case SYSLOG_LEVEL_DEBUG1: 230 case SYSLOG_LEVEL_DEBUG2: 231 case SYSLOG_LEVEL_DEBUG3: 232 log_level = level; 233 break; 234 default: 235 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 236 (int) level); 237 exit(1); 238 } 239 240 log_on_stderr = on_stderr; 241 if (on_stderr) 242 return; 243 244 switch (facility) { 245 case SYSLOG_FACILITY_DAEMON: 246 log_facility = LOG_DAEMON; 247 break; 248 case SYSLOG_FACILITY_USER: 249 log_facility = LOG_USER; 250 break; 251 case SYSLOG_FACILITY_AUTH: 252 log_facility = LOG_AUTH; 253 break; 254 #ifdef LOG_AUTHPRIV 255 case SYSLOG_FACILITY_AUTHPRIV: 256 log_facility = LOG_AUTHPRIV; 257 break; 258 #endif 259 case SYSLOG_FACILITY_LOCAL0: 260 log_facility = LOG_LOCAL0; 261 break; 262 case SYSLOG_FACILITY_LOCAL1: 263 log_facility = LOG_LOCAL1; 264 break; 265 case SYSLOG_FACILITY_LOCAL2: 266 log_facility = LOG_LOCAL2; 267 break; 268 case SYSLOG_FACILITY_LOCAL3: 269 log_facility = LOG_LOCAL3; 270 break; 271 case SYSLOG_FACILITY_LOCAL4: 272 log_facility = LOG_LOCAL4; 273 break; 274 case SYSLOG_FACILITY_LOCAL5: 275 log_facility = LOG_LOCAL5; 276 break; 277 case SYSLOG_FACILITY_LOCAL6: 278 log_facility = LOG_LOCAL6; 279 break; 280 case SYSLOG_FACILITY_LOCAL7: 281 log_facility = LOG_LOCAL7; 282 break; 283 default: 284 fprintf(stderr, 285 "Unrecognized internal syslog facility code %d\n", 286 (int) facility); 287 exit(1); 288 } 289 290 /* 291 * If an external library (eg libwrap) attempts to use syslog 292 * immediately after reexec, syslog may be pointing to the wrong 293 * facility, so we force an open/close of syslog here. 294 */ 295 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 296 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 297 closelog_r(&sdata); 298 #else 299 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 300 closelog(); 301 #endif 302 } 303 304 #define MSGBUFSIZ 1024 305 306 void 307 do_log(LogLevel level, const char *fmt, va_list args) 308 { 309 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 310 struct syslog_data sdata = SYSLOG_DATA_INIT; 311 #endif 312 char msgbuf[MSGBUFSIZ]; 313 char fmtbuf[MSGBUFSIZ]; 314 char *txt = NULL; 315 int pri = LOG_INFO; 316 317 if (level > log_level) 318 return; 319 320 switch (level) { 321 case SYSLOG_LEVEL_FATAL: 322 if (!log_on_stderr) 323 txt = "fatal"; 324 pri = LOG_CRIT; 325 break; 326 case SYSLOG_LEVEL_ERROR: 327 if (!log_on_stderr) 328 txt = "error"; 329 pri = LOG_ERR; 330 break; 331 case SYSLOG_LEVEL_INFO: 332 pri = LOG_INFO; 333 break; 334 case SYSLOG_LEVEL_VERBOSE: 335 pri = LOG_INFO; 336 break; 337 case SYSLOG_LEVEL_DEBUG1: 338 txt = "debug1"; 339 pri = LOG_DEBUG; 340 break; 341 case SYSLOG_LEVEL_DEBUG2: 342 txt = "debug2"; 343 pri = LOG_DEBUG; 344 break; 345 case SYSLOG_LEVEL_DEBUG3: 346 txt = "debug3"; 347 pri = LOG_DEBUG; 348 break; 349 default: 350 txt = "internal error"; 351 pri = LOG_ERR; 352 break; 353 } 354 if (txt != NULL) { 355 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 356 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 357 } else { 358 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 359 } 360 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), 361 log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); 362 if (log_on_stderr) { 363 snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); 364 write(STDERR_FILENO, msgbuf, strlen(msgbuf)); 365 } else { 366 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) 367 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 368 syslog_r(pri, &sdata, "%.500s", fmtbuf); 369 closelog_r(&sdata); 370 #else 371 openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 372 syslog(pri, "%.500s", fmtbuf); 373 closelog(); 374 #endif 375 } 376 } 377