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