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