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