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
init_syslog(const char * hostname)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
exit_syslog(void)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
init_logger_addr()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
closelog()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
openlog(char * ident,int option,int facility)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
setlogmask(int mask)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
syslog(int pri,char * fmt,...)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
vsyslog(int pri,char * fmt,va_list ap)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