1 /*****
2 *
3 * Copyright (C) 2004-2015 CS-SI. All Rights Reserved.
4 * Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
5 *
6 * This file is part of the Prelude library.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 *****/
23
24 #include "config.h"
25 #include "libmissing.h"
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <arpa/inet.h>
39 #include <sys/utsname.h>
40
41 #include <gcrypt.h>
42 #include <gnutls/gnutls.h>
43 #include <gnutls/x509.h>
44
45 #include "glthread/lock.h"
46
47 #define PRELUDE_ERROR_SOURCE_DEFAULT PRELUDE_ERROR_SOURCE_CLIENT
48 #include "prelude-error.h"
49
50 #include "idmef.h"
51 #include "common.h"
52 #include "prelude-log.h"
53 #include "prelude-ident.h"
54 #include "prelude-async.h"
55 #include "prelude-option.h"
56 #include "prelude-connection-pool.h"
57 #include "prelude-client.h"
58 #include "prelude-timer.h"
59 #include "prelude-message-id.h"
60 #include "prelude-option-wide.h"
61 #include "idmef-message-write.h"
62 #include "idmef-additional-data.h"
63 #include "config-engine.h"
64 #include "tls-auth.h"
65
66
67 #define CLIENT_STATUS_NEED_INIT 0
68 #define CLIENT_STATUS_INIT_DONE 1
69
70 #define CLIENT_STATUS_STARTING 2
71 #define CLIENT_STATUS_STARTING_STR "starting"
72
73 #define CLIENT_STATUS_RUNNING 3
74 #define CLIENT_STATUS_RUNNING_STR "running"
75
76 #define CLIENT_STATUS_EXITING 4
77 #define CLIENT_STATUS_EXITING_STR "exiting"
78
79
80 /*
81 * directory where analyzerID file are stored.
82 */
83 #define IDENT_DIR PRELUDE_CONFIG_DIR "/analyzerid"
84
85
86 /*
87 * send an heartbeat every 600 seconds by default.
88 */
89 #define DEFAULT_HEARTBEAT_INTERVAL 600
90
91
92
93 typedef struct {
94 prelude_client_t *client;
95 idmef_address_t *addr;
96 idmef_address_t *idmef_addr;
97 } node_address_data_t;
98
99
100 struct prelude_client {
101
102 int refcount;
103 int flags;
104 int status;
105
106 prelude_connection_permission_t permission;
107
108 /*
109 * information about the user/group this analyzer is running as
110 */
111 prelude_client_profile_t *profile;
112
113 /*
114 * name, analyzerid, and config file for this analyzer.
115 */
116 char *sha1sum;
117 char *config_filename;
118 prelude_bool_t config_external;
119
120 idmef_analyzer_t *analyzer;
121 idmef_analyzer_t *_analyzer_copy;
122
123 prelude_connection_pool_t *cpool;
124 prelude_timer_t heartbeat_timer;
125
126
127 prelude_msgbuf_t *msgbuf;
128 gl_lock_t msgbuf_lock;
129
130 prelude_ident_t *unique_ident;
131
132 prelude_option_t *config_file_opt;
133
134 void (*heartbeat_cb)(prelude_client_t *client, idmef_message_t *heartbeat);
135 };
136
137
138
139 extern int _prelude_internal_argc;
140 extern char *_prelude_internal_argv[1024];
141 extern int _prelude_connection_keepalive_time;
142 extern int _prelude_connection_keepalive_probes;
143 extern int _prelude_connection_keepalive_intvl;
144 prelude_option_t *_prelude_generic_optlist = NULL;
145
146
147
client_write_cb(prelude_msgbuf_t * msgbuf,prelude_msg_t * msg)148 static int client_write_cb(prelude_msgbuf_t *msgbuf, prelude_msg_t *msg)
149 {
150 prelude_client_send_msg(prelude_msgbuf_get_data(msgbuf), msg);
151 return 0;
152 }
153
154
155
generate_sha1sum(const char * filename,prelude_string_t * out)156 static int generate_sha1sum(const char *filename, prelude_string_t *out)
157 {
158 int ret;
159 size_t len, i;
160 unsigned char digest[20], *data;
161
162 ret = _prelude_load_file(filename, &data, &len);
163 if ( ret < 0 )
164 return ret;
165
166 gcry_md_hash_buffer(GCRY_MD_SHA1, digest, data, len);
167 _prelude_unload_file(data, len);
168
169 len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
170 assert(len == sizeof(digest));
171
172 for ( i = 0; i < len; i++ ) {
173 ret = prelude_string_sprintf(out, "%.2x", digest[i]);
174 if ( ret < 0 )
175 return ret;
176 }
177
178 return 0;
179 }
180
181
182
add_hb_data(idmef_heartbeat_t * hb,prelude_string_t * meaning,const char * data)183 static int add_hb_data(idmef_heartbeat_t *hb, prelude_string_t *meaning, const char *data)
184 {
185 int ret;
186 idmef_additional_data_t *ad;
187
188 ret = idmef_heartbeat_new_additional_data(hb, &ad, -1);
189 if ( ret < 0 )
190 return ret;
191
192 idmef_additional_data_set_meaning(ad, meaning);
193 idmef_additional_data_set_string_ref(ad, data);
194
195 return 0;
196 }
197
198
199
client_get_status(prelude_client_t * client)200 static const char *client_get_status(prelude_client_t *client)
201 {
202 if ( client->status == CLIENT_STATUS_RUNNING )
203 return CLIENT_STATUS_RUNNING_STR;
204
205 else if ( client->status == CLIENT_STATUS_STARTING )
206 return CLIENT_STATUS_STARTING_STR;
207
208 else if ( client->status == CLIENT_STATUS_EXITING )
209 return CLIENT_STATUS_EXITING_STR;
210
211 abort();
212 }
213
214
215
gen_heartbeat(prelude_client_t * client)216 static void gen_heartbeat(prelude_client_t *client)
217 {
218 int ret;
219 idmef_time_t *time;
220 prelude_string_t *str;
221 idmef_message_t *message;
222 idmef_heartbeat_t *heartbeat;
223
224 prelude_log_debug(2, "running heartbeat callback.\n");
225
226 ret = idmef_message_new(&message);
227 if ( ret < 0 ) {
228 prelude_perror(ret, "error creating new IDMEF message");
229 goto out;
230 }
231
232 ret = idmef_message_new_heartbeat(message, &heartbeat);
233 if ( ret < 0 ) {
234 prelude_perror(ret, "error creating new IDMEF heartbeat.\n");
235 goto out;
236 }
237
238 idmef_heartbeat_set_heartbeat_interval(heartbeat, prelude_timer_get_expire(&client->heartbeat_timer));
239
240 ret = prelude_string_new_constant(&str, "Analyzer status");
241 if ( ret < 0 )
242 goto out;
243
244 add_hb_data(heartbeat, str, client_get_status(client));
245
246 if ( client->sha1sum ) {
247 ret = prelude_string_new_constant(&str, "Analyzer SHA1");
248 if ( ret < 0 )
249 goto out;
250
251 add_hb_data(heartbeat, str, client->sha1sum);
252 }
253
254 ret = idmef_time_new_from_gettimeofday(&time);
255 if ( ret < 0 )
256 goto out;
257
258 idmef_heartbeat_set_create_time(heartbeat, time);
259 idmef_heartbeat_set_analyzer(heartbeat, idmef_analyzer_ref(client->_analyzer_copy), IDMEF_LIST_PREPEND);
260
261 if ( client->heartbeat_cb ) {
262 client->heartbeat_cb(client, message);
263 goto out;
264 }
265
266 prelude_client_send_idmef(client, message);
267
268 out:
269 idmef_message_destroy(message);
270 }
271
272
heartbeat_expire_cb(void * data)273 static void heartbeat_expire_cb(void *data)
274 {
275 prelude_client_t *client = data;
276
277 gen_heartbeat(client);
278
279 if ( client->status != CLIENT_STATUS_EXITING )
280 prelude_timer_reset(&client->heartbeat_timer);
281 }
282
283
setup_heartbeat_timer(prelude_client_t * client,int expire)284 static void setup_heartbeat_timer(prelude_client_t *client, int expire)
285 {
286 prelude_timer_set_data(&client->heartbeat_timer, client);
287 prelude_timer_set_expire(&client->heartbeat_timer, expire);
288 prelude_timer_set_callback(&client->heartbeat_timer, heartbeat_expire_cb);
289 }
290
291
292 #ifdef HAVE_IPV6
is_loopback_ipv6(struct in6_addr * addr)293 static prelude_bool_t is_loopback_ipv6(struct in6_addr *addr)
294 {
295 struct in6_addr lo;
296
297 inet_pton(AF_INET6, "::1", &lo);
298
299 return (memcmp(addr, &lo, sizeof(lo)) == 0) ? TRUE : FALSE;
300 }
301 #endif
302
303
is_loopback_ipv4(struct in_addr * addr)304 static prelude_bool_t is_loopback_ipv4(struct in_addr *addr)
305 {
306 return (ntohl(addr->s_addr) >> 24) == 127 ? TRUE : FALSE;
307 }
308
309
is_loopback(int family,void * addr)310 static prelude_bool_t is_loopback(int family, void *addr)
311 {
312 if ( family == AF_INET )
313 return is_loopback_ipv4(addr);
314
315 #ifdef HAVE_IPV6
316 else if ( family == AF_INET6 )
317 return is_loopback_ipv6(addr);
318 #endif
319
320 else
321 return FALSE;
322 }
323
324
set_analyzer_host_info(idmef_analyzer_t * analyzer,const char * node_str,const char * addr_str)325 static int set_analyzer_host_info(idmef_analyzer_t *analyzer, const char *node_str, const char *addr_str)
326 {
327 int ret;
328 idmef_node_t *node;
329 idmef_address_t *addr;
330 prelude_string_t *str;
331
332 if ( ! node_str && ! addr_str )
333 return 0;
334
335 ret = idmef_analyzer_new_node(analyzer, &node);
336 if ( ret < 0 )
337 return ret;
338
339 ret = idmef_node_new_name(node, &str);
340 if ( ret < 0 )
341 return ret;
342
343 if ( node_str && prelude_string_is_empty(str) )
344 prelude_string_set_dup(str, node_str);
345
346 if ( addr_str ) {
347 if ( ! (addr = idmef_node_get_next_address(node, NULL)) ) {
348 ret = idmef_node_new_address(node, &addr, 0);
349 if ( ret < 0 )
350 return ret;
351 }
352
353 ret = idmef_address_new_address(addr, &str);
354 if ( ret < 0 )
355 return ret;
356
357 if ( prelude_string_is_empty(str) )
358 prelude_string_set_dup(str, addr_str);
359 }
360
361 return 0;
362 }
363
364
get_fqdn(idmef_analyzer_t * analyzer,const char * nodename)365 static int get_fqdn(idmef_analyzer_t *analyzer, const char *nodename)
366 {
367 int ret;
368 void *in_addr;
369 char addr[256], *addrp = NULL;
370 struct addrinfo hints, *ai, *ais;
371
372 prelude_log_debug(1, "Detected nodename: '%s'.\n", nodename);
373
374 memset(&hints, 0, sizeof(hints));
375 hints.ai_flags = AI_CANONNAME;
376
377 ret = getaddrinfo(nodename, NULL, &hints, &ai);
378 if ( ret < 0 )
379 return ret;
380
381 if ( ai->ai_canonname ) {
382 nodename = ai->ai_canonname;
383 prelude_log_debug(1, "Found canonical name: '%s'.\n", nodename);
384 }
385
386 for ( ais = ai; ai != NULL; ai = ai->ai_next ) {
387 in_addr = prelude_sockaddr_get_inaddr(ai->ai_addr);
388 if ( ! in_addr )
389 continue;
390
391 if ( ! inet_ntop(ai->ai_family, in_addr, addr, sizeof(addr)) )
392 continue;
393
394 if ( is_loopback(ai->ai_family, in_addr) )
395 prelude_log_debug(1, "Ignoring loopback address: '%s'.\n", addr);
396 else {
397 prelude_log_debug(1, "Found address: '%s'.\n", addr);
398 addrp = addr;
399 break;
400 }
401 }
402
403 ret = set_analyzer_host_info(analyzer, nodename, addrp);
404 freeaddrinfo(ais);
405
406 return ret;
407 }
408
409
get_sys_info(idmef_analyzer_t * analyzer)410 static int get_sys_info(idmef_analyzer_t *analyzer)
411 {
412 int ret;
413 struct utsname uts;
414 prelude_string_t *str;
415
416 if ( uname(&uts) < 0 )
417 return prelude_error_from_errno(errno);
418
419 get_fqdn(analyzer, uts.nodename);
420
421 ret = prelude_string_new_dup(&str, uts.sysname);
422 if ( ret < 0 )
423 return ret;
424
425 idmef_analyzer_set_ostype(analyzer, str);
426
427 ret = prelude_string_new_dup(&str, uts.release);
428 if ( ret < 0 )
429 return ret;
430
431 idmef_analyzer_set_osversion(analyzer, str);
432
433 return 0;
434 }
435
436
fill_client_infos(prelude_client_t * client,const char * program)437 static int fill_client_infos(prelude_client_t *client, const char *program)
438 {
439 int ret;
440 prelude_string_t *str, *sha1;
441 idmef_process_t *process;
442 char buf[PATH_MAX], *name, *path;
443
444 snprintf(buf, sizeof(buf), "%" PRELUDE_PRIu64, prelude_client_profile_get_analyzerid(client->profile));
445 ret = prelude_string_new_dup(&str, buf);
446 if ( ret < 0 )
447 return ret;
448
449 idmef_analyzer_set_analyzerid(client->analyzer, str);
450
451 ret = get_sys_info(client->analyzer);
452 if ( ret < 0 )
453 return ret;
454
455 ret = idmef_analyzer_new_process(client->analyzer, &process);
456 if ( ret < 0 )
457 return ret;
458
459 idmef_process_set_pid(process, getpid());
460
461 if ( ! program || ! *program )
462 return 0;
463
464 name = path = NULL;
465 _prelude_get_file_name_and_path(program, &name, &path);
466
467 if ( name ) {
468 ret = prelude_string_new_nodup(&str, name);
469 if ( ret < 0 )
470 return ret;
471
472 idmef_process_set_name(process, str);
473 }
474
475 if ( path && name ) {
476 ret = idmef_process_new_path(process, &str);
477 if ( ret < 0 )
478 return ret;
479
480 ret = prelude_string_sprintf(str, "%s/%s", path, name);
481 if ( ret < 0 )
482 return ret;
483
484 ret = prelude_string_new(&sha1);
485 if ( ret < 0 )
486 return ret;
487
488 ret = generate_sha1sum(prelude_string_get_string(str), sha1);
489 if ( ret < 0 )
490 return ret;
491
492 ret = prelude_string_get_string_released(sha1, &client->sha1sum);
493 prelude_string_destroy(sha1);
494 }
495
496 if ( path )
497 free(path); /* copied above */
498
499 return ret;
500 }
501
502
503
504
set_node_address_category(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)505 static int set_node_address_category(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
506 {
507 idmef_address_category_t category;
508 node_address_data_t *data = context;
509
510 category = idmef_address_category_to_numeric(optarg);
511 if ( category < 0 )
512 return category;
513
514 idmef_address_set_category(data->addr, category);
515
516 return 0;
517 }
518
519
520
get_node_address_category(prelude_option_t * opt,prelude_string_t * out,void * context)521 static int get_node_address_category(prelude_option_t *opt, prelude_string_t *out, void *context)
522 {
523 node_address_data_t *data = context;
524 idmef_address_category_t category = idmef_address_get_category(data->addr);
525 return prelude_string_cat(out, idmef_address_category_to_string(category));
526 }
527
528
529
set_node_address_vlan_num(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)530 static int set_node_address_vlan_num(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
531 {
532 node_address_data_t *data = context;
533
534 if ( ! optarg )
535 idmef_address_unset_vlan_num(data->addr);
536 else
537 idmef_address_set_vlan_num(data->addr, atoi(optarg));
538
539 return 0;
540 }
541
542
543
get_node_address_vlan_num(prelude_option_t * opt,prelude_string_t * out,void * context)544 static int get_node_address_vlan_num(prelude_option_t *opt, prelude_string_t *out, void *context)
545 {
546 int32_t *num;
547 node_address_data_t *data = context;
548
549 num = idmef_address_get_vlan_num(data->addr);
550 if ( num )
551 return prelude_string_sprintf(out, "%" PRELUDE_PRId32, *num);
552
553 return 0;
554 }
555
556
557
set_node_address_vlan_name(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)558 static int set_node_address_vlan_name(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
559 {
560 int ret;
561 prelude_string_t *str = NULL;
562 node_address_data_t *data = context;
563
564 if ( optarg ) {
565 ret = prelude_string_new_dup(&str, optarg);
566 if ( ret < 0 )
567 return ret;
568 }
569
570 idmef_address_set_vlan_name(data->addr, str);
571
572 return 0;
573 }
574
575
576
get_node_address_vlan_name(prelude_option_t * opt,prelude_string_t * out,void * context)577 static int get_node_address_vlan_name(prelude_option_t *opt, prelude_string_t *out, void *context)
578 {
579 prelude_string_t *str;
580 node_address_data_t *data = context;
581
582 str = idmef_address_get_vlan_name(data->addr);
583 if ( ! str )
584 return 0;
585
586 return prelude_string_copy_ref(str, out);
587 }
588
589
590
set_node_address_address(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)591 static int set_node_address_address(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
592 {
593 int ret;
594 prelude_string_t *str = NULL;
595 node_address_data_t *data = context;
596
597 if ( optarg ) {
598 ret = prelude_string_new_dup(&str, optarg);
599 if ( ret < 0 )
600 return ret;
601 }
602
603 idmef_address_set_address(data->addr, str);
604 return 0;
605 }
606
607
608
get_node_address_address(prelude_option_t * opt,prelude_string_t * out,void * context)609 static int get_node_address_address(prelude_option_t *opt, prelude_string_t *out, void *context)
610 {
611 prelude_string_t *str;
612 node_address_data_t *data = context;
613
614 str = idmef_address_get_address(data->addr);
615 if ( ! str )
616 return 0;
617
618 return prelude_string_copy_ref(str, out);
619 }
620
621
622
set_node_address_netmask(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)623 static int set_node_address_netmask(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
624 {
625 int ret;
626 prelude_string_t *str = NULL;
627 node_address_data_t *data = context;
628
629 if ( optarg ) {
630 ret = prelude_string_new_dup(&str, optarg);
631 if ( ret < 0 )
632 return ret;
633 }
634
635 idmef_address_set_netmask(data->addr, str);
636 return 0;
637 }
638
639
640
get_node_address_netmask(prelude_option_t * opt,prelude_string_t * out,void * context)641 static int get_node_address_netmask(prelude_option_t *opt, prelude_string_t *out, void *context)
642 {
643 prelude_string_t *str;
644 node_address_data_t *data = context;
645
646 str = idmef_address_get_netmask(data->addr);
647 if ( ! str )
648 return 0;
649
650 return prelude_string_copy_ref(str, out);
651 }
652
653
654
655
set_node_address(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)656 static int set_node_address(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
657 {
658 int ret;
659 node_address_data_t *data;
660 prelude_option_context_t *octx;
661 prelude_client_t *ptr = context;
662
663 octx = prelude_option_search_context(opt, optarg);
664 if ( octx )
665 return 0;
666
667 data = malloc(sizeof(*data));
668 if ( ! data )
669 return prelude_error_from_errno(errno);
670
671 data->client = ptr;
672 data->idmef_addr = NULL;
673
674 ret = idmef_address_new(&data->addr);
675 if ( ret < 0 ) {
676 free(data);
677 return ret;
678 }
679
680 ret = prelude_option_new_context(opt, &octx, optarg, data);
681 if ( ret < 0 ) {
682 idmef_address_destroy(data->addr);
683 free(data);
684 }
685
686 return ret;
687 }
688
689
commit_node_address(prelude_option_t * opt,prelude_string_t * out,void * context)690 static int commit_node_address(prelude_option_t *opt, prelude_string_t *out, void *context)
691 {
692 int ret;
693 idmef_node_t *node;
694 idmef_analyzer_t *analyzer;
695 idmef_address_t *addr = NULL, *naddr;
696 node_address_data_t *data = context;
697
698 ret = idmef_analyzer_new_node(data->client->analyzer, &node);
699 if ( ret < 0 )
700 return ret;
701
702 if ( node && data->idmef_addr ) {
703 while ( (addr = idmef_node_get_next_address(node, addr)) ) {
704 if ( addr == data->idmef_addr ) {
705 idmef_address_destroy(addr);
706 break;
707 }
708 }
709 }
710
711 ret = idmef_address_clone(data->addr, &naddr);
712 if ( ret < 0 )
713 return ret;
714
715 data->idmef_addr = naddr;
716 idmef_node_set_address(node, naddr, -1);
717
718 if ( data->client->_analyzer_copy ) {
719 ret = idmef_analyzer_clone(data->client->analyzer, &analyzer);
720 if ( ret < 0 )
721 return ret;
722
723 idmef_analyzer_destroy(data->client->_analyzer_copy);
724 data->client->_analyzer_copy = analyzer;
725 }
726
727 return 0;
728 }
729
730
destroy_node_address(prelude_option_t * opt,prelude_string_t * out,void * context)731 static int destroy_node_address(prelude_option_t *opt, prelude_string_t *out, void *context)
732 {
733 int ret;
734 idmef_node_t *node;
735 idmef_analyzer_t *analyzer;
736 idmef_address_t *addr = NULL;
737 node_address_data_t *data = context;
738
739 node = idmef_analyzer_get_node(data->client->analyzer);
740 if ( node ) {
741 while ( (addr = idmef_node_get_next_address(node, addr)) ) {
742 if ( addr == data->idmef_addr ) {
743 idmef_address_destroy(addr);
744 break;
745 }
746 }
747 }
748
749 if ( data->client->_analyzer_copy ) {
750 ret = idmef_analyzer_clone(data->client->analyzer, &analyzer);
751 if ( ret == 0 ) {
752 idmef_analyzer_destroy(data->client->_analyzer_copy);
753 data->client->_analyzer_copy = analyzer;
754 }
755 }
756
757 idmef_address_destroy(data->addr);
758 free(data);
759
760 return 0;
761 }
762
763
764
set_node_category(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)765 static int set_node_category(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
766 {
767 int ret;
768 idmef_node_t *node;
769 idmef_node_category_t category;
770 prelude_client_t *ptr = context;
771
772 category = idmef_node_category_to_numeric(optarg);
773 if ( category < 0 )
774 return category;
775
776 ret = idmef_analyzer_new_node(ptr->analyzer, &node);
777 if ( ret < 0 )
778 return -1;
779
780 idmef_node_set_category(node, category);
781 return 0;
782 }
783
784
785
get_node_category(prelude_option_t * opt,prelude_string_t * out,void * context)786 static int get_node_category(prelude_option_t *opt, prelude_string_t *out, void *context)
787 {
788 const char *category;
789 prelude_client_t *client = context;
790 idmef_node_t *node = idmef_analyzer_get_node(client->analyzer);
791
792 if ( ! node )
793 return 0;
794
795 category = idmef_node_category_to_string(idmef_node_get_category(node));
796 if ( ! category )
797 return -1;
798
799 return prelude_string_cat(out, category);
800 }
801
802
803
set_node_location(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)804 static int set_node_location(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
805 {
806 int ret;
807 idmef_node_t *node;
808 prelude_string_t *str = NULL;
809 prelude_client_t *ptr = context;
810
811 ret = idmef_analyzer_new_node(ptr->analyzer, &node);
812 if ( ret < 0 )
813 return ret;
814
815 if ( optarg ) {
816 ret = prelude_string_new_dup(&str, optarg);
817 if ( ret < 0 )
818 return ret;
819 }
820
821 idmef_node_set_location(node, str);
822
823 return 0;
824 }
825
826
827
get_node_location(prelude_option_t * opt,prelude_string_t * out,void * context)828 static int get_node_location(prelude_option_t *opt, prelude_string_t *out, void *context)
829 {
830 prelude_string_t *str;
831 prelude_client_t *client = context;
832 idmef_node_t *node = idmef_analyzer_get_node(client->analyzer);
833
834 if ( ! node )
835 return 0;
836
837 str = idmef_node_get_location(node);
838 if ( ! str )
839 return 0;
840
841 return prelude_string_copy_ref(str, out);
842 }
843
844
845
set_node_name(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)846 static int set_node_name(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
847 {
848 int ret;
849 idmef_node_t *node;
850 prelude_string_t *str = NULL;
851 prelude_client_t *ptr = context;
852
853 ret = idmef_analyzer_new_node(ptr->analyzer, &node);
854 if ( ret < 0 )
855 return ret;
856
857 if ( optarg ) {
858 ret = prelude_string_new_dup(&str, optarg);
859 if ( ret < 0 )
860 return ret;
861 }
862
863 idmef_node_set_name(node, str);
864
865 return 0;
866 }
867
868
869
get_node_name(prelude_option_t * opt,prelude_string_t * out,void * context)870 static int get_node_name(prelude_option_t *opt, prelude_string_t *out, void *context)
871 {
872 prelude_string_t *str;
873 prelude_client_t *client = context;
874 idmef_node_t *node = idmef_analyzer_get_node(client->analyzer);
875
876 if ( ! node )
877 return 0;
878
879 str = idmef_node_get_name(node);
880 if ( ! str )
881 return 0;
882
883 return prelude_string_copy_ref(str, out);
884 }
885
886
887
888
get_analyzer_name(prelude_option_t * opt,prelude_string_t * out,void * context)889 static int get_analyzer_name(prelude_option_t *opt, prelude_string_t *out, void *context)
890 {
891 prelude_string_t *str;
892 prelude_client_t *client = context;
893
894 str = idmef_analyzer_get_name(client->analyzer);
895 if ( ! str )
896 return 0;
897
898 return prelude_string_copy_ref(str, out);
899 }
900
901
902
903
set_analyzer_name(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)904 static int set_analyzer_name(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
905 {
906 int ret;
907 prelude_string_t *str = NULL;
908 prelude_client_t *ptr = context;
909
910 if ( optarg ) {
911 ret = prelude_string_new_dup(&str, optarg);
912 if ( ret < 0 )
913 return ret;
914 }
915
916 idmef_analyzer_set_name(ptr->analyzer, str);
917 return 0;
918 }
919
920
921
get_manager_addr(prelude_option_t * opt,prelude_string_t * out,void * context)922 static int get_manager_addr(prelude_option_t *opt, prelude_string_t *out, void *context)
923 {
924 prelude_client_t *ptr = context;
925
926 if ( ! ptr->cpool || ! prelude_connection_pool_get_connection_string(ptr->cpool) )
927 return 0;
928
929 return prelude_string_cat(out, prelude_connection_pool_get_connection_string(ptr->cpool));
930 }
931
932
933
connection_pool_event_cb(prelude_connection_pool_t * pool,prelude_connection_pool_event_t event,prelude_connection_t * conn)934 static int connection_pool_event_cb(prelude_connection_pool_t *pool,
935 prelude_connection_pool_event_t event,
936 prelude_connection_t *conn)
937 {
938 int ret;
939 prelude_client_t *client;
940 prelude_msgbuf_t *msgbuf;
941 prelude_msg_t *msg = NULL;
942
943 if ( event != PRELUDE_CONNECTION_POOL_EVENT_INPUT )
944 return 0;
945
946 do {
947 ret = prelude_connection_recv(conn, &msg);
948 } while ( ret < 0 && prelude_error_get_code(ret) == PRELUDE_ERROR_EAGAIN );
949
950 if ( ret < 0 )
951 return ret;
952
953 client = prelude_connection_pool_get_data(pool);
954
955 ret = prelude_connection_new_msgbuf(conn, &msgbuf);
956 if ( ret < 0 )
957 return ret;
958
959 ret = prelude_client_handle_msg_default(client, msg, msgbuf);
960
961 prelude_msg_destroy(msg);
962 prelude_msgbuf_destroy(msgbuf);
963
964 return ret;
965 }
966
967
968
set_manager_addr(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)969 static int set_manager_addr(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
970 {
971 prelude_client_t *client = context;
972 return prelude_connection_pool_set_connection_string(client->cpool, optarg);
973 }
974
975
set_tcp_keepalive_time(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)976 static int set_tcp_keepalive_time(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
977 {
978 _prelude_connection_keepalive_time = atoi(optarg);
979 return 0;
980 }
981
982
set_tcp_keepalive_probes(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)983 static int set_tcp_keepalive_probes(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
984 {
985 _prelude_connection_keepalive_probes = atoi(optarg);
986 return 0;
987 }
988
989
set_tcp_keepalive_intvl(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)990 static int set_tcp_keepalive_intvl(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
991 {
992 _prelude_connection_keepalive_intvl = atoi(optarg);
993 return 0;
994 }
995
996
set_tls_options(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)997 static int set_tls_options(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
998 {
999 return tls_auth_init_priority(optarg);
1000 }
1001
set_heartbeat_interval(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)1002 static int set_heartbeat_interval(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
1003 {
1004 prelude_client_t *ptr = context;
1005
1006 setup_heartbeat_timer(ptr, atoi(optarg));
1007
1008 if ( ptr->status == CLIENT_STATUS_RUNNING )
1009 prelude_timer_reset(&ptr->heartbeat_timer);
1010
1011 return 0;
1012 }
1013
1014
1015
get_heartbeat_interval(prelude_option_t * opt,prelude_string_t * out,void * context)1016 static int get_heartbeat_interval(prelude_option_t *opt, prelude_string_t *out, void *context)
1017 {
1018 prelude_client_t *ptr = context;
1019 return prelude_string_sprintf(out, "%u", ptr->heartbeat_timer.expire);
1020 }
1021
1022
1023
1024
set_profile(prelude_option_t * opt,const char * optarg,prelude_string_t * err,void * context)1025 static int set_profile(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
1026 {
1027 int ret;
1028 char buf[PATH_MAX];
1029 prelude_client_t *client = context;
1030
1031 ret = prelude_client_profile_set_name(client->profile, optarg);
1032 if ( ret < 0 )
1033 return ret;
1034
1035 if ( client->config_external == TRUE )
1036 return 0;
1037
1038 prelude_client_profile_get_config_filename(client->profile, buf, sizeof(buf));
1039
1040 prelude_client_set_config_filename(client, buf);
1041 client->config_external = FALSE;
1042
1043 return 0;
1044 }
1045
1046
1047
_prelude_client_destroy(prelude_client_t * client)1048 static void _prelude_client_destroy(prelude_client_t *client)
1049 {
1050 if ( client->profile )
1051 prelude_client_profile_destroy(client->profile);
1052
1053 if ( client->sha1sum )
1054 free(client->sha1sum);
1055
1056 if ( client->msgbuf )
1057 prelude_msgbuf_destroy(client->msgbuf);
1058
1059 if ( client->analyzer )
1060 idmef_analyzer_destroy(client->analyzer);
1061
1062 if ( client->_analyzer_copy )
1063 idmef_analyzer_destroy(client->_analyzer_copy);
1064
1065 if ( client->config_filename )
1066 free(client->config_filename);
1067
1068 if ( client->cpool )
1069 prelude_connection_pool_destroy(client->cpool);
1070
1071 if ( client->unique_ident )
1072 prelude_ident_destroy(client->unique_ident);
1073
1074 free(client);
1075 }
1076
1077
1078
handle_client_error(prelude_client_t * client,int error)1079 static int handle_client_error(prelude_client_t *client, int error)
1080 {
1081 char *tmp = NULL;
1082
1083 prelude_error_code_t code;
1084 prelude_error_source_t source;
1085
1086 code = prelude_error_get_code(error);
1087 source = prelude_error_get_source(error);
1088
1089 if ( error < 0 && (code == PRELUDE_ERROR_PROFILE || source == PRELUDE_ERROR_SOURCE_CONFIG_ENGINE) ) {
1090 if ( _prelude_thread_get_error() )
1091 tmp = strdup(_prelude_thread_get_error());
1092
1093 error = prelude_error_verbose(PRELUDE_ERROR_PROFILE, "%s%s%s", tmp ? tmp : "", tmp ? "\n" : "", prelude_client_get_setup_error(client));
1094 free(tmp);
1095 }
1096
1097 return error;
1098 }
1099
1100
1101
_prelude_client_register_options(void)1102 int _prelude_client_register_options(void)
1103 {
1104 int ret;
1105 prelude_option_t *opt;
1106 prelude_option_t *root_list;
1107
1108 prelude_option_new_root(&_prelude_generic_optlist);
1109
1110 ret = prelude_option_add(_prelude_generic_optlist, &root_list,
1111 PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0,
1112 "prelude", "Prelude generic options", PRELUDE_OPTION_ARGUMENT_NONE, NULL, NULL);
1113 if ( ret < 0 )
1114 return ret;
1115
1116 ret = prelude_option_add(root_list, &opt, PRELUDE_OPTION_TYPE_CLI, 0, "profile",
1117 "Profile to use for this analyzer", PRELUDE_OPTION_ARGUMENT_REQUIRED,
1118 set_profile, NULL);
1119 if ( ret < 0 )
1120 return ret;
1121 prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_IMMEDIATE);
1122
1123 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG
1124 |PRELUDE_OPTION_TYPE_WIDE, 0, "heartbeat-interval",
1125 "Number of seconds between two heartbeat",
1126 PRELUDE_OPTION_ARGUMENT_REQUIRED,
1127 set_heartbeat_interval, get_heartbeat_interval);
1128 if ( ret < 0 )
1129 return ret;
1130
1131 ret = prelude_option_add(root_list, &opt, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG
1132 |PRELUDE_OPTION_TYPE_WIDE, 0, "server-addr",
1133 "Address where this agent should report events to (addr:port)",
1134 PRELUDE_OPTION_ARGUMENT_REQUIRED, set_manager_addr, get_manager_addr);
1135 if ( ret < 0 )
1136 return ret;
1137 prelude_option_set_priority(opt, PRELUDE_OPTION_PRIORITY_LAST);
1138
1139 ret = prelude_option_add(root_list, &opt, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_CLI, 0, "tls-options",
1140 "TLS ciphers, key exchange methods, protocols, macs, and compression options",
1141 PRELUDE_OPTION_ARGUMENT_REQUIRED, set_tls_options, NULL);
1142 if ( ret < 0 )
1143 return ret;
1144
1145 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG, 0,
1146 "tcp-keepalive-time", "Interval between the last data packet sent and the first keepalive probe",
1147 PRELUDE_OPTION_ARGUMENT_REQUIRED, set_tcp_keepalive_time, NULL);
1148 if ( ret < 0 )
1149 return ret;
1150
1151 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG, 0,
1152 "tcp-keepalive-probes", "Number of not acknowledged probes to send before considering the connection dead",
1153 PRELUDE_OPTION_ARGUMENT_REQUIRED, set_tcp_keepalive_probes, NULL);
1154 if ( ret < 0 )
1155 return ret;
1156
1157 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG, 0,
1158 "tcp-keepalive-intvl", "Interval between subsequential keepalive probes",
1159 PRELUDE_OPTION_ARGUMENT_REQUIRED, set_tcp_keepalive_intvl, NULL);
1160 if ( ret < 0 )
1161 return ret;
1162
1163 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CLI|PRELUDE_OPTION_TYPE_CFG|
1164 PRELUDE_OPTION_TYPE_WIDE, 0, "analyzer-name", "Name for this analyzer",
1165 PRELUDE_OPTION_ARGUMENT_OPTIONAL, set_analyzer_name, get_analyzer_name);
1166 if ( ret < 0 )
1167 return ret;
1168
1169 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "node-name",
1170 "Name of the equipment", PRELUDE_OPTION_ARGUMENT_OPTIONAL,
1171 set_node_name, get_node_name);
1172 if ( ret < 0 )
1173 return ret;
1174
1175 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "node-location",
1176 "Location of the equipment", PRELUDE_OPTION_ARGUMENT_OPTIONAL,
1177 set_node_location, get_node_location);
1178 if ( ret < 0 )
1179 return ret;
1180
1181 ret = prelude_option_add(root_list, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "node-category",
1182 NULL, PRELUDE_OPTION_ARGUMENT_REQUIRED, set_node_category, get_node_category);
1183 if ( ret < 0 )
1184 return ret;
1185
1186 ret = prelude_option_add(root_list, &opt, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE
1187 |PRELUDE_OPTION_TYPE_CONTEXT, 0, "node-address",
1188 "Network or hardware address of the equipment",
1189 PRELUDE_OPTION_ARGUMENT_OPTIONAL, set_node_address, NULL);
1190 if ( ret < 0 )
1191 return ret;
1192
1193 prelude_option_set_commit_callback(opt, commit_node_address);
1194 prelude_option_set_destroy_callback(opt, destroy_node_address);
1195
1196 ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "address",
1197 "Address information", PRELUDE_OPTION_ARGUMENT_OPTIONAL,
1198 set_node_address_address, get_node_address_address);
1199 if ( ret < 0 )
1200 return ret;
1201
1202 ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "netmask",
1203 "Network mask for the address, if appropriate", PRELUDE_OPTION_ARGUMENT_OPTIONAL,
1204 set_node_address_netmask, get_node_address_netmask);
1205 if ( ret < 0 )
1206 return ret;
1207
1208 ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "category",
1209 "Type of address represented", PRELUDE_OPTION_ARGUMENT_REQUIRED,
1210 set_node_address_category, get_node_address_category);
1211 if ( ret < 0 )
1212 return ret;
1213
1214 ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "vlan-name",
1215 "Name of the Virtual LAN to which the address belongs",
1216 PRELUDE_OPTION_ARGUMENT_OPTIONAL, set_node_address_vlan_name,
1217 get_node_address_vlan_name);
1218 if ( ret < 0 )
1219 return ret;
1220
1221 ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "vlan-num",
1222 "Number of the Virtual LAN to which the address belongs",
1223 PRELUDE_OPTION_ARGUMENT_OPTIONAL, set_node_address_vlan_num,
1224 get_node_address_vlan_num);
1225 if ( ret < 0 )
1226 return ret;
1227
1228 return 0;
1229 }
1230
1231
1232
1233
1234 /**
1235 * prelude_client_new:
1236 * @client: Pointer to a client object to initialize.
1237 * @profile: Default profile name for this analyzer.
1238 *
1239 * This function initialize the @client object.
1240 *
1241 * Returns: 0 on success or a negative value if an error occur.
1242 */
prelude_client_new(prelude_client_t ** client,const char * profile)1243 int prelude_client_new(prelude_client_t **client, const char *profile)
1244 {
1245 int ret;
1246 prelude_client_t *new;
1247
1248 prelude_return_val_if_fail(profile, prelude_error(PRELUDE_ERROR_ASSERTION));
1249
1250 new = calloc(1, sizeof(*new));
1251 if ( ! new )
1252 return prelude_error_from_errno(errno);
1253
1254 gl_lock_init(new->msgbuf_lock);
1255 prelude_timer_init_list(&new->heartbeat_timer);
1256
1257 new->refcount = 1;
1258 new->flags = PRELUDE_CLIENT_FLAGS_HEARTBEAT|PRELUDE_CLIENT_FLAGS_CONNECT|PRELUDE_CLIENT_FLAGS_AUTOCONFIG;
1259 new->permission = PRELUDE_CONNECTION_PERMISSION_IDMEF_WRITE;
1260
1261 ret = idmef_analyzer_new(&new->analyzer);
1262 if ( ret < 0 ) {
1263 _prelude_client_destroy(new);
1264 return ret;
1265 }
1266
1267 set_analyzer_name(NULL, profile, NULL, new);
1268
1269 ret = _prelude_client_profile_new(&new->profile);
1270 if ( ret < 0 ) {
1271 _prelude_client_destroy(new);
1272 return ret;
1273 }
1274
1275 set_profile(NULL, profile, NULL, new);
1276
1277 ret = prelude_ident_new(&new->unique_ident);
1278 if ( ret < 0 ) {
1279 _prelude_client_destroy(new);
1280 return ret;
1281 }
1282
1283 ret = prelude_connection_pool_new(&new->cpool, new->profile, new->permission);
1284 if ( ret < 0 )
1285 return ret;
1286
1287 prelude_connection_pool_set_data(new->cpool, new);
1288 prelude_connection_pool_set_flags(new->cpool, prelude_connection_pool_get_flags(new->cpool) |
1289 PRELUDE_CONNECTION_POOL_FLAGS_RECONNECT | PRELUDE_CONNECTION_POOL_FLAGS_FAILOVER);
1290 prelude_connection_pool_set_event_handler(new->cpool, PRELUDE_CONNECTION_POOL_EVENT_INPUT, connection_pool_event_cb);
1291
1292
1293 setup_heartbeat_timer(new, DEFAULT_HEARTBEAT_INTERVAL);
1294
1295
1296 ret = prelude_client_new_msgbuf(new, &new->msgbuf);
1297 if ( ret < 0 ) {
1298 _prelude_client_destroy(new);
1299 return ret;
1300 }
1301
1302 *client = new;
1303
1304 return 0;
1305 }
1306
1307
1308
prelude_client_ref(prelude_client_t * client)1309 prelude_client_t *prelude_client_ref(prelude_client_t *client)
1310 {
1311 prelude_return_val_if_fail(client, NULL);
1312
1313 client->refcount++;
1314 return client;
1315 }
1316
1317
1318
1319 /**
1320 * prelude_client_init:
1321 * @client: Pointer to a #prelude_client_t object to initialize.
1322 *
1323 * This function initialize the @client object, meaning reading generic
1324 * options from the prelude_client_new() provided configuration file
1325 * and the array of arguments specified through prelude_init().
1326 *
1327 * Calling this function is optional and should be done only if you need more
1328 * granularity between prelude_client_new() and prelude_client_start():
1329 *
1330 * prelude_client_start() will call prelude_client_init() for you if needed.
1331 *
1332 * Returns: 0 on success, -1 if an error occured.
1333 */
prelude_client_init(prelude_client_t * client)1334 int prelude_client_init(prelude_client_t *client)
1335 {
1336 int ret;
1337 prelude_string_t *err;
1338 prelude_option_warning_t old_warnings;
1339
1340 /*
1341 * Calling two time init() would result in error in
1342 * fill_client_infos(), due to idmef_analyzer_t object reuse.
1343 */
1344 if ( client->status != CLIENT_STATUS_NEED_INIT )
1345 return 0;
1346
1347 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1348
1349 prelude_option_set_warnings(0, &old_warnings);
1350
1351 ret = prelude_option_read(_prelude_generic_optlist, (const char **)&client->config_filename,
1352 &_prelude_internal_argc, _prelude_internal_argv, &err, client);
1353
1354 prelude_option_set_warnings(old_warnings, NULL);
1355
1356 if ( ret < 0 )
1357 return handle_client_error(client, ret);
1358
1359 ret = _prelude_client_profile_init(client->profile);
1360 if ( ret < 0 )
1361 return handle_client_error(client, ret);
1362
1363 ret = fill_client_infos(client, _prelude_internal_argv[0]);
1364 if ( ret < 0 )
1365 return handle_client_error(client, ret);
1366
1367 client->status = CLIENT_STATUS_INIT_DONE;
1368
1369 return 0;
1370 }
1371
1372
1373
1374
1375 /**
1376 * prelude_client_start:
1377 * @client: Pointer to a client object to initialize.
1378 *
1379 * This function start the @client object, triggering
1380 * a connection from the client to it's server if any were
1381 * specified, and sending the initial @client heartbeat.
1382 *
1383 * If @client was not initialized, then prelude_client_init()
1384 * will be called and thus this function might fail if the
1385 * client was not registered.
1386 *
1387 * Returns: 0 on success, -1 if an error occured.
1388 */
prelude_client_start(prelude_client_t * client)1389 int prelude_client_start(prelude_client_t *client)
1390 {
1391 int ret;
1392 void *credentials;
1393
1394 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1395
1396 if ( client->status == CLIENT_STATUS_NEED_INIT ) {
1397 /*
1398 * if prelude_client_init() was not called
1399 */
1400 ret = prelude_client_init(client);
1401 if ( ret < 0 )
1402 return ret;
1403 }
1404
1405 if ( client->flags & PRELUDE_CLIENT_FLAGS_CONNECT ) {
1406 if ( ! client->cpool )
1407 return prelude_error(PRELUDE_ERROR_CONNECTION_STRING);
1408
1409 ret = prelude_client_profile_get_credentials(client->profile, &credentials);
1410 if ( ret < 0 )
1411 return handle_client_error(client, ret);
1412
1413 ret = prelude_connection_pool_init(client->cpool);
1414 if ( ret < 0 )
1415 return handle_client_error(client, ret);
1416 }
1417
1418
1419 if ( (client->cpool || client->heartbeat_cb) && client->flags & PRELUDE_CLIENT_FLAGS_HEARTBEAT ) {
1420
1421 client->status = CLIENT_STATUS_STARTING;
1422 client->_analyzer_copy = client->analyzer;
1423 gen_heartbeat(client);
1424
1425 /*
1426 * We use a copy of the analyzer object from the timer,
1427 * since it might be run asynchronously.
1428 */
1429 ret = idmef_analyzer_clone(client->analyzer, &client->_analyzer_copy);
1430 if ( ret < 0 )
1431 return ret;
1432
1433 client->status = CLIENT_STATUS_RUNNING;
1434 prelude_timer_init(&client->heartbeat_timer);
1435 }
1436
1437 return 0;
1438 }
1439
1440
1441
1442 /**
1443 * prelude_client_get_analyzer:
1444 * @client: Pointer to a #prelude_client_t object.
1445 *
1446 * Provide access to the #idmef_analyzer_t object associated to @client.
1447 * This analyzer object is sent along with every alerts and heartbeats emited
1448 * by this client. The analyzer object is created by prelude_client_init().
1449 *
1450 * Returns: the #idmef_analyzer_t object associated with @client.
1451 */
prelude_client_get_analyzer(prelude_client_t * client)1452 idmef_analyzer_t *prelude_client_get_analyzer(prelude_client_t *client)
1453 {
1454 prelude_return_val_if_fail(client, NULL);
1455 return client->analyzer;
1456 }
1457
1458
1459
1460
1461 /**
1462 * prelude_client_send_msg:
1463 * @client: Pointer to a #prelude_client_t object.
1464 * @msg: pointer to a message that @client should send.
1465 *
1466 * Send @msg to the peers @client is communicating with.
1467 *
1468 * The message will be sent asynchronously if @PRELUDE_CLIENT_FLAGS_ASYNC_SEND
1469 * was set using prelude_client_set_flags() in which case the caller should
1470 * not call prelude_msg_destroy() on @msg.
1471 */
prelude_client_send_msg(prelude_client_t * client,prelude_msg_t * msg)1472 void prelude_client_send_msg(prelude_client_t *client, prelude_msg_t *msg)
1473 {
1474 prelude_return_if_fail(client);
1475 prelude_return_if_fail(msg);
1476
1477 if ( client->flags & PRELUDE_CLIENT_FLAGS_ASYNC_SEND )
1478 prelude_connection_pool_broadcast_async(client->cpool, msg);
1479 else
1480 prelude_connection_pool_broadcast(client->cpool, msg);
1481 }
1482
1483
1484
1485 /**
1486 * prelude_client_send_idmef:
1487 * @client: Pointer to a #prelude_client_t object.
1488 * @msg: pointer to an IDMEF message to be sent to @client peers.
1489 *
1490 * Send @msg to the peers @client is communicating with.
1491 *
1492 * The message will be sent asynchronously if @PRELUDE_CLIENT_FLAGS_ASYNC_SEND
1493 * was set using prelude_client_set_flags().
1494 */
prelude_client_send_idmef(prelude_client_t * client,idmef_message_t * msg)1495 void prelude_client_send_idmef(prelude_client_t *client, idmef_message_t *msg)
1496 {
1497 prelude_return_if_fail(client);
1498 prelude_return_if_fail(msg);
1499
1500 /*
1501 * we need to hold a lock since asynchronous heartbeat
1502 * could write the message buffer at the same time we do.
1503 */
1504 gl_lock_lock(client->msgbuf_lock);
1505
1506 _idmef_message_assign_missing(client, msg);
1507 idmef_message_write(msg, client->msgbuf);
1508 prelude_msgbuf_mark_end(client->msgbuf);
1509
1510 gl_lock_unlock(client->msgbuf_lock);
1511 }
1512
1513
1514
1515 /**
1516 * prelude_client_recv_msg:
1517 * @client: Pointer to a #prelude_client_t object.
1518 * @timeout: Number of millisecond to wait for a message.
1519 * @msg: Pointer where the received #prelude_msg_t should be stored.
1520 *
1521 * Wait @timeout second for a message on @client connection pool.
1522 *
1523 * A @timeout of -1, mean prelude_client_recv_msg() will block until
1524 * a message is received. A @timeout of 0 mean that it will return
1525 * immediatly.
1526 *
1527 * Returns: 0 on timeout, a negative value on error, 1 on success.
1528 */
prelude_client_recv_msg(prelude_client_t * client,int timeout,prelude_msg_t ** msg)1529 int prelude_client_recv_msg(prelude_client_t *client, int timeout, prelude_msg_t **msg)
1530 {
1531 int ret;
1532 prelude_msg_t *m = NULL;
1533 prelude_connection_t *con;
1534
1535 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1536 prelude_return_val_if_fail(msg, prelude_error(PRELUDE_ERROR_ASSERTION));
1537
1538 ret = prelude_connection_pool_recv(client->cpool, timeout, &con, &m);
1539 if ( ret <= 0 )
1540 return ret;
1541
1542 ret = prelude_client_handle_msg_default(client, m, client->msgbuf);
1543 if ( ret == 0 ) {
1544 prelude_msg_destroy(m);
1545 return 0;
1546 }
1547
1548 *msg = m;
1549 return 1;
1550 }
1551
1552
1553
1554 /**
1555 * prelude_client_recv_idmef:
1556 * @client: Pointer to a #prelude_client_t object.
1557 * @timeout: Number of second to wait for a message.
1558 * @idmef: Pointer where the received #idmef_message_t should be stored.
1559 *
1560 * Wait @timeout second for a message on @client connection pool.
1561 *
1562 * A @timeout of -1, mean prelude_client_recv_idmef() will block until
1563 * a message is received. A @timeout of 0 mean that it will return
1564 * immediatly.
1565 *
1566 * Returns: 0 on timeout, a negative value on error, 1 on success.
1567 */
prelude_client_recv_idmef(prelude_client_t * client,int timeout,idmef_message_t ** idmef)1568 int prelude_client_recv_idmef(prelude_client_t *client, int timeout, idmef_message_t **idmef)
1569 {
1570 int ret;
1571 prelude_msg_t *msg = NULL;
1572
1573 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1574 prelude_return_val_if_fail(idmef, prelude_error(PRELUDE_ERROR_ASSERTION));
1575
1576 if ( ! (client->permission & PRELUDE_CONNECTION_PERMISSION_IDMEF_READ) )
1577 return prelude_error_verbose(PRELUDE_ERROR_GENERIC,
1578 "Client should use 'idmef:r' permission to read IDMEF message");
1579
1580 ret = prelude_client_recv_msg(client, timeout, &msg);
1581 if ( ret <= 0 )
1582 return ret;
1583
1584 ret = idmef_message_new(idmef);
1585 if ( ret < 0 ) {
1586 prelude_msg_destroy(msg);
1587 return ret;
1588 }
1589
1590 ret = idmef_message_read(*idmef, msg);
1591 if ( ret < 0 ) {
1592 prelude_msg_destroy(msg);
1593 idmef_message_destroy(*idmef);
1594 return ret;
1595 }
1596
1597 idmef_message_set_pmsg(*idmef, msg);
1598
1599 return 1;
1600 }
1601
1602
1603
1604 /**
1605 * prelude_client_get_connection_pool:
1606 * @client: pointer to a #prelude_client_t object.
1607 *
1608 * Return a pointer to the #prelude_connection_pool_t object used by @client
1609 * to send messages.
1610 *
1611 * Returns: a pointer to a #prelude_connection_pool_t object.
1612 */
prelude_client_get_connection_pool(prelude_client_t * client)1613 prelude_connection_pool_t *prelude_client_get_connection_pool(prelude_client_t *client)
1614 {
1615 prelude_return_val_if_fail(client, NULL);
1616 return client->cpool;
1617 }
1618
1619
1620
1621 /**
1622 * prelude_client_set_connection_pool:
1623 * @client: pointer to a #prelude_client_t object.
1624 * @pool: pointer to a #prelude_client_pool_t object.
1625 *
1626 * Use this function in order to set your own list of peer that @client
1627 * should send message too. This might be usefull in case you don't want
1628 * this to be automated by prelude_client_init().
1629 */
prelude_client_set_connection_pool(prelude_client_t * client,prelude_connection_pool_t * pool)1630 void prelude_client_set_connection_pool(prelude_client_t *client, prelude_connection_pool_t *pool)
1631 {
1632 prelude_return_if_fail(client);
1633 prelude_return_if_fail(pool);
1634
1635 if ( client->cpool )
1636 prelude_connection_pool_destroy(client->cpool);
1637
1638 client->cpool = pool;
1639 }
1640
1641
1642
1643 /**
1644 * prelude_client_set_heartbeat_cb:
1645 * @client: pointer to a #prelude_client_t object.
1646 * @cb: pointer to a function handling heartbeat sending.
1647 *
1648 * Use if you want to override the default function used to
1649 * automatically send heartbeat to @client peers.
1650 */
prelude_client_set_heartbeat_cb(prelude_client_t * client,void (* cb)(prelude_client_t * client,idmef_message_t * hb))1651 void prelude_client_set_heartbeat_cb(prelude_client_t *client,
1652 void (*cb)(prelude_client_t *client, idmef_message_t *hb))
1653 {
1654 prelude_return_if_fail(client);
1655 prelude_return_if_fail(cb);
1656
1657 client->heartbeat_cb = cb;
1658 }
1659
1660
1661
1662 /**
1663 * prelude_client_destroy:
1664 * @client: Pointer on a client object.
1665 * @status: Exit status for the client.
1666 *
1667 * Destroy @client, and send an heartbeat containing the 'exiting'
1668 * status in case @status is PRELUDE_CLIENT_EXIT_STATUS_SUCCESS.
1669 *
1670 * This is useful for analyzer expected to be running periodically,
1671 * and that shouldn't be treated as behaving anormaly in case no
1672 * heartbeat is sent.
1673 *
1674 * Please note that your are not supposed to run this function
1675 * from a signal handler.
1676 */
prelude_client_destroy(prelude_client_t * client,prelude_client_exit_status_t status)1677 void prelude_client_destroy(prelude_client_t *client, prelude_client_exit_status_t status)
1678 {
1679 prelude_return_if_fail(client);
1680
1681 if ( --client->refcount )
1682 return;
1683
1684 prelude_timer_destroy(&client->heartbeat_timer);
1685
1686 if ( client->status >= CLIENT_STATUS_STARTING &&
1687 status == PRELUDE_CLIENT_EXIT_STATUS_SUCCESS &&
1688 client->flags & PRELUDE_CLIENT_FLAGS_HEARTBEAT ) {
1689
1690 client->status = CLIENT_STATUS_EXITING;
1691 heartbeat_expire_cb(client);
1692 }
1693
1694 _prelude_client_destroy(client);
1695 }
1696
1697
1698
1699
1700 /**
1701 * prelude_client_set_flags:
1702 * @client: Pointer on a #prelude_client_t object.
1703 * @flags: Or'd list of flags used by @client.
1704 *
1705 * Set specific flags in the @client structure.
1706 * This function can be called anytime after the creation of the
1707 * @client object.
1708 *
1709 * When settings asynchronous flags such as #PRELUDE_CLIENT_FLAGS_ASYNC_SEND
1710 * or #PRELUDE_CLIENT_FLAGS_ASYNC_TIMER, be carefull to call
1711 * prelude_client_set_flags() in the same process you want to use the
1712 * asynchronous API from. Threads aren't copied accross fork().
1713 *
1714 * Returns: 0 if setting @flags succeed, -1 otherwise.
1715 */
prelude_client_set_flags(prelude_client_t * client,prelude_client_flags_t flags)1716 int prelude_client_set_flags(prelude_client_t *client, prelude_client_flags_t flags)
1717 {
1718 int ret = 0;
1719
1720 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1721
1722 client->flags = flags;
1723
1724 if ( flags & PRELUDE_CLIENT_FLAGS_ASYNC_TIMER ) {
1725 prelude_async_set_flags(PRELUDE_ASYNC_FLAGS_TIMER);
1726 ret = prelude_async_init();
1727 }
1728
1729 if ( flags & PRELUDE_CLIENT_FLAGS_ASYNC_SEND ) {
1730 prelude_msgbuf_set_flags(client->msgbuf, PRELUDE_MSGBUF_FLAGS_ASYNC);
1731 ret = prelude_async_init();
1732 }
1733
1734 if ( ! (flags & PRELUDE_CLIENT_FLAGS_AUTOCONFIG) )
1735 prelude_client_set_config_filename(client, NULL);
1736
1737 return ret;
1738 }
1739
1740
1741
1742
1743 /**
1744 * prelude_client_get_flags:
1745 * @client: Pointer on a #prelude_client_t object.
1746 *
1747 * Get flags set through prelude_client_set_flags().
1748 *
1749 * Returns: an or'ed list of #prelude_client_flags_t.
1750 */
prelude_client_get_flags(prelude_client_t * client)1751 prelude_client_flags_t prelude_client_get_flags(prelude_client_t *client)
1752 {
1753 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1754 return client->flags;
1755 }
1756
1757
1758
1759 /**
1760 * prelude_client_get_required_permission:
1761 * @client: Pointer on a #prelude_client_t object.
1762 *
1763 * Returns: @client permission as set with prelude_client_set_required_permission()
1764 */
prelude_client_get_required_permission(prelude_client_t * client)1765 prelude_connection_permission_t prelude_client_get_required_permission(prelude_client_t *client)
1766 {
1767 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1768 return client->permission;
1769 }
1770
1771
1772
1773 /**
1774 * prelude_client_set_required_permission:
1775 * @client: Pointer on a #prelude_client_t object.
1776 * @permission: Required permission for @client.
1777 *
1778 * Set the required @permission for @client.
1779 * The default is #PRELUDE_CONNECTION_PERMISSION_IDMEF_WRITE | #PRELUDE_CONNECTION_PERMISSION_ADMIN_READ.
1780 * Value set through this function should be set before prelude_client_start().
1781 *
1782 * If the client certificate for connecting to one of the specified manager doesn't have theses permission
1783 * the client will reject the certificate and ask for registration.
1784 */
prelude_client_set_required_permission(prelude_client_t * client,prelude_connection_permission_t permission)1785 void prelude_client_set_required_permission(prelude_client_t *client, prelude_connection_permission_t permission)
1786 {
1787 prelude_return_if_fail(client);
1788
1789 if ( permission & PRELUDE_CONNECTION_PERMISSION_IDMEF_READ )
1790 prelude_connection_pool_set_event_handler(client->cpool, 0, NULL);
1791
1792 client->permission = permission;
1793 prelude_connection_pool_set_required_permission(client->cpool, permission);
1794 }
1795
1796
1797
1798 /**
1799 * prelude_client_get_config_filename:
1800 * @client: pointer on a #prelude_client_t object.
1801 *
1802 * Return the filename where @client configuration is stored.
1803 * This filename is originally set by the prelude_client_new() function.
1804 *
1805 * Returns: a pointer to @client configuration filename.
1806 */
prelude_client_get_config_filename(prelude_client_t * client)1807 const char *prelude_client_get_config_filename(prelude_client_t *client)
1808 {
1809 prelude_return_val_if_fail(client, NULL);
1810 return client->config_filename;
1811 }
1812
1813
1814
1815 /**
1816 * prelude_client_set_config_filename:
1817 * @client: pointer on a #prelude_client_t object.
1818 * @filename: Configuration file to use for this client.
1819 *
1820 * The default for a client is to use a template configuration file (idmef-client.conf).
1821 * By using this function you might override the default and provide your own
1822 * configuration file to use for @client. The format of the configuration file need
1823 * to be compatible with the Prelude format.
1824 *
1825 * Returns: 0 on success, -1 if an error occured.
1826 */
prelude_client_set_config_filename(prelude_client_t * client,const char * filename)1827 int prelude_client_set_config_filename(prelude_client_t *client, const char *filename)
1828 {
1829 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1830
1831 if ( client->config_filename ) {
1832 free(client->config_filename);
1833 client->config_filename = NULL;
1834 }
1835
1836 if ( ! filename )
1837 client->flags &= ~PRELUDE_CLIENT_FLAGS_AUTOCONFIG;
1838
1839 else {
1840 client->config_filename = strdup(filename);
1841 if ( ! client->config_filename )
1842 return prelude_error_from_errno(errno);
1843 }
1844
1845 client->config_external = TRUE;
1846
1847 return 0;
1848 }
1849
1850
1851
prelude_client_get_unique_ident(prelude_client_t * client)1852 prelude_ident_t *prelude_client_get_unique_ident(prelude_client_t *client)
1853 {
1854 prelude_return_val_if_fail(client, NULL);
1855 return client->unique_ident;
1856 }
1857
1858
1859
prelude_client_get_profile(prelude_client_t * client)1860 prelude_client_profile_t *prelude_client_get_profile(prelude_client_t *client)
1861 {
1862 prelude_return_val_if_fail(client, NULL);
1863 return client->profile;
1864 }
1865
1866
1867
1868 #ifndef PRELUDE_DISABLE_DEPRECATED
1869 /**
1870 * prelude_client_is_setup_needed:
1871 * @error: Error returned by prelude_client_start().
1872 *
1873 * This function should be called as a result of an error by
1874 * the prelude_client_start() function, to know if the analyzer
1875 * need to be registered.
1876 *
1877 * DEPRECATED: use standard error API.
1878 *
1879 * Returns: TRUE if setup is needed, FALSE otherwise.
1880 */
prelude_client_is_setup_needed(int error)1881 prelude_bool_t prelude_client_is_setup_needed(int error)
1882 {
1883 /*
1884 * Deprecated.
1885 */
1886 return FALSE;
1887 }
1888
1889
prelude_client_get_setup_error(prelude_client_t * client)1890 const char *prelude_client_get_setup_error(prelude_client_t *client)
1891 {
1892 int ret;
1893 prelude_string_t *out, *perm;
1894
1895 prelude_return_val_if_fail(client, NULL);
1896
1897 ret = prelude_string_new(&out);
1898 if ( ret < 0 )
1899 return NULL;
1900
1901 if ( client->flags & PRELUDE_CLIENT_FLAGS_CONNECT ) {
1902 ret = prelude_string_new(&perm);
1903 if ( ret < 0 ) {
1904 prelude_string_destroy(out);
1905 return NULL;
1906 }
1907
1908 prelude_connection_permission_to_string(client->permission, perm);
1909
1910 ret = prelude_string_sprintf(out, "\nProfile '%s' does not exist. In order to create it, please run:\n"
1911 "prelude-admin register \"%s\" \"%s\" <manager address> --uid %d --gid %d",
1912 prelude_client_profile_get_name(client->profile),
1913 prelude_client_profile_get_name(client->profile),
1914 prelude_string_get_string(perm),
1915 (int) prelude_client_profile_get_uid(client->profile),
1916 (int) prelude_client_profile_get_gid(client->profile));
1917
1918 prelude_string_destroy(perm);
1919
1920 } else {
1921 ret = prelude_string_sprintf(out, "\nProfile '%s' does not exist. In order to create it, please run:\n"
1922 "prelude-admin add \"%s\" --uid %d --gid %d",
1923 prelude_client_profile_get_name(client->profile),
1924 prelude_client_profile_get_name(client->profile),
1925 (int) prelude_client_profile_get_uid(client->profile),
1926 (int) prelude_client_profile_get_gid(client->profile));
1927 }
1928
1929 if ( ret < 0 )
1930 return NULL;
1931
1932 _prelude_thread_set_error(prelude_string_get_string(out));
1933 prelude_string_destroy(out);
1934
1935 return _prelude_thread_get_error();
1936 }
1937 #endif
1938
1939
1940
prelude_client_print_setup_error(prelude_client_t * client)1941 void prelude_client_print_setup_error(prelude_client_t *client)
1942 {
1943 prelude_return_if_fail(client);
1944 prelude_log(PRELUDE_LOG_WARN, "%s\n\n", prelude_client_get_setup_error(client));
1945 }
1946
1947
1948
prelude_client_handle_msg_default(prelude_client_t * client,prelude_msg_t * msg,prelude_msgbuf_t * msgbuf)1949 int prelude_client_handle_msg_default(prelude_client_t *client, prelude_msg_t *msg, prelude_msgbuf_t *msgbuf)
1950 {
1951 int ret;
1952 uint8_t tag;
1953
1954 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1955 prelude_return_val_if_fail(msg, prelude_error(PRELUDE_ERROR_ASSERTION));
1956 prelude_return_val_if_fail(msgbuf, prelude_error(PRELUDE_ERROR_ASSERTION));
1957
1958 tag = prelude_msg_get_tag(msg);
1959 if ( tag != PRELUDE_MSG_OPTION_REQUEST )
1960 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "Unexpected message type '%d' received", tag);
1961
1962 /*
1963 * lock, handle the request, send reply.
1964 */
1965 gl_lock_lock(client->msgbuf_lock);
1966
1967 ret = prelude_option_process_request(client, msg, msgbuf);
1968 prelude_msgbuf_mark_end(client->msgbuf);
1969
1970 gl_lock_unlock(client->msgbuf_lock);
1971
1972 return ret;
1973 }
1974
1975
1976
prelude_client_new_msgbuf(prelude_client_t * client,prelude_msgbuf_t ** msgbuf)1977 int prelude_client_new_msgbuf(prelude_client_t *client, prelude_msgbuf_t **msgbuf)
1978 {
1979 int ret;
1980
1981 prelude_return_val_if_fail(client, prelude_error(PRELUDE_ERROR_ASSERTION));
1982
1983 ret = prelude_msgbuf_new(msgbuf);
1984 if ( ret < 0 )
1985 return ret;
1986
1987 prelude_msgbuf_set_data(*msgbuf, client);
1988 prelude_msgbuf_set_callback(*msgbuf, client_write_cb);
1989
1990 return 0;
1991 }
1992