Home | History | Annotate | Line # | Download | only in roken
      1 /*	$NetBSD: syslogc.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
      2 
      3 /***********************************************************************
      4  * Copyright (c) 2009, Secure Endpoints Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * - Redistributions of source code must retain the above copyright
     12  *   notice, this list of conditions and the following disclaimer.
     13  *
     14  * - Redistributions in binary form must reproduce the above copyright
     15  *   notice, this list of conditions and the following disclaimer in
     16  *   the documentation and/or other materials provided with the
     17  *   distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     30  * OF THE POSSIBILITY OF SUCH DAMAGE.
     31  *
     32  **********************************************************************/
     33 
     34 /*
     35  * Based on code by Alexander Yaworsky
     36  */
     37 
     38 #include <config.h>
     39 
     40 #include <krb5/roken.h>
     41 
     42 #define SYSLOG_DGRAM_SIZE 1024
     43 
     44 static BOOL        syslog_opened = FALSE;
     45 
     46 static int         syslog_mask = 0xFF;
     47 static char        syslog_ident[ 128 ] = "";
     48 static int         syslog_facility = LOG_USER;
     49 static char        syslog_procid_str[ 20 ];
     50 
     51 static SOCKADDR_IN syslog_hostaddr;
     52 static SOCKET      syslog_socket = INVALID_SOCKET;
     53 static char        local_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ];
     54 
     55 static char        syslog_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ] = "localhost";
     56 static unsigned short syslog_port = SYSLOG_PORT;
     57 
     58 static int   datagramm_size;
     59 
     60 volatile BOOL initialized = FALSE;
     61 BOOL wsa_initialized = FALSE;
     62 CRITICAL_SECTION cs_syslog;
     63 
     64 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
     65 init_syslog(const char * hostname)
     66 {
     67     WSADATA wsd;
     68     char * service;
     69 
     70     if ( initialized )
     71         return;
     72 
     73     if( WSAStartup( MAKEWORD( 2, 2 ), &wsd ) ) {
     74         fprintf(stderr, "Can't initialize WinSock\n");
     75         /* we let the rest of the initialization code go through,
     76            although none of the syslog calls would succeed. */
     77     } else {
     78         wsa_initialized = TRUE;
     79     }
     80 
     81     if (hostname)
     82         strcpy_s(syslog_hostname, sizeof(syslog_hostname), hostname);
     83     else
     84         strcpy_s(syslog_hostname, sizeof(syslog_hostname), "");
     85 
     86     service = strchr(syslog_hostname, ':');
     87 
     88     if (service) {
     89         int tp;
     90 
     91         *service++ = '\0';
     92 
     93         if ((tp = atoi(service)) <= 0) {
     94             struct servent * se;
     95 
     96             se = getservbyname(service, "udp");
     97 
     98             syslog_port = (se == NULL)? SYSLOG_PORT: se->s_port;
     99         } else {
    100             syslog_port = (unsigned short) tp;
    101         }
    102     } else {
    103         syslog_port = SYSLOG_PORT;
    104     }
    105 
    106     InitializeCriticalSection(&cs_syslog);
    107     initialized = TRUE;
    108 
    109     atexit(exit_syslog);
    110 }
    111 
    112 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    113 exit_syslog(void)
    114 {
    115     if ( !initialized )
    116         return;
    117 
    118     closelog();
    119 
    120     if ( wsa_initialized )
    121         WSACleanup();
    122 
    123     DeleteCriticalSection(&cs_syslog);
    124     initialized = FALSE;
    125 }
    126 
    127 static void init_logger_addr()
    128 {
    129     struct hostent * phe = NULL;
    130 
    131     memset( &syslog_hostaddr, 0, sizeof(SOCKADDR_IN) );
    132     syslog_hostaddr.sin_family = AF_INET;
    133 
    134     if (syslog_hostname[0] == '\0')
    135         goto use_default;
    136 
    137     phe = gethostbyname( syslog_hostname );
    138     if( !phe )
    139         goto use_default;
    140 
    141     memcpy( &syslog_hostaddr.sin_addr.s_addr, phe->h_addr, phe->h_length );
    142 
    143     syslog_hostaddr.sin_port = htons( syslog_port );
    144     return;
    145 
    146 use_default:
    147     syslog_hostaddr.sin_addr.S_un.S_addr = htonl( 0x7F000001 );
    148     syslog_hostaddr.sin_port = htons( SYSLOG_PORT );
    149 }
    150 
    151 /******************************************************************************
    152  * closelog
    153  *
    154  * Close desriptor used to write to system logger.
    155  */
    156 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    157 closelog()
    158 {
    159     if ( !initialized )
    160         return;
    161 
    162     EnterCriticalSection(&cs_syslog);
    163     if( syslog_opened ) {
    164         closesocket( syslog_socket );
    165         syslog_socket = INVALID_SOCKET;
    166         syslog_opened = FALSE;
    167     }
    168     LeaveCriticalSection(&cs_syslog);
    169 }
    170 
    171 /******************************************************************************
    172  * openlog
    173  *
    174  * Open connection to system logger.
    175  */
    176 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    177 openlog( char* ident, int option, int facility )
    178 {
    179     BOOL failed = FALSE;
    180     SOCKADDR_IN sa_local;
    181     DWORD n;
    182     int size;
    183 
    184     if ( !initialized )
    185         return;
    186 
    187     EnterCriticalSection(&cs_syslog);
    188 
    189     if( syslog_opened )
    190         goto done;
    191 
    192     failed = TRUE;
    193 
    194     syslog_facility = facility? facility : LOG_USER;
    195 
    196     if( option & LOG_PID )
    197         sprintf_s( syslog_procid_str, sizeof(syslog_procid_str), "[%lu]", GetCurrentProcessId() );
    198     else
    199         syslog_procid_str[0] = '\0';
    200 
    201     /* FIXME: handle other options */
    202 
    203     n = sizeof(local_hostname);
    204     if( !GetComputerName( local_hostname, &n ) )
    205         goto done;
    206 
    207     syslog_socket = INVALID_SOCKET;
    208 
    209     init_logger_addr();
    210 
    211     for( n = 0;; n++ )
    212     {
    213         syslog_socket = socket( AF_INET, SOCK_DGRAM, 0 );
    214         if( INVALID_SOCKET == syslog_socket )
    215             goto done;
    216 
    217         memset( &sa_local, 0, sizeof(SOCKADDR_IN) );
    218         sa_local.sin_family = AF_INET;
    219         if( bind( syslog_socket, (SOCKADDR*) &sa_local, sizeof(SOCKADDR_IN) ) == 0 )
    220             break;
    221         rk_closesocket( syslog_socket );
    222         syslog_socket = INVALID_SOCKET;
    223         if( n == 100 )
    224             goto done;
    225         Sleep(0);
    226     }
    227 
    228     /* get size of datagramm */
    229     size = sizeof(datagramm_size);
    230     if( getsockopt( syslog_socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*) &datagramm_size, &size ) )
    231         goto done;
    232     if( datagramm_size - strlen(local_hostname) - (ident? strlen(ident) : 0) < 64 )
    233         goto done;
    234     if( datagramm_size > SYSLOG_DGRAM_SIZE )
    235         datagramm_size = SYSLOG_DGRAM_SIZE;
    236 
    237     if (ident)
    238         strcpy_s(syslog_ident, sizeof(syslog_ident), ident);
    239 
    240     syslog_facility = (facility ? facility : LOG_USER);
    241     failed = FALSE;
    242 
    243  done:
    244     if( failed ) {
    245         if( syslog_socket != INVALID_SOCKET )
    246             rk_closesocket( syslog_socket );
    247     }
    248     syslog_opened = !failed;
    249 
    250     LeaveCriticalSection(&cs_syslog);
    251 }
    252 
    253 /******************************************************************************
    254  * setlogmask
    255  *
    256  * Set the log mask level.
    257  */
    258 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
    259 setlogmask( int mask )
    260 {
    261     int ret;
    262 
    263     if ( !initialized )
    264         return 0;
    265 
    266     EnterCriticalSection(&cs_syslog);
    267 
    268     ret = syslog_mask;
    269     if( mask )
    270         syslog_mask = mask;
    271 
    272     LeaveCriticalSection(&cs_syslog);
    273 
    274     return ret;
    275 }
    276 
    277 /******************************************************************************
    278  * syslog
    279  *
    280  * Generate a log message using FMT string and option arguments.
    281  */
    282 ROKEN_LIB_FUNCTION void
    283 syslog( int pri, char* fmt, ... )
    284 {
    285     va_list ap;
    286 
    287     va_start( ap, fmt );
    288     vsyslog( pri, fmt, ap );
    289     va_end( ap );
    290 }
    291 
    292 /******************************************************************************
    293  * vsyslog
    294  *
    295  * Generate a log message using FMT and using arguments pointed to by AP.
    296  */
    297 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
    298 vsyslog( int pri, char* fmt, va_list ap )
    299 {
    300     static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    301                             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    302     char  datagramm[ SYSLOG_DGRAM_SIZE ];
    303     SYSTEMTIME stm;
    304     int len;
    305     char *p;
    306 
    307     if ( !initialized )
    308         return;
    309 
    310     EnterCriticalSection(&cs_syslog);
    311 
    312     if( !(LOG_MASK( LOG_PRI( pri )) & syslog_mask) )
    313         goto done;
    314 
    315     openlog( NULL, 0, pri & LOG_FACMASK );
    316     if( !syslog_opened )
    317         goto done;
    318 
    319     if( !(pri & LOG_FACMASK) )
    320         pri |= syslog_facility;
    321 
    322     GetLocalTime( &stm );
    323     len = sprintf_s( datagramm, sizeof(datagramm),
    324                      "<%d>%s %2d %02d:%02d:%02d %s %s%s: ",
    325                      pri,
    326                      month[ stm.wMonth - 1 ], stm.wDay, stm.wHour, stm.wMinute, stm.wSecond,
    327                      local_hostname, syslog_ident, syslog_procid_str );
    328     vsprintf_s( datagramm + len, datagramm_size - len, fmt, ap );
    329     p = strchr( datagramm, '\n' );
    330     if( p )
    331         *p = 0;
    332     p = strchr( datagramm, '\r' );
    333     if( p )
    334         *p = 0;
    335 
    336     sendto( syslog_socket, datagramm, strlen(datagramm), 0, (SOCKADDR*) &syslog_hostaddr, sizeof(SOCKADDR_IN) );
    337 
    338  done:
    339     LeaveCriticalSection(&cs_syslog);
    340 }
    341 
    342