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.29 2003/09/23 20:17:11 markus Exp $"); 38 39 #include "log.h" 40 #include "xmalloc.h" 41 42 #include <syslog.h> 43 #include <vis.h> 44 45 static LogLevel log_level = SYSLOG_LEVEL_INFO; 46 static int log_on_stderr = 1; 47 static int log_facility = LOG_AUTH; 48 static char *argv0; 49 50 extern char *__progname; 51 52 /* textual representation of log-facilities/levels */ 53 54 static struct { 55 const char *name; 56 SyslogFacility val; 57 } log_facilities[] = { 58 { "DAEMON", SYSLOG_FACILITY_DAEMON }, 59 { "USER", SYSLOG_FACILITY_USER }, 60 { "AUTH", SYSLOG_FACILITY_AUTH }, 61 { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 62 { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 63 { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 64 { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 65 { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 66 { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 67 { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 68 { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 69 { NULL, SYSLOG_FACILITY_NOT_SET } 70 }; 71 72 static struct { 73 const char *name; 74 LogLevel val; 75 } log_levels[] = 76 { 77 { "QUIET", SYSLOG_LEVEL_QUIET }, 78 { "FATAL", SYSLOG_LEVEL_FATAL }, 79 { "ERROR", SYSLOG_LEVEL_ERROR }, 80 { "INFO", SYSLOG_LEVEL_INFO }, 81 { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 82 { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 83 { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 84 { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 85 { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 86 { NULL, SYSLOG_LEVEL_NOT_SET } 87 }; 88 89 SyslogFacility 90 log_facility_number(char *name) 91 { 92 int i; 93 94 if (name != NULL) 95 for (i = 0; log_facilities[i].name; i++) 96 if (strcasecmp(log_facilities[i].name, name) == 0) 97 return log_facilities[i].val; 98 return SYSLOG_FACILITY_NOT_SET; 99 } 100 101 LogLevel 102 log_level_number(char *name) 103 { 104 int i; 105 106 if (name != NULL) 107 for (i = 0; log_levels[i].name; i++) 108 if (strcasecmp(log_levels[i].name, name) == 0) 109 return log_levels[i].val; 110 return SYSLOG_LEVEL_NOT_SET; 111 } 112 113 /* Error messages that should be logged. */ 114 115 void 116 error(const char *fmt,...) 117 { 118 va_list args; 119 120 va_start(args, fmt); 121 do_log(SYSLOG_LEVEL_ERROR, fmt, args); 122 va_end(args); 123 } 124 125 /* Log this message (information that usually should go to the log). */ 126 127 void 128 logit(const char *fmt,...) 129 { 130 va_list args; 131 132 va_start(args, fmt); 133 do_log(SYSLOG_LEVEL_INFO, fmt, args); 134 va_end(args); 135 } 136 137 /* More detailed messages (information that does not need to go to the log). */ 138 139 void 140 verbose(const char *fmt,...) 141 { 142 va_list args; 143 144 va_start(args, fmt); 145 do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 146 va_end(args); 147 } 148 149 /* Debugging messages that should not be logged during normal operation. */ 150 151 void 152 debug(const char *fmt,...) 153 { 154 va_list args; 155 156 va_start(args, fmt); 157 do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 158 va_end(args); 159 } 160 161 void 162 debug2(const char *fmt,...) 163 { 164 va_list args; 165 166 va_start(args, fmt); 167 do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 168 va_end(args); 169 } 170 171 void 172 debug3(const char *fmt,...) 173 { 174 va_list args; 175 176 va_start(args, fmt); 177 do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 178 va_end(args); 179 } 180 181 /* 182 * Initialize the log. 183 */ 184 185 void 186 log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 187 { 188 argv0 = av0; 189 190 switch (level) { 191 case SYSLOG_LEVEL_QUIET: 192 case SYSLOG_LEVEL_FATAL: 193 case SYSLOG_LEVEL_ERROR: 194 case SYSLOG_LEVEL_INFO: 195 case SYSLOG_LEVEL_VERBOSE: 196 case SYSLOG_LEVEL_DEBUG1: 197 case SYSLOG_LEVEL_DEBUG2: 198 case SYSLOG_LEVEL_DEBUG3: 199 log_level = level; 200 break; 201 default: 202 fprintf(stderr, "Unrecognized internal syslog level code %d\n", 203 (int) level); 204 exit(1); 205 } 206 207 log_on_stderr = on_stderr; 208 if (on_stderr) 209 return; 210 211 switch (facility) { 212 case SYSLOG_FACILITY_DAEMON: 213 log_facility = LOG_DAEMON; 214 break; 215 case SYSLOG_FACILITY_USER: 216 log_facility = LOG_USER; 217 break; 218 case SYSLOG_FACILITY_AUTH: 219 log_facility = LOG_AUTH; 220 break; 221 case SYSLOG_FACILITY_LOCAL0: 222 log_facility = LOG_LOCAL0; 223 break; 224 case SYSLOG_FACILITY_LOCAL1: 225 log_facility = LOG_LOCAL1; 226 break; 227 case SYSLOG_FACILITY_LOCAL2: 228 log_facility = LOG_LOCAL2; 229 break; 230 case SYSLOG_FACILITY_LOCAL3: 231 log_facility = LOG_LOCAL3; 232 break; 233 case SYSLOG_FACILITY_LOCAL4: 234 log_facility = LOG_LOCAL4; 235 break; 236 case SYSLOG_FACILITY_LOCAL5: 237 log_facility = LOG_LOCAL5; 238 break; 239 case SYSLOG_FACILITY_LOCAL6: 240 log_facility = LOG_LOCAL6; 241 break; 242 case SYSLOG_FACILITY_LOCAL7: 243 log_facility = LOG_LOCAL7; 244 break; 245 default: 246 fprintf(stderr, 247 "Unrecognized internal syslog facility code %d\n", 248 (int) facility); 249 exit(1); 250 } 251 } 252 253 #define MSGBUFSIZ 1024 254 255 void 256 do_log(LogLevel level, const char *fmt, va_list args) 257 { 258 struct syslog_data sdata = SYSLOG_DATA_INIT; 259 char msgbuf[MSGBUFSIZ]; 260 char fmtbuf[MSGBUFSIZ]; 261 char *txt = NULL; 262 int pri = LOG_INFO; 263 264 if (level > log_level) 265 return; 266 267 switch (level) { 268 case SYSLOG_LEVEL_FATAL: 269 if (!log_on_stderr) 270 txt = "fatal"; 271 pri = LOG_CRIT; 272 break; 273 case SYSLOG_LEVEL_ERROR: 274 if (!log_on_stderr) 275 txt = "error"; 276 pri = LOG_ERR; 277 break; 278 case SYSLOG_LEVEL_INFO: 279 pri = LOG_INFO; 280 break; 281 case SYSLOG_LEVEL_VERBOSE: 282 pri = LOG_INFO; 283 break; 284 case SYSLOG_LEVEL_DEBUG1: 285 txt = "debug1"; 286 pri = LOG_DEBUG; 287 break; 288 case SYSLOG_LEVEL_DEBUG2: 289 txt = "debug2"; 290 pri = LOG_DEBUG; 291 break; 292 case SYSLOG_LEVEL_DEBUG3: 293 txt = "debug3"; 294 pri = LOG_DEBUG; 295 break; 296 default: 297 txt = "internal error"; 298 pri = LOG_ERR; 299 break; 300 } 301 if (txt != NULL) { 302 snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); 303 vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 304 } else { 305 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); 306 } 307 strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL); 308 if (log_on_stderr) { 309 snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); 310 write(STDERR_FILENO, msgbuf, strlen(msgbuf)); 311 } else { 312 openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); 313 syslog_r(pri, &sdata, "%.500s", fmtbuf); 314 closelog_r(&sdata); 315 } 316 } 317