1 /* Copyright (C) 2009 Trend Micro Inc.
2 * All right 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 #include "shared.h"
11 #include "remoted.h"
12 #include "os_crypto/md5/md5_op.h"
13 #include "os_net/os_net.h"
14 #include <pthread.h>
15
16 /* Internal structures */
17 typedef struct _file_sum {
18 int mark;
19 char *name;
20 os_md5 sum;
21 } file_sum;
22
23 /* Internal functions prototypes */
24 static void read_controlmsg(unsigned int agentid, char *msg);
25 static int send_file_toagent(unsigned int agentid, const char *name, const char *sum);
26 static void f_files(void);
27 static void c_files(void);
28
29 /* Global vars */
30 static file_sum **f_sum;
31 static time_t _ctime;
32 static time_t _stime;
33
34 /* For the last message tracking */
35 static char *_msg[MAX_AGENTS + 1];
36 static char *_keep_alive[MAX_AGENTS + 1];
37 static int _changed[MAX_AGENTS + 1];
38 static int modified_agentid;
39
40 /* pthread mutex variables */
41 static pthread_mutex_t lastmsg_mutex;
42 static pthread_cond_t awake_mutex;
43
44
45 /* Save a control message received from an agent
46 * read_controlmsg (other thread) is going to deal with it
47 * (only if message changed)
48 */
save_controlmsg(unsigned int agentid,char * r_msg)49 void save_controlmsg(unsigned int agentid, char *r_msg)
50 {
51 char msg_ack[OS_FLSIZE + 1];
52
53 /* Reply to the agent */
54 snprintf(msg_ack, OS_FLSIZE, "%s%s", CONTROL_HEADER, HC_ACK);
55 send_msg(agentid, msg_ack);
56
57 /* Check if there is a keep alive already for this agent */
58 if (_keep_alive[agentid] && _msg[agentid] &&
59 (strcmp(_msg[agentid], r_msg) == 0)) {
60 utimes(_keep_alive[agentid], NULL);
61 }
62
63 else if (strcmp(r_msg, HC_STARTUP) == 0) {
64 return;
65 }
66
67 else {
68 FILE *fp;
69 char *uname = r_msg;
70 char *random_leftovers;
71
72 /* Lock mutex */
73 if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
74 merror(MUTEX_ERROR, ARGV0);
75 return;
76 }
77
78 /* Update rmsg */
79 if (_msg[agentid]) {
80 free(_msg[agentid]);
81 }
82 os_strdup(r_msg, _msg[agentid]);
83
84 /* Unlock mutex */
85 if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
86 merror(MUTEX_ERROR, ARGV0);
87 return;
88 }
89
90 r_msg = strchr(r_msg, '\n');
91 if (!r_msg) {
92 merror("%s: WARN: Invalid message from agent id: '%d'(uname)",
93 ARGV0,
94 agentid);
95 return;
96 }
97
98 *r_msg = '\0';
99 random_leftovers = strchr(r_msg, '\n');
100 if (random_leftovers) {
101 *random_leftovers = '\0';
102 }
103
104 /* Update the keep alive */
105 if (!_keep_alive[agentid]) {
106 char agent_file[OS_SIZE_1024 + 1];
107 agent_file[OS_SIZE_1024] = '\0';
108
109 /* Write to the agent file */
110 snprintf(agent_file, OS_SIZE_1024, "%s/%s-%s",
111 AGENTINFO_DIR,
112 keys.keyentries[agentid]->name,
113 keys.keyentries[agentid]->ip->ip);
114 os_strdup(agent_file, _keep_alive[agentid]);
115 }
116
117 /* Write to the file */
118 fp = fopen(_keep_alive[agentid], "w");
119 if (fp) {
120 fprintf(fp, "%s\n", uname);
121 fclose(fp);
122 } else {
123 merror("ossec-remoted: ERROR: Could not open %s: %s", _keep_alive[agentid], strerror(errno));
124 }
125 }
126
127 /* Lock now to notify of change */
128 if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
129 merror(MUTEX_ERROR, ARGV0);
130 return;
131 }
132
133 /* Assign new values */
134 _changed[agentid] = 1;
135 modified_agentid = (int) agentid;
136
137 /* Signal that new data is available */
138 pthread_cond_signal(&awake_mutex);
139
140 /* Unlock mutex */
141 if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
142 merror(MUTEX_ERROR, ARGV0);
143 return;
144 }
145
146 return;
147 }
148
149 /* Free the files memory */
f_files()150 static void f_files()
151 {
152 int i;
153 if (!f_sum) {
154 return;
155 }
156 for (i = 0;; i++) {
157 if (f_sum[i] == NULL) {
158 break;
159 }
160
161 if (f_sum[i]->name) {
162 free(f_sum[i]->name);
163 }
164
165 free(f_sum[i]);
166 f_sum[i] = NULL;
167 }
168
169 free(f_sum);
170 f_sum = NULL;
171 }
172
173 /* Create the structure with the files and checksums */
c_files()174 static void c_files()
175 {
176 DIR *dp;
177 struct dirent *entry;
178 os_md5 md5sum;
179 unsigned int f_size = 0;
180
181 f_sum = NULL;
182
183 /* Create merged file */
184 os_realloc(f_sum, (f_size + 2) * sizeof(file_sum *), f_sum);
185 os_calloc(1, sizeof(file_sum), f_sum[f_size]);
186 f_sum[f_size]->mark = 0;
187 f_sum[f_size]->name = NULL;
188 f_sum[f_size]->sum[0] = '\0';
189 MergeAppendFile(SHAREDCFG_FILE, NULL);
190 f_size++;
191
192 /* Open directory */
193 dp = opendir(SHAREDCFG_DIR);
194 if (!dp) {
195 merror("%s: Error opening directory: '%s': %s ",
196 ARGV0,
197 SHAREDCFG_DIR,
198 strerror(errno));
199 return;
200 }
201
202 /* Read directory */
203 while ((entry = readdir(dp)) != NULL) {
204 char tmp_dir[512];
205
206 /* Ignore . and .. */
207 if ((strcmp(entry->d_name, ".") == 0) ||
208 (strcmp(entry->d_name, "..") == 0)) {
209 continue;
210 }
211
212 snprintf(tmp_dir, 512, "%s/%s", SHAREDCFG_DIR, entry->d_name);
213
214 /* Leave the shared config file for later */
215 if (strcmp(tmp_dir, SHAREDCFG_FILE) == 0) {
216 continue;
217 }
218
219 if (OS_MD5_File(tmp_dir, md5sum, OS_TEXT) != 0) {
220 merror("%s: Error accessing file '%s'", ARGV0, tmp_dir);
221 continue;
222 }
223
224 f_sum = (file_sum **)realloc(f_sum, (f_size + 2) * sizeof(file_sum *));
225 if (!f_sum) {
226 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
227 }
228
229 f_sum[f_size] = (file_sum *) calloc(1, sizeof(file_sum));
230 if (!f_sum[f_size]) {
231 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
232 }
233
234 strncpy(f_sum[f_size]->sum, md5sum, 32);
235 os_strdup(entry->d_name, f_sum[f_size]->name);
236 f_sum[f_size]->mark = 0;
237
238 MergeAppendFile(SHAREDCFG_FILE, tmp_dir);
239 f_size++;
240 }
241
242 if (f_sum != NULL) {
243 f_sum[f_size] = NULL;
244 }
245
246 closedir(dp);
247
248 if (OS_MD5_File(SHAREDCFG_FILE, md5sum, OS_TEXT) != 0) {
249 merror("%s: Error accessing file '%s'", ARGV0, SHAREDCFG_FILE);
250 f_sum[0]->sum[0] = '\0';
251 }
252 strncpy(f_sum[0]->sum, md5sum, 32);
253
254 os_strdup(SHAREDCFG_FILENAME, f_sum[0]->name);
255
256 return;
257 }
258
259 /* Send a file to the agent
260 * Returns -1 on error
261 */
send_file_toagent(unsigned int agentid,const char * name,const char * sum)262 static int send_file_toagent(unsigned int agentid, const char *name, const char *sum)
263 {
264 int i = 0;
265 size_t n = 0;
266 char file[OS_SIZE_1024 + 1];
267 char buf[OS_SIZE_1024 + 1];
268 FILE *fp;
269
270 snprintf(file, OS_SIZE_1024, "%s/%s", SHAREDCFG_DIR, name);
271 fp = fopen(file, "r");
272 if (!fp) {
273 merror(FOPEN_ERROR, ARGV0, file, errno, strerror(errno));
274 return (-1);
275 }
276
277 /* Send the file name first */
278 snprintf(buf, OS_SIZE_1024, "%s%s%s %s\n",
279 CONTROL_HEADER, FILE_UPDATE_HEADER, sum, name);
280 if (send_msg(agentid, buf) == -1) {
281 merror(SEC_ERROR, ARGV0);
282 fclose(fp);
283 return (-1);
284 }
285
286 /* Send the file contents */
287 while ((n = fread(buf, 1, 900, fp)) > 0) {
288 buf[n] = '\0';
289
290 if (send_msg(agentid, buf) == -1) {
291 merror(SEC_ERROR, ARGV0);
292 fclose(fp);
293 return (-1);
294 }
295
296 /* Sleep 1 every 30 messages -- no flood */
297 if (i > 30) {
298 sleep(1);
299 i = 0;
300 }
301 i++;
302 }
303
304 /* Send the message to close the file */
305 snprintf(buf, OS_SIZE_1024, "%s%s", CONTROL_HEADER, FILE_CLOSE_HEADER);
306 if (send_msg(agentid, buf) == -1) {
307 merror(SEC_ERROR, ARGV0);
308 fclose(fp);
309 return (-1);
310 }
311
312 fclose(fp);
313
314 return (0);
315 }
316
317 /* Read the available control message from the agent */
read_controlmsg(unsigned int agentid,char * msg)318 static void read_controlmsg(unsigned int agentid, char *msg)
319 {
320 int i;
321
322 /* Remove uname */
323 msg = strchr(msg, '\n');
324 if (!msg) {
325 merror("%s: Invalid message from '%d' (uname)", ARGV0, agentid);
326 return;
327 }
328
329 *msg = '\0';
330 msg++;
331
332 if (!f_sum) {
333 /* Nothing to share with agent */
334 return;
335 }
336
337 /* Parse message */
338 while (*msg != '\0') {
339 char *md5;
340 char *file;
341
342 md5 = msg;
343 file = msg;
344
345 msg = strchr(msg, '\n');
346 if (!msg) {
347 merror("%s: Invalid message from '%s' (strchr \\n)",
348 ARGV0,
349 keys.keyentries[agentid]->ip->ip);
350 break;
351 }
352
353 *msg = '\0';
354 msg++;
355
356 file = strchr(file, ' ');
357 if (!file) {
358 merror("%s: Invalid message from '%s' (strchr ' ')",
359 ARGV0,
360 keys.keyentries[agentid]->ip->ip);
361 break;
362 }
363
364 *file = '\0';
365 file++;
366
367 /* New agents only have merged.mg */
368 if (strcmp(file, SHAREDCFG_FILENAME) == 0) {
369 if (strcmp(f_sum[0]->sum, md5) != 0) {
370 debug1("%s: DEBUG Sending file '%s' to agent.", ARGV0,
371 f_sum[0]->name);
372 if (send_file_toagent(agentid, f_sum[0]->name, f_sum[0]->sum) < 0) {
373 merror("%s: ERROR: Unable to send file '%s' to agent.",
374 ARGV0,
375 f_sum[0]->name);
376 }
377 }
378
379 i = 0;
380 while (f_sum[i]) {
381 f_sum[i]->mark = 0;
382 i++;
383 }
384
385 return;
386 }
387
388 for (i = 1;; i++) {
389 if (f_sum[i] == NULL) {
390 break;
391 }
392
393 else if (strcmp(f_sum[i]->name, file) != 0) {
394 continue;
395 }
396
397 else if (strcmp(f_sum[i]->sum, md5) != 0) {
398 f_sum[i]->mark = 1; /* Marked to update */
399 }
400
401 else {
402 f_sum[i]->mark = 2;
403 }
404 break;
405 }
406 }
407
408 /* Update each marked file */
409 for (i = 1;; i++) {
410 if (f_sum[i] == NULL) {
411 break;
412 }
413
414 if ((f_sum[i]->mark == 1) ||
415 (f_sum[i]->mark == 0)) {
416
417 debug1("%s: Sending file '%s' to agent.", ARGV0, f_sum[i]->name);
418 if (send_file_toagent(agentid, f_sum[i]->name, f_sum[i]->sum) < 0) {
419 merror("%s: Error sending file '%s' to agent.",
420 ARGV0,
421 f_sum[i]->name);
422 }
423 }
424
425 f_sum[i]->mark = 0;
426 }
427
428 return;
429 }
430
431 /* Wait for new messages to read
432 * The messages will be sent using save_controlmsg
433 */
wait_for_msgs(void * none)434 void *wait_for_msgs(__attribute__((unused)) void *none)
435 {
436 int id;
437 char msg[OS_SIZE_1024 + 2];
438
439 /* Initialize the memory */
440 memset(msg, '\0', OS_SIZE_1024 + 2);
441
442 /* Should never leave this loop */
443 while (1) {
444 unsigned int i;
445 /* Every NOTIFY * 30 minutes, re-read the files
446 * If something changed, notify all agents
447 */
448 _ctime = time(0);
449 if ((_ctime - _stime) > (NOTIFY_TIME * 30)) {
450 f_files();
451 c_files();
452
453 _stime = _ctime;
454 }
455
456 /* Lock mutex */
457 if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
458 merror(MUTEX_ERROR, ARGV0);
459 return (NULL);
460 }
461
462 /* If no agent changed, wait for signal */
463 if (modified_agentid == -1) {
464 pthread_cond_wait(&awake_mutex, &lastmsg_mutex);
465 }
466
467 /* Unlock mutex */
468 if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
469 merror(MUTEX_ERROR, ARGV0);
470 return (NULL);
471 }
472
473 /* Check if any agent is ready */
474 for (i = 0; i < keys.keysize; i++) {
475 /* If agent wasn't changed, try next */
476 if (_changed[i] != 1) {
477 continue;
478 }
479
480 id = 0;
481
482 /* Lock mutex */
483 if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
484 merror(MUTEX_ERROR, ARGV0);
485 break;
486 }
487
488 if (_msg[i]) {
489 /* Copy the message to be analyzed */
490 strncpy(msg, _msg[i], OS_SIZE_1024);
491 _changed[i] = 0;
492
493 if (modified_agentid >= (int) i) {
494 modified_agentid = -1;
495 }
496
497 id = 1;
498 }
499
500 /* Unlock mutex */
501 if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
502 merror(MUTEX_ERROR, ARGV0);
503 break;
504 }
505
506 if (id) {
507 read_controlmsg(i, msg);
508 }
509 }
510 }
511
512 return (NULL);
513 }
514
515 /* Should be called before anything here */
manager_init(int isUpdate)516 void manager_init(int isUpdate)
517 {
518 int i;
519
520 _stime = time(0);
521
522 f_files();
523 c_files();
524
525 debug1("%s: DEBUG: Running manager_init", ARGV0);
526
527 modified_agentid = -1;
528
529 for (i = 0; i < MAX_AGENTS + 1; i++) {
530 _keep_alive[i] = NULL;
531 _msg[i] = NULL;
532 _changed[i] = 0;
533 }
534
535 /* Initialize mutexes */
536 if (isUpdate == 0) {
537 pthread_mutex_init(&lastmsg_mutex, NULL);
538 pthread_cond_init(&awake_mutex, NULL);
539 }
540
541 return;
542 }
543
544