/* Copyright (C) 2008 Andreas Baumann This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "log/log.h" #include "log/messages.h" /* for i18n */ #include "port/stdio.h" /* for vsnprintf, snprintf */ #include "port/string.h" /* for strcmp, strerror_r, strlen, strlcat */ #include "port/time.h" /* for localtime_r, strftime, time * time_t, struct tm */ #include "port/stdlib.h" /* for abort, itoa */ #include "port/unused.h" /* for WOLF_UNUSED */ #define DEFAULT_TEXT_DOMAIN "libwolf" #include "i18n/gettext.h" /* for i18n */ #include /* for variable arguments */ #include /* for errno */ #include /* for assertions */ #if defined HAVE_SYSLOG_H #include /* for syslog, closelog and levels */ #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG #define WIN32_MEAN_AND_LEAN #include #endif /* defined HAVE_EVENTLOG */ #if defined HAVE_SYSLOG_H const char *wolf_log_syslog_facility_to_str( wolf_log_syslog_facility_t facility ) { switch( facility ) { /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_KERN: return "KERN"; case WOLF_LOG_USER: return "USER"; case WOLF_LOG_MAIL: return "MAIL"; case WOLF_LOG_DAEMON: return "DAEMON"; case WOLF_LOG_AUTH: return "AUTH"; case WOLF_LOG_SYSLOG: return "SYSLOG"; case WOLF_LOG_LPR: return "LPR"; case WOLF_LOG_NEWS: return "NEWS"; case WOLF_LOG_UUCP: return "UUCP"; case WOLF_LOG_CRON: return "CRON"; #if defined LOG_AUTHPRIV /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_AUTHPRIV: return "AUTHPRIV"; #else case WOLF_LOG_AUTHPRIV: return ""; #endif #if defined LOG_FTP /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_FTP: return "FTP"; #else case WOLF_LOG_FTP: return ""; #endif #if defined LOG_NTP /* FreeBSD */ case WOLF_LOG_NTP: return "NTP"; #else case WOLF_LOG_NTP: return ""; #endif #if defined LOG_SECURITY /* FreeBSD */ case WOLF_LOG_SECURITY: return "SECURITY"; #else case WOLF_LOG_SECURITY: return ""; #endif #if defined LOG_CONSOLE /* FreeBSD */ case WOLF_LOG_CONSOLE: return "CONSOLE"; #else case WOLF_LOG_CONSOLE: return ""; #endif #if defined LOG_AUDIT /* Solaris 10 */ case WOLF_LOG_AUDIT: return "AUDIT"; #else case WOLF_LOG_AUDIT: return ""; #endif case WOLF_LOG_LOCAL0: return "LOCAL0"; case WOLF_LOG_LOCAL1: return "LOCAL1"; case WOLF_LOG_LOCAL2: return "LOCAL2"; case WOLF_LOG_LOCAL3: return "LOCAL3"; case WOLF_LOG_LOCAL4: return "LOCAL4"; case WOLF_LOG_LOCAL5: return "LOCAL5"; case WOLF_LOG_LOCAL6: return "LOCAL6"; case WOLF_LOG_LOCAL7: return "LOCAL7"; default: return ""; } } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_SYSLOG_H wolf_log_syslog_facility_t wolf_log_str_to_syslog_facility( const char *facility ) { if( strcmp( facility, "KERN" ) == 0 ) return WOLF_LOG_KERN; if( strcmp( facility, "USER" ) == 0 ) return WOLF_LOG_USER; if( strcmp( facility, "MAIL" ) == 0 ) return WOLF_LOG_MAIL; if( strcmp( facility, "DAEMON" ) == 0 ) return WOLF_LOG_DAEMON; if( strcmp( facility, "AUTH" ) == 0 ) return WOLF_LOG_AUTH; if( strcmp( facility, "SYSLOG" ) == 0 ) return WOLF_LOG_SYSLOG; if( strcmp( facility, "LPR" ) == 0 ) return WOLF_LOG_LPR; if( strcmp( facility, "NEWS" ) == 0 ) return WOLF_LOG_NEWS; if( strcmp( facility, "UUCP" ) == 0 ) return WOLF_LOG_UUCP; if( strcmp( facility, "CRON" ) == 0 ) return WOLF_LOG_CRON; if( strcmp( facility, "AUTHPRIV" ) == 0 ) return WOLF_LOG_AUTHPRIV; if( strcmp( facility, "FTP" ) == 0 ) return WOLF_LOG_FTP; if( strcmp( facility, "NTP" ) == 0 ) return WOLF_LOG_NTP; if( strcmp( facility, "SECURITY" ) == 0 ) return WOLF_LOG_SECURITY; if( strcmp( facility, "CONSOLE" ) == 0 ) return WOLF_LOG_CONSOLE; if( strcmp( facility, "AUDIT" ) == 0 ) return WOLF_LOG_AUDIT; if( strcmp( facility, "LOCAL0" ) == 0 ) return WOLF_LOG_LOCAL0; if( strcmp( facility, "LOCAL1" ) == 0 ) return WOLF_LOG_LOCAL1; if( strcmp( facility, "LOCAL2" ) == 0 ) return WOLF_LOG_LOCAL2; if( strcmp( facility, "LOCAL3" ) == 0 ) return WOLF_LOG_LOCAL3; if( strcmp( facility, "LOCAL4" ) == 0 ) return WOLF_LOG_LOCAL4; if( strcmp( facility, "LOCAL5" ) == 0 ) return WOLF_LOG_LOCAL5; if( strcmp( facility, "LOCAL6" ) == 0 ) return WOLF_LOG_LOCAL6; if( strcmp( facility, "LOCAL7" ) == 0 ) return WOLF_LOG_LOCAL7; /* this is a seasonable default if nothing else exists */ return WOLF_LOG_DAEMON; } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_SYSLOG_H bool wolf_log_platform_has_syslog_facility( wolf_log_syslog_facility_t facility ) { switch( facility ) { /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_KERN: case WOLF_LOG_USER: case WOLF_LOG_MAIL: case WOLF_LOG_DAEMON: case WOLF_LOG_AUTH: case WOLF_LOG_SYSLOG: case WOLF_LOG_LPR: case WOLF_LOG_NEWS: case WOLF_LOG_UUCP: case WOLF_LOG_CRON: case WOLF_LOG_LOCAL0: case WOLF_LOG_LOCAL1: case WOLF_LOG_LOCAL2: case WOLF_LOG_LOCAL3: case WOLF_LOG_LOCAL4: case WOLF_LOG_LOCAL5: case WOLF_LOG_LOCAL6: case WOLF_LOG_LOCAL7: return true; #if defined LOG_AUTHPRIV /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_AUTHPRIV: return true; #else case WOLF_LOG_AUTHPRIV: return false; #endif #if defined LOG_FTP /* Linux, FreeBSD, OpenBSD, NetBSD */ case WOLF_LOG_FTP: return true; #else case WOLF_LOG_FTP: return false; #endif #if defined LOG_NTP /* FreeBSD */ case WOLF_LOG_NTP: return true; #else case WOLF_LOG_NTP: return false; #endif #if defined LOG_SECURITY /* FreeBSD */ case WOLF_LOG_SECURITY: return true; #else case WOLF_LOG_SECURITY: return false; #endif #if defined LOG_CONSOLE /* FreeBSD */ case WOLF_LOG_CONSOLE: return true; #else case WOLF_LOG_CONSOLE: return false; #endif #if defined LOG_AUDIT /* Solaris 10 */ case WOLF_LOG_AUDIT: return true; #else case WOLF_LOG_AUDIT: return false; #endif } return false; } #endif /* defined HAVE_SYSLOG_H */ wolf_log_level_t wolf_log_str_to_level( const char *level ) { if( strcmp( level, "EMERG" ) == 0 ) return WOLF_LOG_EMERG; if( strcmp( level, "ALERT" ) == 0 ) return WOLF_LOG_ALERT; if( strcmp( level, "CRIT" ) == 0 ) return WOLF_LOG_CRIT; if( strcmp( level, "ERR" ) == 0 ) return WOLF_LOG_ERR; if( strcmp( level, "WARNING" ) == 0 ) return WOLF_LOG_WARNING; if( strcmp( level, "NOTICE" ) == 0 ) return WOLF_LOG_NOTICE; if( strcmp( level, "INFO" ) == 0 ) return WOLF_LOG_INFO; if( strcmp( level, "DEBUG" ) == 0 ) return WOLF_LOG_DEBUG; if( strcmp( level, "DEBUG1" ) == 0 ) return WOLF_LOG_DEBUG1; if( strcmp( level, "DEBUG2" ) == 0 ) return WOLF_LOG_DEBUG2; if( strcmp( level, "DEBUG3" ) == 0 ) return WOLF_LOG_DEBUG3; if( strcmp( level, "DEBUG4" ) == 0 ) return WOLF_LOG_DEBUG4; if( strcmp( level, "DEBUG5" ) == 0 ) return WOLF_LOG_DEBUG5; return WOLF_LOG_EMERG; } #if defined HAVE_SYSLOG_H static int map_log_to_syslog_level( wolf_log_level_t level ) { switch( level ) { case WOLF_LOG_EMERG: return LOG_EMERG; case WOLF_LOG_ALERT: return LOG_ALERT; case WOLF_LOG_CRIT: return LOG_CRIT; case WOLF_LOG_ERR: return LOG_ERR; case WOLF_LOG_WARNING: return LOG_WARNING; case WOLF_LOG_NOTICE: return LOG_NOTICE; case WOLF_LOG_INFO: return LOG_INFO; case WOLF_LOG_DEBUG: case WOLF_LOG_DEBUG1: case WOLF_LOG_DEBUG2: case WOLF_LOG_DEBUG3: case WOLF_LOG_DEBUG4: case WOLF_LOG_DEBUG5: return LOG_DEBUG; default: return LOG_EMERG; } } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG /* TODO: logging of audit success/fail and how to map this to the * upper layer (so on Unix things can also go to LOG_SECURITY or * LOG_AUDIT on special Unixes. But for this we have to read a * log first! */ static WORD wolf_log_level_to_eventlog_type( wolf_log_level_t level ) { switch( level ) { case WOLF_LOG_EMERG: case WOLF_LOG_ALERT: case WOLF_LOG_CRIT: case WOLF_LOG_ERR: return EVENTLOG_ERROR_TYPE; case WOLF_LOG_WARNING: return EVENTLOG_WARNING_TYPE; case WOLF_LOG_NOTICE: case WOLF_LOG_INFO: case WOLF_LOG_DEBUG: case WOLF_LOG_DEBUG1: case WOLF_LOG_DEBUG2: case WOLF_LOG_DEBUG3: case WOLF_LOG_DEBUG4: case WOLF_LOG_DEBUG5: return EVENTLOG_INFORMATION_TYPE; default: return -1; } } /* Values are 32 bit values layed out as follows: 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +---+-+-+-----------------------+-------------------------------+ |Sev|C|R| Facility | Code | +---+-+-+-----------------------+-------------------------------+ 1 1 0 0 where Sev - is the severity code 00 - Success 01 - Informational 10 - Warning 11 - Error C - is the Customer code flag R - is a reserved bit Facility - is the facility code Code - is the facility's status code Define the facility codes SeverityNames = ( Success = 0x0 : STATUS_SEVERITY_SUCCESS Informational = 0x1 : STATUS_SEVERITY_INFORMATIONAL Warning = 0x2 : STATUS_SEVERITY_WARNING Error = 0x4 : STATUS_SEVERITY_ERROR ) ;we get a already defined message? but where is Application defined? ;// facility names ;FacilityNames = ( ; System = 0x0FF ; Application = 0xFFF ;) */ static DWORD wolf_log_category_to_eventlog_category( int category_id ) { return( category_id | 0x0FFF0000L ); } static DWORD wolf_log_event_id_to_eventlog_event_id( WORD severity, int message_id ) { DWORD id; /* no clue, why the bitmask has to differ from the EVENTLOG_xxx * constants, but so it is.. * * 00 - Success 0 * 01 - Informational 4 * 10 - Warning 2 * 11 - Error 1 */ int s = 0; switch( severity ) { case EVENTLOG_ERROR_TYPE: s = 3; break; case EVENTLOG_WARNING_TYPE: s = 2; break; case EVENTLOG_INFORMATION_TYPE: s = 1; break; } return( message_id | 0x0FFF0000L | ( s << 30 ) ); } #endif /* defined HAVE_EVENTLOG */ #if defined HAVE_SYSLOG_H static int map_log_facility_to_syslog_facility( int facility ) { switch( facility ) { case WOLF_LOG_KERN: return LOG_KERN; case WOLF_LOG_USER: return LOG_USER; case WOLF_LOG_MAIL: return LOG_MAIL; case WOLF_LOG_DAEMON: return LOG_DAEMON; case WOLF_LOG_AUTH: return LOG_AUTH; case WOLF_LOG_SYSLOG: return LOG_SYSLOG; case WOLF_LOG_LPR: return LOG_LPR; case WOLF_LOG_NEWS: return LOG_NEWS; case WOLF_LOG_UUCP: return LOG_UUCP; case WOLF_LOG_CRON: return LOG_CRON; #if defined LOG_AUTHPRIV case WOLF_LOG_AUTHPRIV: return LOG_AUTHPRIV; #else case WOLF_LOG_AUTHPRIV: return LOG_DAEMON; #endif #if defined LOG_FTP case WOLF_LOG_FTP: return LOG_FTP; #else case WOLF_LOG_FTP: return LOG_DAEMON; #endif #if defined LOG_NTP case WOLF_LOG_NTP: return LOG_NTP; #else case WOLF_LOG_NTP: return LOG_DAEMON; #endif #if defined LOG_SECURITY case WOLF_LOG_SECURITY: return LOG_SECURITY; #else case WOLF_LOG_SECURITY: return LOG_DAEMON; #endif #if defined LOG_CONSOLE case WOLF_LOG_CONSOLE: return LOG_CONSOLE; #else case WOLF_LOG_CONSOLE: return LOG_DAEMON; #endif #if defined LOG_AUDIT case WOLF_LOG_AUDIT: return LOG_AUDIT; #else case WOLF_LOG_AUDIT: return LOG_DAEMON; #endif case WOLF_LOG_LOCAL0: return LOG_LOCAL0; case WOLF_LOG_LOCAL1: return LOG_LOCAL1; case WOLF_LOG_LOCAL2: return LOG_LOCAL2; case WOLF_LOG_LOCAL3: return LOG_LOCAL3; case WOLF_LOG_LOCAL4: return LOG_LOCAL4; case WOLF_LOG_LOCAL5: return LOG_LOCAL5; case WOLF_LOG_LOCAL6: return LOG_LOCAL6; case WOLF_LOG_LOCAL7: return LOG_LOCAL7; default: return LOG_DAEMON; } } #endif /* defined HAVE_SYSLOG_H */ const char *wolf_log_level_to_str( wolf_log_level_t level ) { switch( level ) { case WOLF_LOG_EMERG: return "EMERG"; case WOLF_LOG_ALERT: return "ALERT"; case WOLF_LOG_CRIT: return "CRIT"; case WOLF_LOG_ERR: return "ERR"; case WOLF_LOG_WARNING: return "WARNING"; case WOLF_LOG_NOTICE: return "NOTICE"; case WOLF_LOG_INFO: return "INFO"; case WOLF_LOG_DEBUG: return "DEBUG"; case WOLF_LOG_DEBUG1: return "DEBUG1"; case WOLF_LOG_DEBUG2: return "DEBUG2"; case WOLF_LOG_DEBUG3: return "DEBUG3"; case WOLF_LOG_DEBUG4: return "DEBUG4"; case WOLF_LOG_DEBUG5: return "DEBUG5"; default: return ""; } } static const char *log_logfile_filename; static FILE *log_file = NULL; static wolf_log_level_t log_logfile_level; static wolf_log_level_t log_stderr_level; #if defined HAVE_SYSLOG_H static const char *syslog_ident; static int syslog_facility; static int syslog_level; static int syslog_options; #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG static HANDLE event_source = 0; static int eventlog_level; static const char *eventlog_server; static const char *eventlog_log; static const char *eventlog_source; static PSID sid = NULL; #endif /* defined HAVE_EVENTLOG */ void wolf_log_openlogtofile( const char *filename, wolf_log_level_t level ) { log_logfile_filename = filename; log_logfile_level = level; wolf_log_reopenlogtofile( ); } #if defined HAVE_SYSLOG_H static int map_log_options_to_syslog_options( int opts ) { int syslog_opts = LOG_NDELAY; if( ( opts & WOLF_LOG_SYSLOG_PID ) == WOLF_LOG_SYSLOG_PID ) { syslog_opts |= LOG_PID; } if( ( opts & WOLF_LOG_SYSLOG_CONS ) == WOLF_LOG_SYSLOG_CONS ) { syslog_opts |= LOG_CONS; } return syslog_opts; } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_SYSLOG_H void wolf_log_openlogtosyslog( const char *ident, wolf_log_syslog_facility_t facility, wolf_log_level_t level, int options ) { syslog_ident = ident; syslog_facility = map_log_facility_to_syslog_facility( facility ); syslog_level = map_log_to_syslog_level( level ); syslog_options = map_log_options_to_syslog_options( options ); openlog( ident, LOG_CONS | LOG_NDELAY, facility ); setlogmask( LOG_UPTO( level ) ); } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG static void registry_set_expandable_string( HKEY h, TCHAR *name, TCHAR *value ) { RegSetValueEx( h, name, 0, REG_EXPAND_SZ, (LPBYTE)value, strlen( value ) ); } static void registry_set_word( HKEY h, TCHAR *name, DWORD value ) { RegSetValueEx( h, name, 0, REG_DWORD, (LPBYTE)&value, sizeof( DWORD ) ); } static void register_event_source( const char *log, const char *source, const char *path_to_dll, int nof_categories ) { char key[256]; HKEY h = 0; DWORD disposition; /* compose the registry key and simply overwrite the values there, we know */ snprintf( key, 256, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s", log, source ); RegCreateKeyEx( HKEY_LOCAL_MACHINE, key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &h, &disposition ); /* make sure not to have hard-coded pathes here, otherwise remote * event logging will not work! */ registry_set_expandable_string( h, "EventMessageFile", (char *)path_to_dll ); registry_set_expandable_string( h, "CategoryMessageFile", (char *)path_to_dll ); registry_set_word( h, "TypesSupported", (DWORD)7 ); registry_set_word( h, "CategoryCount", (DWORD)nof_categories ); RegCloseKey( h ); } static PSID get_current_sid( void ) { HANDLE process = NULL; HANDLE token = NULL; DWORD token_user_size = 0; PTOKEN_USER token_user; PSID token_sid = NULL; DWORD sid_size = 0; PSID sid = NULL; /* get the token for the current process */ process = GetCurrentProcess( ); if( process == NULL ) { fprintf( stderr, "%s: Unable to get current process handle\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); abort( ); } if( !OpenProcessToken( process, TOKEN_QUERY, &token ) ) { fprintf( stderr, "%s: Unable to get process token of current process\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); abort( ); } /* get the required size to store the user token and allocate memory for it */ (void)GetTokenInformation( token, TokenUser, NULL, 0, &token_user_size ); token_user = (PTOKEN_USER)malloc( token_user_size * sizeof( BYTE ) ); if( token_user == NULL ) { fprintf( stderr, "%s: Unable to get memory to store user token\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); CloseHandle( token ); abort( ); } /* get the user token */ if( !GetTokenInformation( token, TokenUser, (LPVOID)token_user, token_user_size, &token_user_size ) ) { fprintf( stderr, "%s: Unable to get user token\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); free( token_user ); CloseHandle( token ); abort( ); } /* finally we made our way to the SID. Make a local copy of it because it and return that one */ token_sid = (PSID)token_user->User.Sid; sid_size = GetLengthSid( token_sid ); sid = (PSID)malloc( sid_size ); if( sid != NULL ) { if( !CopySid( sid_size, sid, token_sid ) ) { fprintf( stderr, "%s: Unable to make a copy of the current SID\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); free( sid ); free( token_user ); CloseHandle( token ); abort( ); } } /* process handle is a pseudo handle which doesn't need closing */ free( token_user ); CloseHandle( token ); return sid; } /* FIXME: those two functions are really bad and must be fixed together * with a POSIX-positional C-sprintf. For now we should be careful that * we log simple things.. */ static int compute_nof_placeholders( const char *format ) { const char *c; int nof_placeholders; for( c = format, nof_placeholders = 0; *c != '\0'; c++ ) if( *c == '%' && *(c+1) != '%' ) nof_placeholders++; return nof_placeholders; } static void map_placeholders_to_strings( char **msg_arr, const char *format, va_list ap ) { const char *c; int field; int i; int size; char *s; for( c = format, field = 0; *c != '\0'; c++ ) { if( *c == '%' && *(c+1) != '%' ) { switch( *(c+1) ) { case 'd': i = va_arg( ap, int ); msg_arr[field] = (char *)malloc( 20 ); snprintf( msg_arr[field], 20, "%d", i ); field++; break; case 's': s = va_arg( ap, char * ); msg_arr[field] = (char *)malloc( 512 ); snprintf( msg_arr[field], 512, "%s", s ); field++; break; } c++; } } } void wolf_log_openlogtoeventlog( const char *server, const char *log, const char *source, const char *path_to_dll, int nof_categories, wolf_log_level_t level ) { eventlog_server = server; eventlog_log = log; eventlog_source = source; eventlog_level = level; /* fiddle in the registry and register the location of the * message DLL, how many categories we define and what types * of events we are supporting */ register_event_source( log, source, path_to_dll, nof_categories ); /* for logging the user of the process into the event log */ sid = get_current_sid( ); /* TODO: remote machine and event log source should be in the API, * but we have Windows localized strings which are hard to unify * with Unix. We also don't want to have a stupid string wrapper * on top.. No clue for now */ event_source = RegisterEventSource( server, source ); if( event_source == NULL ) { /* TODO: add GetLastError here! */ fprintf( stderr, "%s: Unable to register event source\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); } } #endif /* defined HAVE_EVENTLOG */ void wolf_log_openlogtostderr( wolf_log_level_t level ) { log_stderr_level = level; } void wolf_log_closelogtofile( void ) { if( log_file != NULL ) { fclose( log_file ); log_file = NULL; } } #if defined HAVE_SYSLOG_H void wolf_log_closelogtosyslog( void ) { closelog( ); } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG void wolf_log_closelogtoeventlog( void ) { if( sid != NULL ) { free( sid ); sid = NULL; } if( !DeregisterEventSource( event_source ) ) { /* TODO: add GetLastError here! */ fprintf( stderr, "%s: Unable to deregister event source handle\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); } } #endif /* defined HAVE_EVENTLOG */ void wolf_log_closelogtostderr( void ) { /* do nothing here */ } void wolf_log_reopenlogtofile( void ) { if( log_file != NULL ) { fclose( log_file ); } log_file = fopen( log_logfile_filename, "a" ); if( log_file == NULL ) { char errmsg[255]; strerror_r( errno, errmsg, 255 ); fprintf( stderr, "%s: Unable to open logfile '%s': %s\n", wolf_log_level_to_str( WOLF_LOG_ALERT ), log_logfile_filename, errmsg ); } } #if defined HAVE_SYSLOG_H void wolf_log_reopenlogtosyslog( void ) { openlog( syslog_ident, syslog_options, syslog_facility ); setlogmask( LOG_UPTO( syslog_level ) ); } #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG void wolf_log_reopenlogtoeventlog( void ) { /* TODO: close and open? */ } #endif /* defined HAVE_EVENTLOG */ static void wolf_log_ap( wolf_log_level_t level, int category_id, int message_id, const char *format, va_list ap ); void wolf_log( wolf_log_level_t level, int category_id, int message_id, const char *format, ... ) { va_list ap; va_start( ap, format ); wolf_log_ap( level, category_id, message_id, format, ap ); va_end( ap ); } static void wolf_log_ap( wolf_log_level_t level, int category_id, int message_id, const char *format, va_list ap ) { char s[1024]; vsnprintf( s, 1024, format, ap ); if( level <= log_stderr_level ) fprintf( stderr, "%s: %s\n",wolf_log_level_to_str( level ), s ); if( level <= log_logfile_level && log_file != NULL ) { time_t t; struct tm local_time; char date_str[100]; time( &t ); assert( t >= 0 ); /* actually the only error known is an illegal buffer */ if( localtime_r( &t, &local_time ) == NULL ) { char errmsg[512]; strerror_r( errno, errmsg, 512 ); fprintf( stderr, _( "%s: localtime_r failed: %s\n" ), wolf_log_level_to_str( WOLF_LOG_ALERT ), errmsg ); abort( ); } strftime( date_str, 100, "%b %d %H:%M:%S", &local_time ); fprintf( log_file, "%s %s %d-%d: %s\n", date_str, wolf_log_level_to_str( level ), category_id, message_id, s ); fflush( log_file ); } #if defined HAVE_SYSLOG_H syslog( map_log_to_syslog_level( level ), "%s", s ); #endif /* defined HAVE_SYSLOG_H */ #if defined HAVE_EVENTLOG if( level <= eventlog_level && event_source != 0 ) { /* parse C-snprintf-like format string, map the placeholders * there to normal strings, then add them to a string array */ int nof_placeholders = compute_nof_placeholders( format ); LPSTR *msg_arr = (LPSTR *)malloc( sizeof( LPCTSTR ) * nof_placeholders ); map_placeholders_to_strings( msg_arr, format, ap ); if( !ReportEvent( event_source, /* event source handle */ wolf_log_level_to_eventlog_type( level ), wolf_log_category_to_eventlog_category( category_id ), wolf_log_event_id_to_eventlog_event_id( wolf_log_level_to_eventlog_type( level ), message_id ), sid, /* the security identifier */ nof_placeholders, /* at the moment only one string */ 0, /* no binary raw data */ msg_arr, /* the array of strings */ NULL /* no binary raw data */ ) ) { /* TODO: add GetLastError here! */ fprintf( stderr, "%s: Unable to log to event log\n", wolf_log_level_to_str( WOLF_LOG_ALERT ) ); } free( (LPSTR *)msg_arr ); } #endif /* defined HAVE_EVENTLOG */ }