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