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