log.c revision 1.39
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 <sys/types.h> 38 39#include <stdarg.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <syslog.h> 44#include <unistd.h> 45#include <vis.h> 46 47#include "xmalloc.h" 48#include "log.h" 49 50static LogLevel log_level = SYSLOG_LEVEL_INFO; 51static int log_on_stderr = 1; 52static int log_facility = LOG_AUTH; 53static char *argv0; 54 55extern char *__progname; 56 57/* textual representation of log-facilities/levels */ 58 59static struct { 60 const char *name; 61 SyslogFacility val; 62} log_facilities[] = { 63 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 64 { "USER", SYSLOG_FACILITY_USER }, 65 { "AUTH", SYSLOG_FACILITY_AUTH }, 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 77static 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 94SyslogFacility 95log_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 106LogLevel 107log_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 120void 121error(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 130void 131sigdie(const char *fmt,...) 132{ 133 va_list args; 134 135 va_start(args, fmt); 136 do_log(SYSLOG_LEVEL_FATAL, fmt, args); 137 va_end(args); 138 _exit(1); 139} 140 141 142/* Log this message (information that usually should go to the log). */ 143 144void 145logit(const char *fmt,...) 146{ 147 va_list args; 148 149 va_start(args, fmt); 150 do_log(SYSLOG_LEVEL_INFO, fmt, args); 151 va_end(args); 152} 153 154/* More detailed messages (information that does not need to go to the log). */ 155 156void 157verbose(const char *fmt,...) 158{ 159 va_list args; 160 161 va_start(args, fmt); 162 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 163 va_end(args); 164} 165 166/* Debugging messages that should not be logged during normal operation. */ 167 168void 169debug(const char *fmt,...) 170{ 171 va_list args; 172 173 va_start(args, fmt); 174 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 175 va_end(args); 176} 177 178void 179debug2(const char *fmt,...) 180{ 181 va_list args; 182 183 va_start(args, fmt); 184 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 185 va_end(args); 186} 187 188void 189debug3(const char *fmt,...) 190{ 191 va_list args; 192 193 va_start(args, fmt); 194 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 195 va_end(args); 196} 197 198/* 199 * Initialize the log. 200 */ 201 202void 203log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 204{ 205 argv0 = av0; 206 207 switch (level) { 208 case SYSLOG_LEVEL_QUIET: 209 case SYSLOG_LEVEL_FATAL: 210 case SYSLOG_LEVEL_ERROR: 211 case SYSLOG_LEVEL_INFO: 212 case SYSLOG_LEVEL_VERBOSE: 213 case SYSLOG_LEVEL_DEBUG1: 214 case SYSLOG_LEVEL_DEBUG2: 215 case SYSLOG_LEVEL_DEBUG3: 216 log_level = level; 217 break; 218 default: 219 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 220 (int) level); 221 exit(1); 222 } 223 224 log_on_stderr = on_stderr; 225 if (on_stderr) 226 return; 227 228 switch (facility) { 229 case SYSLOG_FACILITY_DAEMON: 230 log_facility = LOG_DAEMON; 231 break; 232 case SYSLOG_FACILITY_USER: 233 log_facility = LOG_USER; 234 break; 235 case SYSLOG_FACILITY_AUTH: 236 log_facility = LOG_AUTH; 237 break; 238 case SYSLOG_FACILITY_LOCAL0: 239 log_facility = LOG_LOCAL0; 240 break; 241 case SYSLOG_FACILITY_LOCAL1: 242 log_facility = LOG_LOCAL1; 243 break; 244 case SYSLOG_FACILITY_LOCAL2: 245 log_facility = LOG_LOCAL2; 246 break; 247 case SYSLOG_FACILITY_LOCAL3: 248 log_facility = LOG_LOCAL3; 249 break; 250 case SYSLOG_FACILITY_LOCAL4: 251 log_facility = LOG_LOCAL4; 252 break; 253 case SYSLOG_FACILITY_LOCAL5: 254 log_facility = LOG_LOCAL5; 255 break; 256 case SYSLOG_FACILITY_LOCAL6: 257 log_facility = LOG_LOCAL6; 258 break; 259 case SYSLOG_FACILITY_LOCAL7: 260 log_facility = LOG_LOCAL7; 261 break; 262 default: 263 fprintf(stderr, 264 "Unrecognized internal syslog facility code %d\n", 265 (int) facility); 266 exit(1); 267 } 268} 269 270#define MSGBUFSIZ 1024 271 272void 273do_log(LogLevel level, const char *fmt, va_list args) 274{ 275 struct syslog_data sdata = SYSLOG_DATA_INIT; 276 char msgbuf[MSGBUFSIZ]; 277 char fmtbuf[MSGBUFSIZ]; 278 char *txt = NULL; 279 int pri = LOG_INFO; 280 281 if (level > log_level) 282 return; 283 284 switch (level) { 285 case SYSLOG_LEVEL_FATAL: 286 if (!log_on_stderr) 287 txt = "fatal"; 288 pri = LOG_CRIT; 289 break; 290 case SYSLOG_LEVEL_ERROR: 291 if (!log_on_stderr) 292 txt = "error"; 293 pri = LOG_ERR; 294 break; 295 case SYSLOG_LEVEL_INFO: 296 pri = LOG_INFO; 297 break; 298 case SYSLOG_LEVEL_VERBOSE: 299 pri = LOG_INFO; 300 break; 301 case SYSLOG_LEVEL_DEBUG1: 302 txt = "debug1"; 303 pri = LOG_DEBUG; 304 break; 305 case SYSLOG_LEVEL_DEBUG2: 306 txt = "debug2"; 307 pri = LOG_DEBUG; 308 break; 309 case SYSLOG_LEVEL_DEBUG3: 310 txt = "debug3"; 311 pri = LOG_DEBUG; 312 break; 313 default: 314 txt = "internal error"; 315 pri = LOG_ERR; 316 break; 317 } 318 if (txt != NULL) { 319 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 320 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 321 } else { 322 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 323 } 324 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL); 325 if (log_on_stderr) { 326 snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); 327 write(STDERR_FILENO, msgbuf, strlen(msgbuf)); 328 } else { 329 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 330 syslog_r(pri, &sdata, "%.500s", fmtbuf); 331 closelog_r(&sdata); 332 } 333} 334