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