xref: /reactos/base/services/telnetd/syslog.c (revision 50cf16b3)
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