1 /* 2 * syslog-client.c - syslog client implementation for windows 3 * 4 * Created by Alexander Yaworsky 5 * 6 * THIS SOFTWARE IS NOT COPYRIGHTED 7 * 8 * This source code is offered for use in the public domain. You may 9 * use, modify or distribute it freely. 10 * 11 * This code is distributed in the hope that it will be useful but 12 * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY 13 * DISCLAIMED. This includes but is not limited to warranties of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 * 16 */ 17 18 /* define SYSLOG_CONF_DIR where syslog.host should be 19 */ 20 21 #ifndef SYSLOG_CONF_DIR 22 static const char *syslog_conf_dir = "."; 23 #else 24 static const char *syslog_conf_dir = SYSLOG_CONF_DIR; 25 #endif 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <winsock2.h> 30 #include <ws2tcpip.h> 31 #include "syslog.h" 32 33 #ifdef TEST 34 # define SYSLOG_DGRAM_SIZE 80 35 #else 36 # define SYSLOG_DGRAM_SIZE 1024 37 #endif 38 39 static BOOL initialized = FALSE; 40 static int log_mask = 0xFF; 41 static char *syslog_ident; 42 static int syslog_facility; 43 static char str_pid[ 40 ]; 44 static SOCKADDR_IN sa_logger; 45 static SOCKET sock; 46 static char local_hostname[ MAX_COMPUTERNAME_LENGTH + 1 ]; 47 static char datagramm[ SYSLOG_DGRAM_SIZE ]; 48 static int datagramm_size; 49 50 /****************************************************************************** 51 * set_syslog_conf_dir 52 * 53 * maybe this function will be useful... 54 */ 55 const char* set_syslog_conf_dir( const char* dir ) 56 { 57 const char *ret = syslog_conf_dir; 58 syslog_conf_dir = dir; 59 return ret; 60 } 61 62 /****************************************************************************** 63 * init_logger_addr 64 * 65 * Read configuration file syslog.host. This file should contain host address 66 * and, optionally, port. Initialize sa_logger. If the configuration file does 67 * not exist, use localhost:514. 68 * Returns: 0 - ok, -1 - error. 69 */ 70 static void init_logger_addr() 71 { 72 char pathname[ FILENAME_MAX ]; 73 char *p; 74 FILE *fd; 75 char host[256]; 76 struct hostent * phe; 77 78 memset( &sa_logger, 0, sizeof(SOCKADDR_IN) ); 79 sa_logger.sin_family = AF_INET; 80 81 if( '\\' == syslog_conf_dir[0] || '/' == syslog_conf_dir[0] || ':' == syslog_conf_dir[1] ) 82 { 83 /* absolute path */ 84 strcpy( pathname, syslog_conf_dir ); 85 } 86 else 87 { 88 /* relative path */ 89 char *q; 90 91 strcpy( pathname, __argv[0] ); 92 p = strrchr( pathname, '\\' ) + 1; 93 q = strrchr( pathname, '/' ) + 1; 94 if( p < q ) 95 *q = 0; 96 else if( p > q ) 97 *p = 0; 98 else 99 pathname[0] = 0; 100 strcat( pathname, syslog_conf_dir ); 101 } 102 p = &pathname[ strlen( pathname ) - 1 ]; 103 if( '\\' != *p && '/' != *p ) 104 { 105 p++; *p = '/'; 106 } 107 strcpy( ++p, "syslog.host" ); 108 109 /* read destination host name */ 110 fd = fopen( pathname, "r" ); 111 if( !fd ) 112 goto use_default; 113 114 if( NULL == fgets( host, sizeof(host), fd ) ) 115 host[0] = 0; 116 else 117 { 118 p = strchr( host, '\n' ); 119 if( p ) 120 *p = 0; 121 p = strchr( host, '\r' ); 122 if( p ) 123 *p = 0; 124 } 125 fclose( fd ); 126 127 p = strchr( host, ':' ); 128 if( p ) 129 *p++ = 0; 130 131 phe = gethostbyname( host ); 132 if( !phe ) 133 goto use_default; 134 135 memcpy( &sa_logger.sin_addr.s_addr, phe->h_addr, phe->h_length ); 136 137 if( p ) 138 sa_logger.sin_port = htons( (unsigned short) strtoul( p, NULL, 0 ) ); 139 else 140 sa_logger.sin_port = htons( SYSLOG_PORT ); 141 return; 142 143 use_default: 144 sa_logger.sin_addr.S_un.S_addr = htonl( 0x7F000001 ); 145 sa_logger.sin_port = htons( SYSLOG_PORT ); 146 } 147 148 /****************************************************************************** 149 * closelog 150 * 151 * Close descriptor used to write to system logger. 152 */ 153 void closelog() 154 { 155 if( !initialized ) 156 return; 157 closesocket( sock ); 158 WSACleanup(); 159 initialized = FALSE; 160 } 161 162 /****************************************************************************** 163 * openlog 164 * 165 * Open connection to system logger. 166 */ 167 void openlog( char* ident, int option, int facility ) 168 { 169 BOOL failed = TRUE, wsa_initialized = FALSE; 170 WSADATA wsd; 171 SOCKADDR_IN sa_local; 172 DWORD n; 173 int size; 174 175 if( initialized ) 176 return; 177 178 syslog_facility = facility? facility : LOG_USER; 179 180 /* FIXME: should we reset logmask? */ 181 182 if( option & LOG_PID ) 183 snprintf( str_pid, sizeof(str_pid), "[%lu]", GetCurrentProcessId() ); 184 else 185 str_pid[0] = 0; 186 187 /* FIXME: handle other options */ 188 189 n = sizeof(local_hostname); 190 if( !GetComputerName( local_hostname, &n ) ) 191 goto done; 192 193 sock = INVALID_SOCKET; 194 if( WSAStartup( MAKEWORD( 2, 2 ), &wsd ) ) 195 goto done; 196 wsa_initialized = TRUE; 197 198 init_logger_addr(); 199 200 for( n = 0;; n++ ) 201 { 202 sock = socket( AF_INET, SOCK_DGRAM, 0 ); 203 if( INVALID_SOCKET == sock ) 204 goto done; 205 206 memset( &sa_local, 0, sizeof(SOCKADDR_IN) ); 207 sa_local.sin_family = AF_INET; 208 if( bind( sock, (SOCKADDR*) &sa_local, sizeof(SOCKADDR_IN) ) == 0 ) 209 break; 210 closesocket( sock ); 211 sock = INVALID_SOCKET; 212 if( n == 100 ) 213 goto done; 214 Sleep(0); 215 } 216 217 /* get size of datagramm */ 218 size = sizeof(datagramm_size); 219 if( getsockopt( sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*) &datagramm_size, &size ) ) 220 goto done; 221 if( datagramm_size - strlen(local_hostname) - (ident? strlen(ident) : 0) < 64 ) 222 goto done; 223 if( datagramm_size > sizeof(datagramm) ) 224 datagramm_size = sizeof(datagramm); 225 226 if( atexit( closelog ) ) 227 goto done; 228 229 syslog_ident = ident; 230 syslog_facility = facility; 231 failed = FALSE; 232 233 done: 234 if( failed ) 235 { 236 if( sock != INVALID_SOCKET ) closesocket( sock ); 237 if( wsa_initialized ) WSACleanup(); 238 } 239 initialized = !failed; 240 } 241 242 /****************************************************************************** 243 * setlogmask 244 * 245 * Set the log mask level. 246 */ 247 int setlogmask( int mask ) 248 { 249 int ret = log_mask; 250 251 if( mask ) 252 log_mask = mask; 253 return ret; 254 } 255 256 /****************************************************************************** 257 * syslog 258 * 259 * Generate a log message using FMT string and option arguments. 260 */ 261 void syslog( int pri, char* fmt, ... ) 262 { 263 va_list ap; 264 265 va_start( ap, fmt ); 266 vsyslog( pri, fmt, ap ); 267 va_end( ap ); 268 } 269 270 /****************************************************************************** 271 * vsyslog 272 * 273 * Generate a log message using FMT and using arguments pointed to by AP. 274 */ 275 void vsyslog( int pri, char* fmt, va_list ap ) 276 { 277 static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 278 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 279 SYSTEMTIME stm; 280 int len; 281 char *p; 282 283 if( !(LOG_MASK( LOG_PRI( pri )) & log_mask) ) 284 return; 285 286 openlog( NULL, 0, pri & LOG_FACMASK ); 287 if( !initialized ) 288 return; 289 290 if( !(pri & LOG_FACMASK) ) 291 pri |= syslog_facility; 292 293 GetLocalTime( &stm ); 294 len = sprintf( datagramm, "<%d>%s %2d %02d:%02d:%02d %s %s%s: ", 295 pri, 296 month[ stm.wMonth - 1 ], stm.wDay, stm.wHour, stm.wMinute, stm.wSecond, 297 local_hostname, syslog_ident? syslog_ident : "", str_pid ); 298 vsnprintf( datagramm + len, datagramm_size - len, fmt, ap ); 299 p = strchr( datagramm, '\n' ); 300 if( p ) 301 *p = 0; 302 p = strchr( datagramm, '\r' ); 303 if( p ) 304 *p = 0; 305 306 sendto( sock, datagramm, strlen(datagramm), 0, (SOCKADDR*) &sa_logger, sizeof(SOCKADDR_IN) ); 307 } 308 309