340 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***********************************************************************
 | |
|  * Copyright (c) 2009, Secure Endpoints Inc.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * - Redistributions of source code must retain the above copyright
 | |
|  *   notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  * - Redistributions in binary form must reproduce the above copyright
 | |
|  *   notice, this list of conditions and the following disclaimer in
 | |
|  *   the documentation and/or other materials provided with the
 | |
|  *   distribution.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
|  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | |
|  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | |
|  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | |
|  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | |
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | |
|  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 | |
|  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | |
|  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 | |
|  * OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  *
 | |
|  **********************************************************************/
 | |
| 
 | |
| /*
 | |
|  * Based on code by Alexander Yaworsky
 | |
|  */
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #include <roken.h>
 | |
| 
 | |
| #define SYSLOG_DGRAM_SIZE 1024
 | |
| 
 | |
| static BOOL        syslog_opened = FALSE;
 | |
| 
 | |
| static int         syslog_mask = 0xFF;
 | |
| static char        syslog_ident[ 128 ] = "";
 | |
| static int         syslog_facility = LOG_USER;
 | |
| static char        syslog_procid_str[ 20 ];
 | |
| 
 | |
| static SOCKADDR_IN syslog_hostaddr;
 | |
| static SOCKET      syslog_socket = INVALID_SOCKET;
 | |
| static char        local_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ];
 | |
| 
 | |
| static char        syslog_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ] = "localhost";
 | |
| static unsigned short syslog_port = SYSLOG_PORT;
 | |
| 
 | |
| static int   datagramm_size;
 | |
| 
 | |
| volatile BOOL initialized = FALSE;
 | |
| BOOL wsa_initialized = FALSE;
 | |
| CRITICAL_SECTION cs_syslog;
 | |
| 
 | |
| ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
 | |
| init_syslog(const char * hostname)
 | |
| {
 | |
|     WSADATA wsd;
 | |
|     char * service;
 | |
| 
 | |
|     if ( initialized )
 | |
|         return;
 | |
| 
 | |
|     if( WSAStartup( MAKEWORD( 2, 2 ), &wsd ) ) {
 | |
|         fprintf(stderr, "Can't initialize WinSock\n");
 | |
|         /* we let the rest of the initialization code go through,
 | |
|            although none of the syslog calls would succeed. */
 | |
|     } else {
 | |
|         wsa_initialized = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (hostname)
 | |
|         strcpy_s(syslog_hostname, sizeof(syslog_hostname), hostname);
 | |
|     else
 | |
|         strcpy_s(syslog_hostname, sizeof(syslog_hostname), "");
 | |
| 
 | |
|     service = strchr(syslog_hostname, ':');
 | |
| 
 | |
|     if (service) {
 | |
|         int tp;
 | |
| 
 | |
|         *service++ = '\0';
 | |
| 
 | |
|         if ((tp = atoi(service)) <= 0) {
 | |
|             struct servent * se;
 | |
| 
 | |
|             se = getservbyname(service, "udp");
 | |
| 
 | |
|             syslog_port = (se == NULL)? SYSLOG_PORT: se->s_port;
 | |
|         } else {
 | |
|             syslog_port = (unsigned short) tp;
 | |
|         }
 | |
|     } else {
 | |
|         syslog_port = SYSLOG_PORT;
 | |
|     }
 | |
| 
 | |
|     InitializeCriticalSection(&cs_syslog);
 | |
|     initialized = TRUE;
 | |
| 
 | |
|     atexit(exit_syslog);
 | |
| }
 | |
| 
 | |
| ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
 | |
| exit_syslog(void)
 | |
| {
 | |
|     if ( !initialized )
 | |
|         return;
 | |
| 
 | |
|     closelog();
 | |
| 
 | |
|     if ( wsa_initialized )
 | |
|         WSACleanup();
 | |
| 
 | |
|     DeleteCriticalSection(&cs_syslog);
 | |
|     initialized = FALSE;
 | |
| }
 | |
| 
 | |
| static void init_logger_addr()
 | |
| {
 | |
|     struct hostent * phe = NULL;
 | |
| 
 | |
|     memset( &syslog_hostaddr, 0, sizeof(SOCKADDR_IN) );
 | |
|     syslog_hostaddr.sin_family = AF_INET;
 | |
| 
 | |
|     if (syslog_hostname[0] == '\0')
 | |
|         goto use_default;
 | |
| 
 | |
|     phe = gethostbyname( syslog_hostname );
 | |
|     if( !phe )
 | |
|         goto use_default;
 | |
| 
 | |
|     memcpy( &syslog_hostaddr.sin_addr.s_addr, phe->h_addr, phe->h_length );
 | |
| 
 | |
|     syslog_hostaddr.sin_port = htons( syslog_port );
 | |
|     return;
 | |
| 
 | |
| use_default:
 | |
|     syslog_hostaddr.sin_addr.S_un.S_addr = htonl( 0x7F000001 );
 | |
|     syslog_hostaddr.sin_port = htons( SYSLOG_PORT );
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
|  * closelog
 | |
|  *
 | |
|  * Close desriptor used to write to system logger.
 | |
|  */
 | |
| ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
 | |
| closelog()
 | |
| {
 | |
|     if ( !initialized )
 | |
|         return;
 | |
| 
 | |
|     EnterCriticalSection(&cs_syslog);
 | |
|     if( syslog_opened ) {
 | |
|         closesocket( syslog_socket );
 | |
|         syslog_socket = INVALID_SOCKET;
 | |
|         syslog_opened = FALSE;
 | |
|     }
 | |
|     LeaveCriticalSection(&cs_syslog);
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
|  * openlog
 | |
|  *
 | |
|  * Open connection to system logger.
 | |
|  */
 | |
| ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
 | |
| openlog( char* ident, int option, int facility )
 | |
| {
 | |
|     BOOL failed = FALSE;
 | |
|     SOCKADDR_IN sa_local;
 | |
|     DWORD n;
 | |
|     int size;
 | |
| 
 | |
|     if ( !initialized )
 | |
|         return;
 | |
| 
 | |
|     EnterCriticalSection(&cs_syslog);
 | |
| 
 | |
|     if( syslog_opened )
 | |
|         goto done;
 | |
| 
 | |
|     failed = TRUE;
 | |
| 
 | |
|     syslog_facility = facility? facility : LOG_USER;
 | |
| 
 | |
|     if( option & LOG_PID )
 | |
|         sprintf_s( syslog_procid_str, sizeof(syslog_procid_str), "[%lu]", GetCurrentProcessId() );
 | |
|     else
 | |
|         syslog_procid_str[0] = '\0';
 | |
| 
 | |
|     /* FIXME: handle other options */
 | |
| 
 | |
|     n = sizeof(local_hostname);
 | |
|     if( !GetComputerName( local_hostname, &n ) )
 | |
|         goto done;
 | |
| 
 | |
|     syslog_socket = INVALID_SOCKET;
 | |
| 
 | |
|     init_logger_addr();
 | |
| 
 | |
|     for( n = 0;; n++ )
 | |
|     {
 | |
|         syslog_socket = socket( AF_INET, SOCK_DGRAM, 0 );
 | |
|         if( INVALID_SOCKET == syslog_socket )
 | |
|             goto done;
 | |
| 
 | |
|         memset( &sa_local, 0, sizeof(SOCKADDR_IN) );
 | |
|         sa_local.sin_family = AF_INET;
 | |
|         if( bind( syslog_socket, (SOCKADDR*) &sa_local, sizeof(SOCKADDR_IN) ) == 0 )
 | |
|             break;
 | |
|         rk_closesocket( syslog_socket );
 | |
|         syslog_socket = INVALID_SOCKET;
 | |
|         if( n == 100 )
 | |
|             goto done;
 | |
|         Sleep(0);
 | |
|     }
 | |
| 
 | |
|     /* get size of datagramm */
 | |
|     size = sizeof(datagramm_size);
 | |
|     if( getsockopt( syslog_socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*) &datagramm_size, &size ) )
 | |
|         goto done;
 | |
|     if( datagramm_size - strlen(local_hostname) - (ident? strlen(ident) : 0) < 64 )
 | |
|         goto done;
 | |
|     if( datagramm_size > SYSLOG_DGRAM_SIZE )
 | |
|         datagramm_size = SYSLOG_DGRAM_SIZE;
 | |
| 
 | |
|     if (ident)
 | |
|         strcpy_s(syslog_ident, sizeof(syslog_ident), ident);
 | |
| 
 | |
|     syslog_facility = (facility ? facility : LOG_USER);
 | |
|     failed = FALSE;
 | |
| 
 | |
|  done:
 | |
|     if( failed ) {
 | |
|         if( syslog_socket != INVALID_SOCKET )
 | |
|             rk_closesocket( syslog_socket );
 | |
|     }
 | |
|     syslog_opened = !failed;
 | |
| 
 | |
|     LeaveCriticalSection(&cs_syslog);
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
|  * setlogmask
 | |
|  *
 | |
|  * Set the log mask level.
 | |
|  */
 | |
| ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
 | |
| setlogmask( int mask )
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     if ( !initialized )
 | |
|         return 0;
 | |
| 
 | |
|     EnterCriticalSection(&cs_syslog);
 | |
| 
 | |
|     ret = syslog_mask;
 | |
|     if( mask )
 | |
|         syslog_mask = mask;
 | |
| 
 | |
|     LeaveCriticalSection(&cs_syslog);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
|  * syslog
 | |
|  *
 | |
|  * Generate a log message using FMT string and option arguments.
 | |
|  */
 | |
| ROKEN_LIB_FUNCTION void
 | |
| syslog( int pri, char* fmt, ... )
 | |
| {
 | |
|     va_list ap;
 | |
| 
 | |
|     va_start( ap, fmt );
 | |
|     vsyslog( pri, fmt, ap );
 | |
|     va_end( ap );
 | |
| }
 | |
| 
 | |
| /******************************************************************************
 | |
|  * vsyslog
 | |
|  *
 | |
|  * Generate a log message using FMT and using arguments pointed to by AP.
 | |
|  */
 | |
| ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
 | |
| vsyslog( int pri, char* fmt, va_list ap )
 | |
| {
 | |
|     static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 | |
|                             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 | |
|     char  datagramm[ SYSLOG_DGRAM_SIZE ];
 | |
|     SYSTEMTIME stm;
 | |
|     int len;
 | |
|     char *p;
 | |
| 
 | |
|     if ( !initialized )
 | |
|         return;
 | |
| 
 | |
|     EnterCriticalSection(&cs_syslog);
 | |
| 
 | |
|     if( !(LOG_MASK( LOG_PRI( pri )) & syslog_mask) )
 | |
|         goto done;
 | |
| 
 | |
|     openlog( NULL, 0, pri & LOG_FACMASK );
 | |
|     if( !syslog_opened )
 | |
|         goto done;
 | |
| 
 | |
|     if( !(pri & LOG_FACMASK) )
 | |
|         pri |= syslog_facility;
 | |
| 
 | |
|     GetLocalTime( &stm );
 | |
|     len = sprintf_s( datagramm, sizeof(datagramm),
 | |
|                      "<%d>%s %2d %02d:%02d:%02d %s %s%s: ",
 | |
|                      pri,
 | |
|                      month[ stm.wMonth - 1 ], stm.wDay, stm.wHour, stm.wMinute, stm.wSecond,
 | |
|                      local_hostname, syslog_ident, syslog_procid_str );
 | |
|     vsprintf_s( datagramm + len, datagramm_size - len, fmt, ap );
 | |
|     p = strchr( datagramm, '\n' );
 | |
|     if( p )
 | |
|         *p = 0;
 | |
|     p = strchr( datagramm, '\r' );
 | |
|     if( p )
 | |
|         *p = 0;
 | |
| 
 | |
|     sendto( syslog_socket, datagramm, strlen(datagramm), 0, (SOCKADDR*) &syslog_hostaddr, sizeof(SOCKADDR_IN) );
 | |
| 
 | |
|  done:
 | |
|     LeaveCriticalSection(&cs_syslog);
 | |
| }
 | |
| 
 | 
