Imported Upstream version 2.3
[ossec-hids.git] / src / win32 / win_agent.c
1 /* @(#) $Id: win_agent.c,v 1.56 2009/12/01 20:27:01 dcid Exp $ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights reserved.
5  *
6  * This program is a free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License (version 3) as published by the FSF - Free Software
9  * Foundation.
10  *
11  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/en/licensing.html
13  */
14
15
16 #ifdef WIN32
17
18 #include "shared.h"
19 #include "agentd.h"
20 #include "logcollector.h"
21 #include "os_win.h"
22 #include "os_net/os_net.h"
23 #include "os_execd/execd.h"
24 #include "os_crypto/md5/md5_op.h"
25
26 #ifndef ARGV0
27 #define ARGV0 "ossec-agent"
28 #endif
29
30 time_t __win32_curr_time = 0;
31 time_t __win32_shared_time = 0;
32 char *__win32_uname = NULL;
33 char *__win32_shared = NULL;
34 HANDLE hMutex;
35
36
37 /** Prototypes **/
38 int Start_win32_Syscheck();
39 void send_win32_info(time_t curr_time);
40
41
42 /* Help message */
43 void agent_help()
44 {
45     printf("\nOSSEC HIDS %s %s .\n", ARGV0, __version);
46     printf("Available options:\n");
47     printf("\t-h                This help message.\n");
48     printf("\thelp              This help message.\n");
49     printf("\tinstall-service   Installs as a service\n");
50     printf("\tuninstall-service Uninstalls as a service\n");
51     printf("\tstart             Manually starts (not from services)\n");
52     exit(1);
53 }
54
55 /* syscheck main thread */
56 void *skthread()
57 {
58     verbose("%s: Starting syscheckd thread.", ARGV0);
59
60     Start_win32_Syscheck();
61
62     return (NULL);
63 }
64
65
66 /** main(int argc, char **argv)
67  * ..
68  */
69 int main(int argc, char **argv)
70 {
71     char *tmpstr;
72     char mypath[OS_MAXSTR +1];
73     char myfile[OS_MAXSTR +1];
74
75     /* Setting the name */
76     OS_SetName(ARGV0);
77
78
79     /* Find where I'm */
80     mypath[OS_MAXSTR] = '\0';
81     myfile[OS_MAXSTR] = '\0';
82     
83     
84     /* mypath is going to be the whole path of the file */
85     strncpy(mypath, argv[0], OS_MAXSTR);
86     tmpstr = strrchr(mypath, '\\');
87     if(tmpstr)
88     {
89         /* tmpstr is now the file name */
90         *tmpstr = '\0';
91         tmpstr++;
92         strncpy(myfile, tmpstr, OS_MAXSTR);
93     }
94     else
95     {
96         strncpy(myfile, argv[0], OS_MAXSTR);
97         mypath[0] = '.';
98         mypath[1] = '\0';
99     }
100     chdir(mypath);
101     getcwd(mypath, OS_MAXSTR -1);
102     strncat(mypath, "\\", OS_MAXSTR - (strlen(mypath) + 2));
103     strncat(mypath, myfile, OS_MAXSTR - (strlen(mypath) + 2));
104     
105      
106     if(argc > 1)
107     {
108         if(strcmp(argv[1], "install-service") == 0)
109         {
110             return(InstallService(mypath));
111         }
112         else if(strcmp(argv[1], "uninstall-service") == 0)
113         {
114             return(UninstallService());
115         }
116         else if(strcmp(argv[1], "start") == 0)
117         {
118             return(local_start());
119         }
120         else if(strcmp(argv[1], "-h") == 0)
121         {
122             agent_help();
123         }
124         else if(strcmp(argv[1], "help") == 0)
125         {
126             agent_help();
127         }
128         else
129         {
130             merror("%s: Unknown option: %s", ARGV0, argv[1]);
131             exit(1);
132         }
133     }
134
135
136     /* Start it */
137     if(!os_WinMain(argc, argv))
138     {
139         ErrorExit("%s: Unable to start WinMain.", ARGV0);
140     }
141
142     return(0);
143 }
144
145
146 /* Locally starts (after service/win init) */
147 int local_start()
148 {
149     int debug_level;
150     char *cfg = DEFAULTCPATH;
151     WSADATA wsaData;
152     DWORD  threadID;
153     DWORD  threadID2;
154
155
156     /* Starting logr */
157     logr = (agent *)calloc(1, sizeof(agent));
158     if(!logr)
159     {
160         ErrorExit(MEM_ERROR, ARGV0);
161     }
162     logr->port = DEFAULT_SECURE;
163
164
165     /* Getting debug level */
166     debug_level = getDefine_Int("windows","debug", 0, 2);
167     while(debug_level != 0)
168     {
169         nowDebug();
170         debug_level--;
171     }
172     
173     
174     
175     /* Configuration file not present */
176     if(File_DateofChange(cfg) < 0)
177         ErrorExit("%s: Configuration file '%s' not found",ARGV0,cfg);
178
179
180     /* Starting Winsock */
181     if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
182     {
183         ErrorExit("%s: WSAStartup() failed", ARGV0);
184     }
185                                 
186
187     /* Read agent config */
188     debug1("%s: DEBUG: Reading agent configuration.", ARGV0);
189     if(ClientConf(cfg) < 0)
190     {
191         ErrorExit(CLIENT_ERROR,ARGV0);
192     }
193
194
195     /* Reading logcollector config file */
196     debug1("%s: DEBUG: Reading logcollector configuration.", ARGV0);
197     if(LogCollectorConfig(cfg) < 0)
198     {
199         ErrorExit(CONFIG_ERROR, ARGV0, cfg);
200     }
201
202
203     /* Checking auth keys */
204     if(!OS_CheckKeys())
205     {
206         ErrorExit(AG_NOKEYS_EXIT, ARGV0);
207     }
208                                 
209
210
211     /* If there is not file to monitor, create a clean entry
212      * for the mark messages.
213      */
214     if(logff == NULL)
215     {
216         os_calloc(2, sizeof(logreader), logff);
217         logff[0].file = NULL;
218         logff[0].ffile = NULL;
219         logff[0].logformat = NULL;
220         logff[0].fp = NULL;
221         logff[1].file = NULL;
222         logff[1].logformat = NULL;
223
224         merror(NO_FILE, ARGV0);
225     }
226
227
228     /* Reading execd config. */
229     if(!WinExecd_Start())
230     {
231         logr->execdq = -1;
232     }
233     
234     
235     /* Reading keys */
236     verbose(ENC_READ, ARGV0);
237         
238     OS_ReadKeys(&keys);
239     OS_StartCounter(&keys);
240     os_write_agent_info(keys.keyentries[0]->name, NULL, keys.keyentries[0]->id);
241
242
243     /* Initial random numbers */
244     srandom(time(0));
245     random();
246
247
248     /* Socket connection */
249     logr->sock = -1;
250     StartMQ(NULL, 0);
251
252
253     /* Starting mutex */
254     debug1("%s: DEBUG: Creating thread mutex.", ARGV0);
255     hMutex = CreateMutex(NULL, FALSE, NULL);
256     if(hMutex == NULL)
257     {
258         ErrorExit("%s: Error creating mutex.", ARGV0);
259     }
260
261
262
263     /* Starting syscheck thread */
264     if(CreateThread(NULL, 
265                     0, 
266                     (LPTHREAD_START_ROUTINE)skthread, 
267                     NULL, 
268                     0, 
269                     (LPDWORD)&threadID) == NULL)
270     {
271         merror(THREAD_ERROR, ARGV0);
272     }
273
274     
275
276     /* Checking if server is connected */
277     os_setwait();
278         
279     start_agent(1);
280             
281     os_delwait();
282
283
284     /* Sending integrity message for agent configs */
285     intcheck_file(cfg, "");
286     intcheck_file(OSSEC_DEFINES, "");
287                 
288
289     /* Starting receiver thread */
290     if(CreateThread(NULL, 
291                     0, 
292                     (LPTHREAD_START_ROUTINE)receiver_thread, 
293                     NULL, 
294                     0, 
295                     (LPDWORD)&threadID2) == NULL)
296     {
297         merror(THREAD_ERROR, ARGV0);
298     }
299     
300     
301     /* Sending agent information message */
302     send_win32_info(time(0));
303     
304     
305     /* Startting logcollector -- main process here */
306     LogCollectorStart();
307
308     WSACleanup();
309     return(0);
310 }
311
312
313 /* SendMSG for windows */
314 int SendMSG(int queue, char *message, char *locmsg, char loc)
315 {
316     int _ssize;
317     
318     time_t cu_time;
319     
320     char *pl;
321     char tmpstr[OS_MAXSTR+2];
322     char crypt_msg[OS_MAXSTR +2];
323     
324     DWORD dwWaitResult; 
325
326     tmpstr[OS_MAXSTR +1] = '\0';
327     crypt_msg[OS_MAXSTR +1] = '\0';
328
329
330     debug2("%s: DEBUG: Attempting to send message to server.", ARGV0);
331     
332     /* Using a mutex to synchronize the writes */
333     while(1)
334     {
335         dwWaitResult = WaitForSingleObject(hMutex, 1000000L);
336
337         if(dwWaitResult != WAIT_OBJECT_0) 
338         {
339             switch(dwWaitResult)
340             {
341                 case WAIT_TIMEOUT:
342                     merror("%s: Error waiting mutex (timeout).", ARGV0);
343                     sleep(5);
344                     continue;
345                 case WAIT_ABANDONED:
346                     merror("%s: Error waiting mutex (abandoned).", ARGV0);
347                     return(0);
348                 default:    
349                     merror("%s: Error waiting mutex.", ARGV0);    
350                     return(0);
351             }
352         }
353         else
354         {
355             /* Lock acquired */
356             break;
357         }
358     }
359
360
361     cu_time = time(0);
362     
363
364     /* Check if the server has responded */
365     if((cu_time - available_server) > (NOTIFY_TIME - 180))
366     {
367         debug1("%s: DEBUG: Sending info to server (c1)...", ARGV0);
368         send_win32_info(cu_time);
369
370
371         /* Attempting to send message again. */
372         if((cu_time - available_server) > NOTIFY_TIME)
373         {
374             sleep(1);
375             send_win32_info(cu_time);
376             sleep(1);
377
378             if((cu_time - available_server) > NOTIFY_TIME)
379             {
380                 send_win32_info(cu_time);
381             }
382         }
383
384
385         /* If we reached here, the server is unavailable for a while. */
386         if((cu_time - available_server) > ((3 * NOTIFY_TIME) - 180))
387         {
388             int wi = 1;
389
390
391             /* Last attempt before going into reconnect mode. */
392             debug1("%s: DEBUG: Sending info to server (c3)...", ARGV0);
393             sleep(1);
394             send_win32_info(cu_time);
395             if((cu_time - available_server) > ((3 * NOTIFY_TIME) - 180))
396             {
397                 sleep(1);
398                 send_win32_info(cu_time);
399                 sleep(1);
400             }
401
402
403             /* Checking and generating log if unavailable. */
404             cu_time = time(0);
405             if((cu_time - available_server) > ((3 * NOTIFY_TIME) - 180))
406             {
407                 int global_sleep = 1;
408                 int mod_sleep = 12;
409
410                 /* If response is not available, set lock and
411                  * wait for it.
412                  */
413                 verbose(SERVER_UNAV, ARGV0);
414
415
416                 /* Going into reconnect mode. */
417                 while((cu_time - available_server) > ((3*NOTIFY_TIME) - 180))
418                 {
419                     /* Sending information to see if server replies */
420                     if(logr->sock != -1)
421                     {
422                         send_win32_info(cu_time);
423                     }
424
425                     sleep(wi);
426                     cu_time = time(0);
427
428                     if(wi < 20)
429                     {
430                         wi++;
431                     }
432                     else
433                     {
434                         global_sleep++;
435                     }
436
437
438                     /* If we have more than one server, try all. */
439                     if(wi > 12 && logr->rip[1])
440                     {
441                         int curr_rip = logr->rip_id;
442                         merror("%s: INFO: Trying next server ip in "
443                                "line: '%s'.", 
444                                ARGV0,
445                                logr->rip[logr->rip_id + 1] != NULL?
446                                logr->rip[logr->rip_id + 1]:
447                                logr->rip[0]);
448                         
449                         connect_server(logr->rip_id +1);
450
451                         if(logr->rip_id != curr_rip)
452                         {
453                             wi = 1;
454                         }
455                     }
456                     else if(global_sleep == 2 || ((global_sleep % mod_sleep) == 0) ||
457                             (logr->sock == -1))
458                     {
459                         connect_server(logr->rip_id +1);
460                         if(logr->sock == -1)
461                         {
462                             sleep(wi + global_sleep);
463                         }
464                         else
465                         {
466                             sleep(global_sleep);
467                         }
468
469                         if(global_sleep > 30)
470                         {
471                             mod_sleep = 50;
472                         }
473                     }
474                 }
475
476                 verbose(AG_CONNECTED, ARGV0, logr->rip[logr->rip_id], 
477                                              logr->port);
478                 verbose(SERVER_UP, ARGV0);
479             }
480         }
481     }
482     
483
484     /* Send notification */
485     else if((cu_time - __win32_curr_time) > (NOTIFY_TIME - 200))
486     {
487         debug1("%s: DEBUG: Sending info to server (ctime2)...", ARGV0);
488         send_win32_info(cu_time);
489     }
490
491
492     
493     /* locmsg cannot have the C:, as we use it as delimiter */
494     pl = strchr(locmsg, ':');
495     if(pl)
496     {
497         /* Setting pl after the ":" if it exists. */
498         pl++;
499     }
500     else
501     {
502         pl = locmsg;
503     }
504
505     
506     debug2("%s: DEBUG: Sending message to server: '%s'", ARGV0, message);
507     
508     snprintf(tmpstr,OS_MAXSTR,"%c:%s:%s", loc, pl, message);
509
510     _ssize = CreateSecMSG(&keys, tmpstr, crypt_msg, 0);
511
512
513     /* Returns NULL if can't create encrypted message */
514     if(_ssize == 0)
515     {
516         merror(SEC_ERROR,ARGV0);
517         if(!ReleaseMutex(hMutex))
518         {
519             merror("%s: Error releasing mutex.", ARGV0);        
520         }
521         
522         return(-1);
523     }
524
525     /* Send _ssize of crypt_msg */
526     if(OS_SendUDPbySize(logr->sock, _ssize, crypt_msg) < 0)
527     {
528         merror(SEND_ERROR,ARGV0, "server");
529         sleep(1);
530     }
531
532     if(!ReleaseMutex(hMutex))
533     {
534         merror("%s: Error releasing mutex.", ARGV0);
535     }
536     return(0);        
537 }
538
539
540 /* StartMQ for windows */
541 int StartMQ(char * path, short int type)
542 {
543     /* Connecting to the server. */
544     connect_server(0);
545     
546     if((path == NULL) && (type == 0))
547     {
548         return(0);
549     }
550     
551     return(0);
552 }
553
554
555 /* Send win32 info to server */
556 void send_win32_info(time_t curr_time)
557 {
558     int msg_size;
559     char tmp_msg[OS_MAXSTR +2];
560     char crypt_msg[OS_MAXSTR +2];
561
562     tmp_msg[OS_MAXSTR +1] = '\0';
563     crypt_msg[OS_MAXSTR +1] = '\0';
564
565
566     debug1("%s: DEBUG: Sending keep alive message.", ARGV0);
567
568
569     /* fixing time */
570     __win32_curr_time = curr_time;
571
572
573     /* Getting uname. */
574     if(!__win32_uname)
575     {
576         __win32_uname = getuname();
577         if(!__win32_uname)
578         {
579             merror("%s: Error generating system information.", ARGV0);
580             os_strdup("Microsoft Windows - Unknown (unable to get system info)", __win32_uname);
581         }
582     }
583
584
585     /* Getting shared files list -- every 30 seconds only. */
586     if((__win32_curr_time - __win32_shared_time) > 30)
587     {
588         if(__win32_shared)
589         {
590             free(__win32_shared);
591             __win32_shared = NULL;
592         }
593
594         __win32_shared_time = __win32_curr_time;
595     }
596     
597     
598     /* get shared files */
599     if(!__win32_shared)
600     {
601         __win32_shared = getsharedfiles();
602         if(!__win32_shared)
603         {
604             __win32_shared = strdup("\0");
605             if(!__win32_shared)
606             {
607                 merror(MEM_ERROR, ARGV0);
608                 return;
609             }
610         }
611     }
612
613
614
615     /* creating message */
616     if(File_DateofChange(AGENTCONFIGINT) > 0)
617     {
618         os_md5 md5sum;
619         if(OS_MD5_File(AGENTCONFIGINT, md5sum) != 0)
620         {
621             snprintf(tmp_msg, OS_SIZE_1024, "#!-%s\n%s", __win32_uname, __win32_shared);
622         }
623         else
624         {
625             snprintf(tmp_msg, OS_SIZE_1024, "#!-%s / %s\n%s", __win32_uname, md5sum, __win32_shared);
626         }
627     }
628     else
629     {
630         snprintf(tmp_msg, OS_SIZE_1024, "#!-%s\n%s", __win32_uname, __win32_shared);
631     }
632
633
634     /* creating message */
635     debug1("%s: DEBUG: Sending keep alive: %s", ARGV0, tmp_msg);
636
637     msg_size = CreateSecMSG(&keys, tmp_msg, crypt_msg, 0);
638
639     if(msg_size == 0)
640     {
641         merror(SEC_ERROR, ARGV0);
642         return;
643     }
644
645     /* Sending UDP message */
646     if(OS_SendUDPbySize(logr->sock, msg_size, crypt_msg) < 0)
647     {
648         merror(SEND_ERROR, ARGV0, "server");
649         sleep(1);
650     }
651
652     return;
653 }
654
655 #endif
656 /* EOF */