log.c revision 3109:393fae270b2d
11556Srgrimes/* 21556Srgrimes * Author: Tatu Ylonen <ylo@cs.hut.fi> 31556Srgrimes * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 41556Srgrimes * All rights reserved 51556Srgrimes * 61556Srgrimes * As far as I am concerned, the code I have written for this software 71556Srgrimes * can be used freely for any purpose. Any derived versions of this 81556Srgrimes * software must be clearly marked as such, and if the derived work is 91556Srgrimes * incompatible with the protocol description in the RFC file, it must be 101556Srgrimes * called by a name other than "ssh" or "Secure Shell". 111556Srgrimes */ 121556Srgrimes/* 131556Srgrimes * Copyright (c) 2000 Markus Friedl. All rights reserved. 141556Srgrimes * 151556Srgrimes * Redistribution and use in source and binary forms, with or without 161556Srgrimes * modification, are permitted provided that the following conditions 171556Srgrimes * are met: 181556Srgrimes * 1. Redistributions of source code must retain the above copyright 191556Srgrimes * notice, this list of conditions and the following disclaimer. 201556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 211556Srgrimes * notice, this list of conditions and the following disclaimer in the 221556Srgrimes * documentation and/or other materials provided with the distribution. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 251556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 261556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 271556Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 281556Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 291556Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30114433Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 311556Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3227959Ssteve * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 331556Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 341556Srgrimes */ 3527964Ssteve/* 3627964Ssteve * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3727964Ssteve * Use is subject to license terms. 3827964Ssteve */ 39114433Sobrien 4027964Ssteve#include "includes.h" 4199110SobrienRCSID("$OpenBSD: log.c,v 1.24 2002/07/19 15:43:33 markus Exp $"); 4299110Sobrien 431556Srgrimes#pragma ident "%Z%%M% %I% %E% SMI" 441556Srgrimes 4547584Skris#include "log.h" 4647584Skris#include "xmalloc.h" 471556Srgrimes 481556Srgrimes#include <atomic.h> 491556Srgrimes#include <syslog.h> 501556Srgrimes 511556Srgrimesstatic LogLevel log_level = SYSLOG_LEVEL_INFO; 5290644Simpstatic int log_on_stderr = 1; 5390644Simpstatic int log_facility = LOG_AUTH; 541556Srgrimesstatic char *argv0; 551556Srgrimes 561556Srgrimesextern char *__progname; 5750539Smharo 581556Srgrimesstatic const char *log_txt_prefix = ""; 591556Srgrimes 6050872Smharo/* textual representation of log-facilities/levels */ 61137009Sdelphij 627798Sachestatic struct { 63191670Simp const char *name; 641556Srgrimes SyslogFacility val; 6590110Simp} log_facilities[] = { 66137009Sdelphij { "DAEMON", SYSLOG_FACILITY_DAEMON }, 6790110Simp { "USER", SYSLOG_FACILITY_USER }, 68136113Sdes { "AUTH", SYSLOG_FACILITY_AUTH }, 6990110Simp#ifdef LOG_AUTHPRIV 70122409Sguido { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, 7190110Simp#endif 72191670Simp { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, 7390110Simp { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, 741556Srgrimes { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, 751556Srgrimes { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, 761556Srgrimes { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, 771556Srgrimes { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, 78136112Sdes { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, 791556Srgrimes { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, 80136112Sdes { NULL, SYSLOG_FACILITY_NOT_SET } 811556Srgrimes}; 821556Srgrimes 8390110Simpstatic struct { 841556Srgrimes const char *name; 85137009Sdelphij LogLevel val; 8654895Ssheldonh} log_levels[] = 871556Srgrimes{ 8854895Ssheldonh { "QUIET", SYSLOG_LEVEL_QUIET }, 8954895Ssheldonh { "FATAL", SYSLOG_LEVEL_FATAL }, 9054895Ssheldonh { "ERROR", SYSLOG_LEVEL_ERROR }, 9154895Ssheldonh { "NOTICE", SYSLOG_LEVEL_NOTICE }, 9254895Ssheldonh { "INFO", SYSLOG_LEVEL_INFO }, 9354895Ssheldonh { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, 9454895Ssheldonh { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, 9554895Ssheldonh { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, 9654895Ssheldonh { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, 9754895Ssheldonh { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, 9897533Stjr { NULL, SYSLOG_LEVEL_NOT_SET } 9954895Ssheldonh}; 10097533Stjr 10197533StjrSyslogFacility 10299858Stjrlog_facility_number(char *name) 10397533Stjr{ 10497533Stjr int i; 10597533Stjr 10654895Ssheldonh if (name != NULL) 10754895Ssheldonh for (i = 0; log_facilities[i].name; i++) 10820421Ssteve if (strcasecmp(log_facilities[i].name, name) == 0) 109137009Sdelphij return log_facilities[i].val; 1101556Srgrimes return SYSLOG_FACILITY_NOT_SET; 1111556Srgrimes} 1121556Srgrimes 1131556SrgrimesLogLevel 1141556Srgrimeslog_level_number(char *name) 1151556Srgrimes{ 1161556Srgrimes int i; 1171556Srgrimes 1181556Srgrimes if (name != NULL) 1191556Srgrimes for (i = 0; log_levels[i].name; i++) 1201556Srgrimes if (strcasecmp(log_levels[i].name, name) == 0) 1211556Srgrimes return log_levels[i].val; 122137009Sdelphij return SYSLOG_LEVEL_NOT_SET; 123137009Sdelphij} 124137009Sdelphij 1251556Srgrimesvoid 1261556Srgrimesset_log_txt_prefix(const char *txt) 1271556Srgrimes{ 1281556Srgrimes log_txt_prefix = txt; 1291556Srgrimes} 1301556Srgrimes 1311556Srgrimes/* Error messages that should be logged. */ 13250872Smharo 13350872Smharovoid 13450872Smharoerror(const char *fmt,...) 13520421Ssteve{ 13620421Ssteve va_list args; 13720421Ssteve 1381556Srgrimes va_start(args, fmt); 1391556Srgrimes do_log(SYSLOG_LEVEL_ERROR, fmt, args); 1401556Srgrimes va_end(args); 1411556Srgrimes} 1421556Srgrimes 1431556Srgrimesvoid 14444282Sjkhnotice(const char *fmt,...) 14544282Sjkh{ 146122409Sguido va_list args; 1471556Srgrimes 14844282Sjkh va_start(args, fmt); 1491556Srgrimes do_log(SYSLOG_LEVEL_NOTICE, fmt, args); 1501556Srgrimes va_end(args); 151136124Sdes} 152136124Sdes 1537798Sache/* Log this message (information that usually should go to the log). */ 1541556Srgrimes 155191670Simpvoid 15620421Sstevelog(const char *fmt,...) 15720421Ssteve{ 15820421Ssteve va_list args; 159137009Sdelphij 160137009Sdelphij va_start(args, fmt); 161137009Sdelphij do_log(SYSLOG_LEVEL_INFO, fmt, args); 162137009Sdelphij va_end(args); 16320421Ssteve} 16420421Ssteve 16520421Ssteve/* More detailed messages (information that does not need to go to the log). */ 16620421Ssteve 16720421Sstevevoid 16820421Ssteveverbose(const char *fmt,...) 1691556Srgrimes{ 1701556Srgrimes va_list args; 1711556Srgrimes 1721556Srgrimes va_start(args, fmt); 17390110Simp do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); 1741556Srgrimes va_end(args); 1751556Srgrimes} 1761556Srgrimes 1771556Srgrimes/* Debugging messages that should not be logged during normal operation. */ 17820421Ssteve 1797798Sachevoid 1801556Srgrimesdebug(const char *fmt,...) 1811556Srgrimes{ 1821556Srgrimes va_list args; 1831556Srgrimes 1841556Srgrimes va_start(args, fmt); 18520421Ssteve do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); 1861556Srgrimes va_end(args); 1871556Srgrimes} 1881556Srgrimes 1891556Srgrimesvoid 1901556Srgrimesdebug2(const char *fmt,...) 1911556Srgrimes{ 1921556Srgrimes va_list args; 19351230Sbde 19420421Ssteve va_start(args, fmt); 19520421Ssteve do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); 19620421Ssteve va_end(args); 19720421Ssteve} 198137639Sjkh 199137639Sjkhvoid 200137639Sjkhdebug3(const char *fmt,...) 20199744Sdillon{ 202137639Sjkh va_list args; 2031556Srgrimes 2041556Srgrimes va_start(args, fmt); 2051556Srgrimes do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); 2061556Srgrimes va_end(args); 2071556Srgrimes} 2081556Srgrimes 2091556Srgrimes/* Fatal cleanup */ 2101556Srgrimes 2111556Srgrimesstruct fatal_cleanup { 2121556Srgrimes struct fatal_cleanup *next; 2131556Srgrimes void (*proc) (void *); 2141556Srgrimes void *context; 2151556Srgrimes}; 216124041Skuriyama 217124041Skuriyamastatic struct fatal_cleanup *fatal_cleanups = NULL; 2181556Srgrimes 2191556Srgrimes/* Registers a cleanup function to be called by fatal() before exiting. */ 2201556Srgrimes 2211556Srgrimesvoid 2221556Srgrimesfatal_add_cleanup(void (*proc) (void *), void *context) 2231556Srgrimes{ 2241556Srgrimes struct fatal_cleanup *cu; 2251556Srgrimes 2261556Srgrimes cu = xmalloc(sizeof(*cu)); 2271556Srgrimes cu->proc = proc; 2281556Srgrimes cu->context = context; 22920421Ssteve cu->next = fatal_cleanups; 2301556Srgrimes fatal_cleanups = cu; 2311556Srgrimes} 2321556Srgrimes 2331556Srgrimes/* Removes a cleanup function to be called at fatal(). */ 2347798Sache 2357798Sachevoid 2367798Sachefatal_remove_cleanup(void (*proc) (void *context), void *context) 237193087Sjilles{ 2387798Sache struct fatal_cleanup **cup, *cu; 2397798Sache 2401556Srgrimes for (cup = &fatal_cleanups; *cup; cup = &cu->next) { 2411556Srgrimes cu = *cup; 2421556Srgrimes if (cu->proc == proc && cu->context == context) { 2431556Srgrimes *cup = cu->next; 2441556Srgrimes xfree(cu); 2451556Srgrimes return; 24620421Ssteve } 24720421Ssteve } 24820421Ssteve debug3("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx", 24920421Ssteve (u_long) proc, (u_long) context); 2501556Srgrimes} 2511556Srgrimes 2527798Sache/* Remove all cleanups, to be called after fork() */ 2537798Sachevoid 2547798Sachefatal_remove_all_cleanups(void) 2557798Sache{ 256193087Sjilles struct fatal_cleanup *cu, *next_cu; 2577798Sache 25853819Smharo for (cu = fatal_cleanups; cu; cu = next_cu) { 2597798Sache next_cu = cu->next; 2607798Sache xfree(cu); 2617798Sache } 2627798Sache 2637798Sache fatal_cleanups = NULL; 26420421Ssteve} 26520421Ssteve 26620421Ssteve/* Cleanup and exit. Make sure each cleanup is called only once. */ 26753819Smharovoid 26853819Smharofatal_cleanup(void) 26953819Smharo{ 27050872Smharo struct fatal_cleanup *cu, *next_cu; 27170219Sobrien static volatile u_int called = 0; 272191670Simp 273191670Simp if (atomic_cas_uint(&called, 0, 1) == 1) 274191670Simp exit(255); 275191670Simp /* Call cleanup functions. */ 276191670Simp for (cu = fatal_cleanups; cu; cu = next_cu) { 2771556Srgrimes next_cu = cu->next; 27850539Smharo debug("Calling cleanup 0x%lx(0x%lx)", 27920421Ssteve (u_long) cu->proc, (u_long) cu->context); 28020421Ssteve (*cu->proc) (cu->context); 28120421Ssteve } 28253819Smharo exit(255); 28353819Smharo} 28453819Smharo 28550872Smharo 28670219Sobrien/* 287191670Simp * Initialize the log. 288191670Simp */ 289191670Simp 290191670Simpvoid 291191670Simplog_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) 29220421Ssteve{ 29350539Smharo argv0 = av0; 29420421Ssteve 29520421Ssteve switch (level) { 296124041Skuriyama case SYSLOG_LEVEL_QUIET: 297124041Skuriyama case SYSLOG_LEVEL_FATAL: 298124041Skuriyama case SYSLOG_LEVEL_ERROR: 299124041Skuriyama case SYSLOG_LEVEL_NOTICE: 300124041Skuriyama case SYSLOG_LEVEL_INFO: 301124041Skuriyama case SYSLOG_LEVEL_VERBOSE: 302124041Skuriyama case SYSLOG_LEVEL_DEBUG1: 303124041Skuriyama case SYSLOG_LEVEL_DEBUG2: 30420421Ssteve case SYSLOG_LEVEL_DEBUG3: 3057798Sache log_level = level; 306122409Sguido break; 307122409Sguido default: 30853819Smharo fprintf(stderr, "Unrecognized internal syslog level code %d\n", 30953819Smharo (int) level); 31053819Smharo exit(1); 31150872Smharo } 31270219Sobrien 313191670Simp log_on_stderr = on_stderr; 314191670Simp if (on_stderr) 315191670Simp return; 316191670Simp 317191670Simp switch (facility) { 3187798Sache case SYSLOG_FACILITY_DAEMON: 31950539Smharo log_facility = LOG_DAEMON; 3207798Sache break; 3211556Srgrimes case SYSLOG_FACILITY_USER: 3227798Sache log_facility = LOG_USER; 3231556Srgrimes break; 3241556Srgrimes case SYSLOG_FACILITY_AUTH: 3251556Srgrimes log_facility = LOG_AUTH; 3261556Srgrimes break; 3271556Srgrimes#ifdef LOG_AUTHPRIV 328157770Smaxim case SYSLOG_FACILITY_AUTHPRIV: 3291556Srgrimes log_facility = LOG_AUTHPRIV; 3301556Srgrimes break; 3311556Srgrimes#endif 33290110Simp case SYSLOG_FACILITY_LOCAL0: 3331556Srgrimes log_facility = LOG_LOCAL0; 3341556Srgrimes break; 33520421Ssteve case SYSLOG_FACILITY_LOCAL1: 3361556Srgrimes log_facility = LOG_LOCAL1; 3371556Srgrimes break; 3381556Srgrimes case SYSLOG_FACILITY_LOCAL2: 3391556Srgrimes log_facility = LOG_LOCAL2; 3401556Srgrimes break; 3411556Srgrimes case SYSLOG_FACILITY_LOCAL3: 3421556Srgrimes log_facility = LOG_LOCAL3; 3431556Srgrimes break; 3441556Srgrimes case SYSLOG_FACILITY_LOCAL4: 34520421Ssteve log_facility = LOG_LOCAL4; 34620421Ssteve break; 34720421Ssteve case SYSLOG_FACILITY_LOCAL5: 34820421Ssteve log_facility = LOG_LOCAL5; 34920421Ssteve break; 35020421Ssteve case SYSLOG_FACILITY_LOCAL6: 35120421Ssteve log_facility = LOG_LOCAL6; 35220421Ssteve break; 3531556Srgrimes case SYSLOG_FACILITY_LOCAL7: 35420421Ssteve log_facility = LOG_LOCAL7; 35520421Ssteve break; 35620421Ssteve default: 3571556Srgrimes fprintf(stderr, 3581556Srgrimes "Unrecognized internal syslog facility code %d\n", 35920421Ssteve (int) facility); 36020421Ssteve exit(1); 3611556Srgrimes } 3621556Srgrimes} 3631556Srgrimes 3641556Srgrimes#define MSGBUFSIZ 1024 36520421Ssteve 3661556Srgrimes/* PRINTFLIKE2 */ 3677798Sachevoid 368163485Smaximdo_log(LogLevel level, const char *fmt, va_list args) 3697798Sache{ 3707798Sache char msgbuf[MSGBUFSIZ]; 371193087Sjilles char fmtbuf[MSGBUFSIZ]; 37253819Smharo char *txt = NULL; 37320421Ssteve int pri = LOG_INFO; 37420421Ssteve int do_gettext = log_on_stderr; /* 37520421Ssteve * Localize user messages - not 3767798Sache * syslog()ed messages. 3777798Sache */ 3787798Sache 379122409Sguido if (level > log_level) 380122409Sguido return; 3817798Sache 3827798Sache switch (level) { 3831556Srgrimes case SYSLOG_LEVEL_FATAL: 3841556Srgrimes if (!log_on_stderr) 3851556Srgrimes txt = "fatal"; 3861556Srgrimes pri = LOG_CRIT; 3871556Srgrimes break; 38853819Smharo case SYSLOG_LEVEL_ERROR: 38950539Smharo if (!log_on_stderr) 390191670Simp txt = "error"; 391191670Simp pri = LOG_ERR; 392191670Simp break; 393191670Simp case SYSLOG_LEVEL_NOTICE: 3941556Srgrimes pri = LOG_NOTICE; 3951556Srgrimes break; 3961556Srgrimes case SYSLOG_LEVEL_INFO: 3971556Srgrimes pri = LOG_INFO; 3981556Srgrimes break; 3991556Srgrimes case SYSLOG_LEVEL_VERBOSE: 4001556Srgrimes pri = LOG_INFO; 4011556Srgrimes break; 4021556Srgrimes case SYSLOG_LEVEL_DEBUG1: 4031556Srgrimes txt = "debug1"; 404102230Strhodes pri = LOG_DEBUG; 405102230Strhodes /* 4061556Srgrimes * Don't localize debug messages - such are not intended 4071556Srgrimes * for users but for support staff whose preferred 408122409Sguido * language is unknown, therefore we default to the 40990110Simp * language used in the source code: English. 4101556Srgrimes */ 4111556Srgrimes do_gettext = 0; 41247584Skris break; 4131556Srgrimes case SYSLOG_LEVEL_DEBUG2: 41447584Skris txt = "debug2"; 41547584Skris pri = LOG_DEBUG; 4161556Srgrimes do_gettext = 0; /* Don't localize debug messages. */ 4171556Srgrimes break; 4181556Srgrimes case SYSLOG_LEVEL_DEBUG3: 4191556Srgrimes txt = "debug3"; 4201556Srgrimes pri = LOG_DEBUG; 4211556Srgrimes do_gettext = 0; /* Don't localize debug messages. */ 4221556Srgrimes break; 4231556Srgrimes default: 424122409Sguido txt = "internal error"; 425163812Sdelphij pri = LOG_ERR; 426163777Sdelphij break; 427163777Sdelphij } 428163812Sdelphij if (txt != NULL) { 429163777Sdelphij snprintf(fmtbuf, sizeof(fmtbuf), "%s%s: %s", log_txt_prefix, 4301556Srgrimes do_gettext ? gettext(txt) : txt, 4311556Srgrimes do_gettext ? gettext(fmt) : fmt); 43247584Skris vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); 43347584Skris } else { 43447584Skris vsnprintf(msgbuf, sizeof(msgbuf), 43547584Skris do_gettext ? gettext(fmt) : fmt, 436122304Sbde args); 4371556Srgrimes } 4381556Srgrimes if (log_on_stderr) { 43947584Skris fprintf(stderr, "%s\r\n", msgbuf); 4401556Srgrimes } else { 44147584Skris openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); 4421556Srgrimes syslog(pri, "%.500s", msgbuf); 4431556Srgrimes closelog(); 4441556Srgrimes } 4451556Srgrimes} 4461556Srgrimes