1 /*****
2 *
3 * Copyright (C) 2002-2015 CS-SI. All Rights Reserved.
4 * Author: Krzysztof Zaraska
5 *         Yoann Vandoorselaere <yoann@prelude-ids.com>
6 *
7 * This file is part of the Prelude library.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 *****/
24 
25 #include "libmissing.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <stdarg.h>
32 #include <limits.h>
33 #include <assert.h>
34 
35 #include "glthread/lock.h"
36 
37 #include "prelude-hash.h"
38 #include "prelude-log.h"
39 #include "prelude-inttypes.h"
40 #include "prelude-string.h"
41 
42 #define PRELUDE_ERROR_SOURCE_DEFAULT PRELUDE_ERROR_SOURCE_IDMEF_PATH
43 #include "prelude-error.h"
44 
45 #include "idmef-time.h"
46 #include "idmef-data.h"
47 #include "idmef-class.h"
48 #include "idmef-value.h"
49 
50 #include "idmef-object-prv.h"
51 #include "idmef-tree-wrap.h"
52 #include "idmef-path.h"
53 #include "prelude-string.h"
54 #include "prelude-linked-object.h"
55 #include "common.h"
56 
57 
58 #define MAX_DEPTH                16
59 #define MAX_NAME_LEN            128
60 #define HASH_DEFAULT_SIZE       128
61 
62 #define INDEX_UNDEFINED INT_MIN
63 #define INDEX_KEY       (INT_MIN + 1)
64 #define INDEX_FORBIDDEN (INT_MIN + 2)
65 
66 
67 typedef struct idmef_key_listed_object {
68         IDMEF_OBJECT;
69         prelude_list_t list;
70         prelude_string_t *objkey;
71 } idmef_key_listed_object_t;
72 
73 
74 typedef struct idmef_path_element {
75 
76         int index;
77         char *index_key;
78 
79         idmef_class_id_t class;
80         idmef_class_child_id_t position;
81         idmef_value_type_id_t value_type;
82 
83 } idmef_path_element_t;
84 
85 
86 struct idmef_path {
87 
88         gl_lock_t mutex;
89         char name[MAX_NAME_LEN];
90         int refcount;
91         unsigned int depth;
92         idmef_class_id_t top_class;
93 
94         idmef_path_element_t elem[MAX_DEPTH];
95 };
96 
97 
98 
99 static int _idmef_path_set(const idmef_path_t *path, idmef_class_id_t class, size_t i,
100                            int index_override, void *ptr, idmef_value_t *value);
101 
102 
103 static prelude_bool_t flush_cache = FALSE;
104 static prelude_hash_t *cached_path = NULL;
105 static gl_lock_t cached_path_mutex = gl_lock_initializer;
106 
107 
108 
path_lock_cb(void * data)109 static void path_lock_cb(void *data)
110 {
111         idmef_path_t *path = data;
112         gl_lock_lock(path->mutex);
113 }
114 
115 
path_reinit_cb(void * data)116 static void path_reinit_cb(void *data)
117 {
118         idmef_path_t *path = data;
119         gl_lock_init(path->mutex);
120 }
121 
122 
path_unlock_cb(void * data)123 static void path_unlock_cb(void *data)
124 {
125         idmef_path_t *path = data;
126         gl_lock_unlock(path->mutex);
127 }
128 
129 
130 
flush_cache_if_wanted(void * ptr)131 static void flush_cache_if_wanted(void *ptr)
132 {
133         if ( flush_cache )
134                 idmef_path_destroy(ptr);
135 }
136 
137 
138 
path_hash_func(const void * path)139 static unsigned int path_hash_func(const void *path)
140 {
141         const char *ptr = ((const idmef_path_t *) path)->name;
142         unsigned int hv = *ptr;
143 
144         if ( hv )
145                 for ( ptr += 1; *ptr; ptr++ )
146                         hv = (hv << 5) - hv + *ptr;
147 
148         return hv;
149 
150 }
151 
152 
path_key_cmp_func(const void * p1,const void * p2)153 static int path_key_cmp_func(const void *p1, const void *p2)
154 {
155         const idmef_path_t *path1 = p1;
156         const idmef_path_t *path2 = p2;
157 
158         if ( path1->top_class != path2->top_class )
159                 return -1;
160 
161         return strcmp(path1->name, path2->name);
162 }
163 
164 
165 
initialize_path_cache_if_needed(void)166 static int initialize_path_cache_if_needed(void)
167 {
168         if ( cached_path )
169                 return 0;
170 
171         return prelude_hash_new2(&cached_path, HASH_DEFAULT_SIZE, path_hash_func, path_key_cmp_func, NULL, flush_cache_if_wanted);
172 }
173 
174 
175 
build_name(idmef_path_t * path)176 static int build_name(idmef_path_t *path)
177 {
178         unsigned int i;
179         const char *name;
180         idmef_class_id_t class;
181 
182         /*
183          * we don't need gl_lock_{,un}lock since the path has no name
184          * it means that it is not in the cache and thus, not shared
185          */
186         path->name[0] = '\0';
187         class = IDMEF_CLASS_ID_MESSAGE;
188 
189         for ( i = 0; i < path->depth; i++ ) {
190 
191                 if ( i > 0 )
192                         strncat(path->name, ".", sizeof(path->name) - strlen(path->name));
193 
194                 name = idmef_path_get_name(path, i);
195                 if ( ! name )
196                         return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INTEGRITY);
197 
198                 strncat(path->name, name, sizeof(path->name) - strlen(path->name));
199 
200                 if ( path->elem[i].index != INDEX_UNDEFINED && path->elem[i].index != INDEX_FORBIDDEN ) {
201                         strncat(path->name, "(", sizeof(path->name) - strlen(path->name));
202 
203                         if ( path->elem[i].index != INDEX_KEY )
204                                 snprintf(path->name + strlen(path->name), sizeof(path->name) - strlen(path->name), "%d", path->elem[i].index);
205 
206                         else if ( path->elem[i].index_key )
207                                 strncat(path->name, path->elem[i].index_key, sizeof(path->name) - strlen(path->name));
208 
209                         strncat(path->name, ")", sizeof(path->name) - strlen(path->name));
210                 }
211 
212                 class = idmef_class_get_child_class(class, path->elem[i].position);
213                 if ( class < 0 && i < path->depth - 1 )
214                         return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INTEGRITY);
215         }
216 
217         return 0;
218 }
219 
220 
221 
222 
223 static int idmef_path_get_internal(idmef_value_t **ret, const idmef_path_t *path,
224                                    unsigned int depth, void *parent, idmef_class_id_t parent_class);
225 
226 
has_index_key(prelude_list_t * elem,const char * index_key)227 static inline prelude_bool_t has_index_key(prelude_list_t *elem, const char *index_key)
228 {
229         idmef_key_listed_object_t *obj = prelude_list_entry(elem, idmef_key_listed_object_t, list);
230         return (obj->objkey && strcmp(prelude_string_get_string_or_default(obj->objkey, ""), index_key) == 0) ? TRUE : FALSE;
231 }
232 
233 
set_index_key(const idmef_path_element_t * elem,void * ptr)234 static int set_index_key(const idmef_path_element_t *elem, void *ptr)
235 {
236         idmef_key_listed_object_t *obj = ptr;
237 
238         if ( ! elem->index_key )
239                 return 0;
240 
241         if ( obj->objkey )
242                 prelude_string_destroy(obj->objkey);
243 
244         return prelude_string_new_dup(&obj->objkey, elem->index_key);
245 }
246 
247 
248 
idmef_path_get_list_internal(idmef_value_t ** value_list,const idmef_path_t * path,int depth,prelude_list_t * list,idmef_class_id_t parent_class)249 static int idmef_path_get_list_internal(idmef_value_t **value_list,
250                                         const idmef_path_t *path, int depth,
251                                         prelude_list_t *list, idmef_class_id_t parent_class)
252 {
253         int ret;
254         prelude_list_t *tmp;
255         idmef_value_t *value;
256         unsigned int cnt = 0;
257 
258         ret = idmef_value_new_list(value_list);
259         if ( ret < 0 )
260                 return ret;
261 
262         prelude_list_for_each(list, tmp) {
263                 value = NULL;
264 
265                 if ( path->elem[depth - 1].index_key && ! has_index_key(tmp, path->elem[depth - 1].index_key) )
266                         continue;
267 
268                 if ( parent_class >= 0 )
269                         ret = idmef_path_get_internal(&value, path, depth, idmef_linked_object_get_object(tmp), parent_class);
270                 else {
271                         idmef_value_type_id_t type = path->elem[depth - 1].value_type;
272 
273                         ret = idmef_value_new(&value, type, tmp);
274                         if ( ret == 0 ) {
275                                 idmef_value_type_t vt;
276 
277                                 vt.id = type;
278                                 vt.data.string_val = (void *) tmp;
279 
280                                 ret = idmef_value_type_ref(&vt);
281                                 if ( ret < 0 )
282                                         idmef_value_destroy(value);
283                         }
284                 }
285 
286                 if ( ret < 0 ) {
287                         idmef_value_destroy(*value_list);
288                         return ret;
289                 }
290 
291                 ret = idmef_value_list_add(*value_list, value);
292                 if ( ret < 0 ) {
293                         idmef_value_destroy(*value_list);
294                         return ret;
295                 }
296 
297                 cnt++;
298         }
299 
300         if ( ! cnt ) {
301                 idmef_value_destroy(*value_list);
302                 *value_list = NULL;
303         }
304 
305         return cnt;
306 }
307 
308 
idmef_path_get_nth_internal(idmef_value_t ** value,const idmef_path_t * path,unsigned int depth,prelude_list_t * list,idmef_class_id_t parent_class,int which,const char * index_key)309 static int idmef_path_get_nth_internal(idmef_value_t **value, const idmef_path_t *path,
310                                        unsigned int depth, prelude_list_t *list,
311                                        idmef_class_id_t parent_class, int which, const char *index_key)
312 {
313         int cnt = 0;
314         prelude_list_t *tmp = NULL;
315 
316         if ( which >= 0 ) {
317                 prelude_list_for_each(list, tmp) {
318                         if ( cnt++ == which )
319                                 return idmef_path_get_internal(value, path, depth, idmef_linked_object_get_object(tmp), parent_class);
320                 }
321         } else {
322                 which = -which;
323                 which--; /* With negative value, -1 is the base, translate to 0 */
324 
325                 prelude_list_for_each_reversed(list, tmp) {
326                         if ( cnt++ == which )
327                                 return idmef_path_get_internal(value, path, depth, idmef_linked_object_get_object(tmp), parent_class);
328                 }
329         }
330 
331         return 0;
332 }
333 
334 
335 
idmef_path_get_internal(idmef_value_t ** value,const idmef_path_t * path,unsigned int depth,void * parent,idmef_class_id_t parent_class)336 static int idmef_path_get_internal(idmef_value_t **value, const idmef_path_t *path,
337                                    unsigned int depth, void *parent, idmef_class_id_t parent_class)
338 {
339         void *child;
340         int ret, which;
341         idmef_class_id_t child_class;
342         idmef_class_child_id_t child_id;
343 
344         if ( depth < path->depth ) {
345 
346                 child_id = path->elem[depth].position;
347 
348                 ret = idmef_class_get_child(parent, parent_class, child_id, &child);
349                 if ( ret < 0 )
350                         return ret;
351 
352                 if ( ! child ) {
353                         *value = NULL;
354                         return 0;
355                 }
356 
357                 child_class = idmef_class_get_child_class(parent_class, child_id);
358                 which = path->elem[depth].index;
359 
360                 if ( which == INDEX_FORBIDDEN )
361                         return idmef_path_get_internal(value, path, depth + 1, child, child_class);
362 
363                 if ( which == INDEX_UNDEFINED || which == INDEX_KEY || which == IDMEF_LIST_APPEND || which == IDMEF_LIST_PREPEND )
364                         return idmef_path_get_list_internal(value, path, depth + 1, child, child_class);
365 
366                 return idmef_path_get_nth_internal(value, path, depth + 1, child, child_class, which, path->elem[depth].index_key);
367         }
368 
369         if ( parent_class < 0 || (path->depth > 0 && path->elem[path->depth - 1].value_type == IDMEF_VALUE_TYPE_ENUM) ) {
370                 *value = parent;
371                 return 1;
372         }
373 
374         ret = (ret = idmef_value_new_class(value, parent_class, parent) < 0) ? ret : 1;
375         if ( ret == 1 )
376                 idmef_class_ref(parent_class, parent);
377 
378         return ret;
379 }
380 
381 
delete_listed_child(void * parent,idmef_class_id_t class,const idmef_path_element_t * elem)382 static void delete_listed_child(void *parent, idmef_class_id_t class, const idmef_path_element_t *elem)
383 {
384         int ret;
385         void *obj;
386         prelude_list_t *head, *tmp, *bkp;
387 
388         ret = idmef_class_get_child(parent, class, elem->position, (void *) &head);
389         if ( ret < 0 )
390                 return;
391 
392         prelude_list_for_each_safe(head, tmp, bkp) {
393                 obj = idmef_linked_object_get_object(tmp);
394 
395                 if ( elem->index_key && ! has_index_key(obj, elem->index_key) )
396                         continue;
397 
398                 /*
399                  * The object might be referenced from other place than
400                  * this message, in which case idmef_class_destroy()
401                  * will only decrease it's reference count.
402                  *
403                  * We manually call prelude_list_del_init() in order to
404                  * disassociate the object from the message.
405                  */
406                 prelude_list_del_init(tmp);
407                 idmef_class_destroy(idmef_class_get_child_class(class, elem->position), obj);
408         }
409 }
410 
411 
412 
_idmef_path_set_undefined_not_last(const idmef_path_t * path,const idmef_path_element_t * elem,idmef_class_id_t class,size_t i,void * ptr,idmef_value_t * value)413 static int _idmef_path_set_undefined_not_last(const idmef_path_t *path, const idmef_path_element_t *elem,
414                                               idmef_class_id_t class, size_t i, void *ptr, idmef_value_t *value)
415 {
416         int j = 0, ret;
417         idmef_value_t *val;
418         prelude_list_t *head, *tmp, *bkp;
419 
420         assert(idmef_class_is_child_list(class, elem->position));
421 
422         ret = idmef_class_get_child(ptr, class, elem->position, (void *) &head);
423         if ( ret < 0 )
424                 return ret;
425 
426         prelude_list_for_each_safe(head, tmp, bkp) {
427                 if ( elem->index_key && ! has_index_key(tmp, elem->index_key) )
428                         continue;
429 
430                 if ( value && idmef_value_is_list(value) ) {
431                         ret = idmef_value_get_nth2(value, j++, &val);
432                         if ( ret <= 0 )
433                                 return ret;
434                 } else {
435                         j = 1;
436                         val = value;
437                 }
438 
439                 ret = _idmef_path_set(path, elem->class, i + 1, 0, idmef_linked_object_get_object(tmp), val);
440                 if ( ret < 0 )
441                         return ret;
442         }
443 
444         for ( ; value && j < idmef_value_get_count(value); j++ ) {
445                 ret = _idmef_path_set(path, class, i, IDMEF_LIST_APPEND, ptr, idmef_value_get_nth(value, j));
446                 if ( ret < 0 )
447                         return ret;
448 
449                 ret = set_index_key(elem, idmef_linked_object_get_object(head->prev));
450                 if ( ret < 0 )
451                         return ret;
452         }
453 
454         return ret;
455 }
456 
457 
458 
ad_magic_set_datatype(idmef_additional_data_t * data,idmef_value_type_id_t vtype)459 static void ad_magic_set_datatype(idmef_additional_data_t *data, idmef_value_type_id_t vtype)
460 {
461         idmef_additional_data_type_t type;
462 
463         /*
464          * In case the user has already set the type member, do nothing.
465          */
466         if ( _idmef_additional_data_type_is_set(data) != 0 )
467                 return;
468 
469         if ( vtype >= IDMEF_VALUE_TYPE_INT8 && vtype <= IDMEF_VALUE_TYPE_UINT64 )
470                 type = IDMEF_ADDITIONAL_DATA_TYPE_INTEGER;
471 
472         else if ( vtype == IDMEF_VALUE_TYPE_FLOAT || vtype == IDMEF_VALUE_TYPE_DOUBLE )
473                 type = IDMEF_ADDITIONAL_DATA_TYPE_REAL;
474 
475         else if ( vtype == IDMEF_VALUE_TYPE_STRING )
476                 type = IDMEF_ADDITIONAL_DATA_TYPE_STRING;
477 
478         else if ( vtype == IDMEF_VALUE_TYPE_DATA )
479                 type = IDMEF_ADDITIONAL_DATA_TYPE_BYTE_STRING;
480 
481        else if ( vtype == IDMEF_VALUE_TYPE_TIME )
482                 type = IDMEF_ADDITIONAL_DATA_TYPE_DATE_TIME;
483 
484         else
485                 return;
486 
487         idmef_additional_data_set_type(data, type);
488 }
489 
490 
491 
_idmef_path_set(const idmef_path_t * path,idmef_class_id_t class,size_t i,int index_override,void * ptr,idmef_value_t * value)492 static int _idmef_path_set(const idmef_path_t *path, idmef_class_id_t class, size_t i,
493                            int index_override, void *ptr, idmef_value_t *value)
494 {
495         void *prevptr = NULL;
496         int ret, index, j;
497         prelude_bool_t is_last_element;
498         idmef_value_type_id_t tid;
499         const idmef_path_element_t *elem;
500         idmef_class_id_t parent_class;
501 
502         parent_class = (class == IDMEF_CLASS_ID_MESSAGE) ? class : path->elem[i - 1].class;
503 
504         for ( ; i < path->depth; i++ ) {
505 
506                 elem = &path->elem[i];
507                 index = (index_override) ? index_override : elem->index;
508                 index_override = 0;
509                 is_last_element = (i == (path->depth - 1));
510 
511                 if ( index == INDEX_UNDEFINED || index == INDEX_KEY ) {
512                         if ( ! is_last_element )
513                                 return _idmef_path_set_undefined_not_last(path, elem, class, i, ptr, value);
514                         else {
515                                 delete_listed_child(ptr, class, elem);
516 
517                                 for ( j = 0; value && j < idmef_value_get_count(value); j++ ) {
518                                         ret = _idmef_path_set(path, class, i, IDMEF_LIST_APPEND, ptr, idmef_value_get_nth(value, j));
519                                         if ( ret < 0 )
520                                                 return ret;
521 
522                                         if ( index == INDEX_KEY ) {
523                                                 prelude_list_t *head;
524 
525                                                 ret = idmef_class_get_child(ptr, class, elem->position, (void *) &head);
526                                                 if ( ret < 0 )
527                                                         return ret;
528 
529                                                 ret = set_index_key(elem, head->prev);
530                                                 if ( ret < 0 )
531                                                         return ret;
532                                         }
533                                 }
534 
535                                 return 0;
536                         }
537                 }
538 
539                 parent_class = class;
540 
541                 if ( value || ! is_last_element ) {
542                         prevptr = ptr;
543 
544                         ret = idmef_class_new_child(ptr, class, elem->position, index, &ptr);
545                         if ( ret < 0 )
546                                 return ret;
547 
548                         class = idmef_class_get_child_class(class, elem->position);
549                         assert( ! (class < 0 && i < path->depth - 1) );
550                 }
551         }
552 
553         elem = &path->elem[path->depth - 1];
554         if ( ! value )
555                 return idmef_class_destroy_child(ptr, parent_class, elem->position, elem->index);
556 
557         tid = idmef_class_get_child_value_type(parent_class, elem->position);
558         if ( parent_class == IDMEF_CLASS_ID_ADDITIONAL_DATA && tid == IDMEF_VALUE_TYPE_DATA && prevptr )
559                 ad_magic_set_datatype(prevptr, idmef_value_get_type(value));
560 
561         return _idmef_value_copy_internal(value, tid, class, ptr);
562 }
563 
564 
565 
566 /**
567  * idmef_path_get:
568  * @path: Pointer to a #idmef_path_t object.
569  * @message: Pointer to a #idmef_message_t object.
570  * @ret: Address where to store the retrieved #idmef_value_t.
571  *
572  * This function retrieves the value for @path within @message,
573  * and stores it into the provided @ret address of type #idmef_value_t.
574  *
575  * Returns: The number of element retrieved, or a negative value if an error occured.
576  */
idmef_path_get(const idmef_path_t * path,void * obj,idmef_value_t ** ret)577 int idmef_path_get(const idmef_path_t *path, void *obj, idmef_value_t **ret)
578 {
579         idmef_object_t *object = obj;
580 
581         if ( object->_idmef_object_id != path->top_class )
582                 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "path for object '%s' used with '%s' object root",
583                                              idmef_class_get_name(path->top_class), idmef_class_get_name(object->_idmef_object_id));
584 
585         return idmef_path_get_internal(ret, path, 0, object, object->_idmef_object_id);
586 }
587 
588 
589 
590 /**
591  * idmef_path_set:
592  * @path: Pointer to a #idmef_path_t object.
593  * @message: Pointer to a #idmef_message_t object.
594  * @value: Pointer to a #idmef_value_t object.
595  *
596  * This function sets the provided @value for @path within @message.
597  *
598  * Returns: 0 on success, a negative value if an error occured.
599  */
idmef_path_set(const idmef_path_t * path,void * obj,idmef_value_t * value)600 int idmef_path_set(const idmef_path_t *path, void *obj, idmef_value_t *value)
601 {
602         idmef_object_t *object = obj;
603 
604         if ( path->depth < 1 )
605                 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "Path with depth of 0 are not allowed");
606 
607         if ( object->_idmef_object_id != path->top_class )
608                 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "path for object '%s' used with '%s' object root",
609                                              idmef_class_get_name(path->top_class), idmef_class_get_name(object->_idmef_object_id));
610 
611 
612         return _idmef_path_set(path, object->_idmef_object_id, 0, 0, object, value);
613 }
614 
615 
616 
copy_path_name(idmef_path_t * path,const char * buffer)617 static int copy_path_name(idmef_path_t *path, const char *buffer)
618 {
619         size_t len;
620 
621         len = strlen(buffer) + 1;
622         if ( len >= sizeof(path->name) )
623                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_LENGTH);
624 
625         memcpy(path->name, buffer, len);
626 
627         return 0;
628 }
629 
630 
631 
632 /*
633  * idmef_object_create returns:
634  * -1 if something wrong happen
635  * 0 for a new empty object
636  * 1 for an existing object already in the cache
637  */
idmef_path_create(idmef_path_t ** path,idmef_class_id_t rootclass,const char * buffer)638 static int idmef_path_create(idmef_path_t **path, idmef_class_id_t rootclass, const char *buffer)
639 {
640         int ret;
641         idmef_path_t tmp;
642 
643         ret = copy_path_name(&tmp, buffer);
644         if ( ret < 0 )
645                 return ret;
646 
647         tmp.top_class = rootclass;
648 
649         gl_lock_lock(cached_path_mutex);
650 
651         ret = initialize_path_cache_if_needed();
652         if ( ret < 0 ) {
653                 gl_lock_unlock(cached_path_mutex);
654                 return ret;
655         }
656 
657         *path = prelude_hash_get(cached_path, &tmp);
658         gl_lock_unlock(cached_path_mutex);
659 
660         if ( *path )
661                 return 1;
662 
663         *path = calloc(1, sizeof(**path));
664         if ( ! *path )
665                 return prelude_error_from_errno(errno);
666 
667         (*path)->refcount = 1;
668         gl_lock_init((*path)->mutex);
669 
670         return 0;
671 }
672 
673 
674 
675 /*
676  * return 1 if we are reading the last object.
677  * return 0 if reading an object.
678  * return -1 if there is no more things to read.
679  */
parse_path_token(char ** sptr,char ** out)680 static int parse_path_token(char **sptr, char **out)
681 {
682         char *buf = *sptr, *ptr;
683 
684         if ( *buf == '\0' )
685                 *buf++ = '.';
686 
687         *out = buf;
688 
689         ptr = strchr(buf, '.');
690         if ( ! ptr )
691                 return -1;
692 
693         *ptr = '\0';
694         *sptr = ptr;
695 
696         return 0;
697 }
698 
699 
700 
idmef_path_parse_new(idmef_path_t * path,idmef_class_id_t rootclass,const char * buffer)701 static int idmef_path_parse_new(idmef_path_t *path, idmef_class_id_t rootclass, const char *buffer)
702 {
703         int ret, index = -1, is_last;
704         unsigned int depth = 0;
705         char *endptr, *ptr, *ptr2, *end;
706         idmef_class_child_id_t child = 0;
707         idmef_class_id_t class;
708         idmef_value_type_id_t vtype;
709 
710         ret = copy_path_name(path, buffer);
711         if ( ret < 0 )
712                 return ret;
713 
714         end = ptr = NULL;
715         endptr = path->name;
716         path->top_class = class = rootclass;
717 
718         do {
719                 index = INDEX_UNDEFINED;
720                 is_last = parse_path_token(&endptr, &ptr);
721 
722                 ptr2 = strchr(ptr, '(');
723                 if ( ptr2 ) {
724                         char *errptr = NULL;
725                         char *tok = ptr2 + 1;
726 
727                         end = strchr(ptr2, ')');
728                         if ( ! end )
729                                 return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "Malformed IDMEFPath index : missing ')' character");
730 
731                         *end = *ptr2 = '\0';
732                         if ( strcmp(tok, "<<") == 0 )
733                                 index = IDMEF_LIST_PREPEND;
734 
735                         else if ( strcmp(tok, ">>") == 0 )
736                                 index = IDMEF_LIST_APPEND;
737 
738                         else if ( (*tok == '\'' || *tok == '"') && *(tok + strlen(tok) - 1) == *tok ) {
739                                 index = INDEX_KEY;
740                                 path->elem[depth].index_key = strndup(tok + 1, strlen(tok) - 2);
741                         }
742 
743                         else if ( strcmp(ptr2 + 1, "*") != 0 ) {
744                                 index = strtol(ptr2 + 1, &errptr, 0);
745                                 if ( index == 0 && errptr == tok )
746                                         return prelude_error_verbose(PRELUDE_ERROR_GENERIC, "Invalid index specified : `%s`", tok);
747                         }
748                         *end = ')';
749                 }
750 
751                 child = idmef_class_find_child(class, ptr);
752                 if ( child < 0 )
753                         return child;
754 
755                 path->elem[depth].position = child;
756 
757                 if ( ptr2 )
758                         *ptr2 = '(';
759 
760                 if ( index == INDEX_UNDEFINED )
761                         path->elem[depth].index = idmef_class_is_child_list(class, child) ? INDEX_UNDEFINED : INDEX_FORBIDDEN;
762                 else {
763                         if ( ! idmef_class_is_child_list(class, child) )
764                                 return prelude_error_verbose(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN,
765                                                              "Invalid IDMEF path element '%s': indexing not supported", ptr);
766 
767                         if ( index == INDEX_KEY && ! idmef_class_is_child_keyed_list(class, child) )
768                                 return prelude_error_verbose(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN,
769                                                              "Invalid IDMEF path element '%s': key not supported as index", ptr);
770 
771                         path->elem[depth].index = index;
772                 }
773 
774                 /* The last object may not be a structure */
775                 vtype = path->elem[depth].value_type = idmef_class_get_child_value_type(class, child);
776                 if ( vtype != IDMEF_VALUE_TYPE_CLASS && ! is_last )
777                         return prelude_error_verbose(PRELUDE_ERROR_GENERIC,
778                                                      "IDMEF element '%s' is a leaf and thus has no child '%s'",
779                                                      ptr, endptr + 1);
780 
781                 class = path->elem[depth].class = idmef_class_get_child_class(class, child);
782                 if ( ++depth == MAX_DEPTH )
783                         return prelude_error(PRELUDE_ERROR_IDMEF_PATH_DEPTH);
784 
785         } while ( ! is_last );
786 
787         path->depth = depth;
788 
789         return 0;
790 }
791 
792 
793 
794 
795 /**
796  * idmef_path_new_from_root_fast:
797  * @path: Address where to store the created #idmef_path_t object.
798  * @rootclass: #idmef_class_id_t ID of the root path.
799  * @buffer: Name of the path to create.
800  *
801  * Creates a #idmef_path_t object whom root is @rootclass pointing
802  * to @buffer, and stores it within @path.
803  *
804  * Returns: 0 on success, or a negative value if an error occured.
805  */
idmef_path_new_from_root_fast(idmef_path_t ** path,idmef_class_id_t rootclass,const char * buffer)806 int idmef_path_new_from_root_fast(idmef_path_t **path, idmef_class_id_t rootclass, const char *buffer)
807 {
808         int ret;
809 
810         prelude_return_val_if_fail(buffer, prelude_error(PRELUDE_ERROR_ASSERTION));
811 
812         ret = idmef_path_create(path, rootclass, buffer);
813         if ( ret < 0 )
814                 return ret;
815 
816         if ( ret == 1 ) {
817                 idmef_path_ref(*path);
818                 return 0;
819         }
820 
821         if ( *buffer == '\0' )
822                 (*path)->elem[0].class = IDMEF_CLASS_ID_MESSAGE;
823         else {
824                 ret = idmef_path_parse_new(*path, rootclass, buffer);
825                 if ( ret < 0 ) {
826                         gl_lock_destroy((*path)->mutex);
827                         free(*path);
828                         return ret;
829                 }
830         }
831 
832         gl_lock_lock(cached_path_mutex);
833 
834         if ( prelude_hash_add(cached_path, *path, *path) < 0 ) {
835 
836                 gl_lock_destroy((*path)->mutex);
837                 free(*path);
838                 gl_lock_unlock(cached_path_mutex);
839                 return ret;
840         }
841 
842         gl_lock_unlock(cached_path_mutex);
843 
844         idmef_path_ref(*path);
845 
846         return 0;
847 }
848 
849 
850 
851 
852 /**
853  * idmef_path_new_fast:
854  * @path: Address where to store the created #idmef_path_t object.
855  * @buffer: Name of the path to create.
856  *
857  * Creates a #idmef_path_t object pointing to @buffer, and stores it within @path.
858  *
859  * Returns: 0 on success, or a negative value if an error occured.
860  */
idmef_path_new_fast(idmef_path_t ** path,const char * buffer)861 int idmef_path_new_fast(idmef_path_t **path, const char *buffer)
862 {
863         return idmef_path_new_from_root_fast(path, IDMEF_CLASS_ID_MESSAGE, buffer);
864 }
865 
866 
867 
868 /**
869  * idmef_path_new_v:
870  * @path: Address where to store the created #idmef_path_t object.
871  * @format: Format string.
872  * @args: Pointer to a variable argument list.
873  *
874  * Creates an #idmef_path_t object pointing to the provided format
875  * string @format and @args, and stores it within @path.
876  *
877  * Returns: 0 on success, or a negative value if an error occured.
878  */
idmef_path_new_v(idmef_path_t ** path,const char * format,va_list args)879 int idmef_path_new_v(idmef_path_t **path, const char *format, va_list args)
880 {
881         int ret;
882         char buffer[MAX_NAME_LEN];
883 
884         prelude_return_val_if_fail(format, prelude_error(PRELUDE_ERROR_ASSERTION));
885 
886         ret = vsnprintf(buffer, sizeof(buffer), format, args);
887         if ( ret < 0 || (size_t) ret > sizeof(buffer) - 1 )
888                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_LENGTH);
889 
890         return idmef_path_new_fast(path, buffer);
891 }
892 
893 
894 
895 /**
896  * idmef_path_new:
897  * @path: Address where to store the created #idmef_path_t object.
898  * @format: Format string.
899  * @...: Arguments list.
900  *
901  * Creates an #idmef_path_t object pointing to the provided format
902  * string @format and @..., and stores it within @path.
903  *
904  * Returns: 0 on success, or a negative value if an error occured.
905  */
idmef_path_new(idmef_path_t ** path,const char * format,...)906 int idmef_path_new(idmef_path_t **path, const char *format, ...)
907 {
908         int ret;
909         va_list args;
910 
911         prelude_return_val_if_fail(format, prelude_error(PRELUDE_ERROR_ASSERTION));
912 
913         va_start(args, format);
914         ret = idmef_path_new_v(path, format, args);
915         va_end(args);
916 
917         return ret;
918 }
919 
920 
921 
922 /**
923  * idmef_path_get_class:
924  * @path: Pointer to an #idmef_path_t object.
925  * @depth: Depth of @path to retrieve the #idmef_class_id_t from.
926  *
927  * Retrieves the #idmef_class_id_t value for the element of @path
928  * located at @depth. If depth is -1, the last element depth is addressed.
929  *
930  * Returns: The #idmef_class_id_t for the elemnt, or a negative value if an error occured.
931  */
idmef_path_get_class(const idmef_path_t * path,int depth)932 idmef_class_id_t idmef_path_get_class(const idmef_path_t *path, int depth)
933 {
934         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
935 
936         if ( depth < 0 )
937                 depth = path->depth - 1;
938 
939         if ( path->depth == 0 && depth < 0 )
940                 return IDMEF_CLASS_ID_MESSAGE;
941 
942         return path->elem[depth].class;
943 }
944 
945 
946 
947 /**
948  * idmef_path_get_value_type:
949  * @path: Pointer to an #idmef_path_t object.
950  * @depth: Depth of @path to retrieve the #idmef_value_type_id_t from.
951  *
952  * Retrieves the #idmef_value_type_id_t identifying the type of value
953  * acceptable for this path element, for the @path element located at
954  * @depth. If depth is -1, the last element depth is addressed.
955  *
956  * Returns: The #idmef_value_type_id_t for the element, or a negative value if an error occured.
957  */
idmef_path_get_value_type(const idmef_path_t * path,int depth)958 idmef_value_type_id_t idmef_path_get_value_type(const idmef_path_t *path, int depth)
959 {
960         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
961 
962         if ( depth < 0 )
963                 depth = path->depth - 1;
964 
965         if ( path->depth == 0 && depth < 0 )
966                 return IDMEF_VALUE_TYPE_CLASS;
967 
968         return path->elem[depth].value_type;
969 }
970 
971 
972 
invalidate(idmef_path_t * path)973 static inline int invalidate(idmef_path_t *path)
974 {
975         int ret;
976 
977         gl_lock_lock(path->mutex);
978 
979         if ( path->refcount == 1 ) {
980                 gl_lock_unlock(path->mutex);
981                 return 0; /* not cached */
982         }
983 
984         /*
985          * We can modify the path only if the caller
986          * is the only entity that has pointer to it.
987          *
988          * The path should have refcount equal to 1 or 2.
989          * If refcount is equal to 1, it means that only the caller
990          * has the pointer to the path, so we can modify it.
991          *
992          * If refcount is equal to 2, that means that the path
993          * can also be present in the cached_path hash,
994          * so it should be removed from the hash before modification.
995          * If, however, refcount is 2 but the path is not present
996          * in the hash, we cannot continue, as there exists
997          * another entity that has pointer to the path.
998          */
999 
1000         if ( path->refcount > 2 ) {
1001                 gl_lock_unlock(path->mutex);
1002                 return -1;
1003         }
1004 
1005         if ( path->refcount == 2 ) {
1006                 gl_lock_lock(cached_path_mutex);
1007                 ret = prelude_hash_elem_destroy(cached_path, path);
1008                 gl_lock_unlock(cached_path_mutex);
1009 
1010                 if ( ret == 0 )
1011                         path->refcount--;  /* path was present in a hash */
1012                 else {
1013                         gl_lock_unlock(path->mutex);
1014                         return -1; /* path was not present in a hash and refcount != 1 */
1015                 }
1016         }
1017 
1018         gl_lock_unlock(path->mutex);
1019 
1020         return 0; /* successfully invalidated */
1021 }
1022 
1023 
1024 
1025 /**
1026  * idmef_path_set_index:
1027  * @path: Pointer to an #idmef_path_t object.
1028  * @depth: Depth of @path to set @index for.
1029  * @index: Index for the provided element @depth.
1030  *
1031  * Modifies @index for the element located at @depth of provided @path.
1032  * This function is only applicable for element that accept listed value.
1033  *
1034  * Returns: 0 on success, a negative value if an error occured.
1035  */
idmef_path_set_index(idmef_path_t * path,unsigned int depth,int index)1036 int idmef_path_set_index(idmef_path_t *path, unsigned int depth, int index)
1037 {
1038         int ret;
1039 
1040         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1041         prelude_return_val_if_fail(depth < path->depth, prelude_error(PRELUDE_ERROR_IDMEF_PATH_DEPTH));
1042 
1043         if ( index == INDEX_FORBIDDEN || index == INDEX_KEY )
1044                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_RESERVED);
1045 
1046         if ( path->elem[depth].index == INDEX_FORBIDDEN )
1047                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN);
1048 
1049         ret = invalidate(path);
1050         if ( ret < 0 )
1051                 return ret;
1052 
1053         if ( path->elem[depth].index == INDEX_KEY )
1054                 free(path->elem[depth].index_key);
1055 
1056         path->elem[depth].index = index;
1057 
1058         ret = build_name(path);
1059         if ( ret < 0 )
1060                 return ret;
1061 
1062         return 0;
1063 }
1064 
1065 
1066 
1067 /**
1068  * idmef_path_undefine_index:
1069  * @path: Pointer to an #idmef_path_t object.
1070  * @depth: Depth of @path to undefine the index for.
1071  *
1072  * Modifies the element located at @depth of provided @path so that it's
1073  * index is undefined.
1074  *
1075  * This function is only applicable for element that accept listed value.
1076  *
1077  * Returns: 0 on success, a negative value if an error occured.
1078  */
idmef_path_undefine_index(idmef_path_t * path,unsigned int depth)1079 int idmef_path_undefine_index(idmef_path_t *path, unsigned int depth)
1080 {
1081         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1082 
1083         return idmef_path_set_index(path, depth, INDEX_UNDEFINED);
1084 }
1085 
1086 
1087 
1088 /**
1089  * idmef_path_get_index:
1090  * @path: Pointer to an #idmef_path_t object.
1091  * @depth: Depth of @path to retrieve the index from.
1092  *
1093  * Gets the current index for element located at @depth of @path.
1094  * This function is only applicable for element that accepts listed value.
1095  *
1096  * Returns: The element index, or a negative value if an error occured.
1097  */
idmef_path_get_index(const idmef_path_t * path,unsigned int depth)1098 int idmef_path_get_index(const idmef_path_t *path, unsigned int depth)
1099 {
1100         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1101         prelude_return_val_if_fail(depth < path->depth, prelude_error(PRELUDE_ERROR_IDMEF_PATH_DEPTH));
1102 
1103         if ( path->elem[depth].index == INDEX_UNDEFINED )
1104                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_UNDEFINED);
1105 
1106         if ( path->elem[depth].index == INDEX_FORBIDDEN )
1107                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN);
1108 
1109         return path->elem[depth].index;
1110 }
1111 
1112 
1113 
idmef_path_get_key(const idmef_path_t * path,unsigned int depth,const char ** key)1114 int idmef_path_get_key(const idmef_path_t *path, unsigned int depth, const char **key)
1115 {
1116         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1117         prelude_return_val_if_fail(depth < path->depth, prelude_error(PRELUDE_ERROR_IDMEF_PATH_DEPTH));
1118 
1119         if ( path->elem[depth].index == INDEX_UNDEFINED )
1120                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_UNDEFINED);
1121 
1122         if ( path->elem[depth].index == INDEX_FORBIDDEN )
1123                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN);
1124 
1125         if ( path->elem[depth].index != INDEX_KEY )
1126                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_INDEX_FORBIDDEN);
1127 
1128         *key = path->elem[depth].index_key;
1129         return 0;
1130 }
1131 
1132 
1133 
1134 /**
1135  * idmef_path_make_child:
1136  * @path: Pointer to an #idmef_path_t object.
1137  * @child_name: Name of the child element to create.
1138  * @index: Index for @child_name, if applicable.
1139  *
1140  * Modifies @path so that it points to the child node identified by @child_name,
1141  * children of the current path. That is if the path is currently pointing to
1142  * alert.classification, and @child_name is set to "text", @path will be
1143  * modified to point to alert.classification.text.
1144  *
1145  * Returns: 0 on success, or a negative value if an error occured.
1146  */
idmef_path_make_child(idmef_path_t * path,const char * child_name,int index)1147 int idmef_path_make_child(idmef_path_t *path, const char *child_name, int index)
1148 {
1149         int ret;
1150         char buf[16] = { 0 };
1151         idmef_class_id_t class;
1152         idmef_class_child_id_t child;
1153 
1154         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1155         prelude_return_val_if_fail(child_name, prelude_error(PRELUDE_ERROR_ASSERTION));
1156 
1157         if ( path->depth > MAX_DEPTH - 1 )
1158                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_DEPTH);
1159 
1160         class = idmef_path_get_class(path, -1);
1161 
1162         child = idmef_class_find_child(class, child_name);
1163         if ( child < 0 )
1164                 return child;
1165 
1166         ret = invalidate(path);
1167         if ( ret < 0 )
1168                 return ret;
1169 
1170         if ( index >= 0 && idmef_class_is_child_list(class, child) )
1171              snprintf(buf, sizeof(buf), "(%d)", index);
1172 
1173         snprintf(path->name + strlen(path->name), sizeof(path->name) - strlen(path->name), "%s%s%s",
1174                  (path->depth > 0) ? "." : "", child_name, buf);
1175 
1176         path->depth++;
1177 
1178         path->elem[path->depth - 1].position = child;
1179         if ( idmef_class_is_child_list(class, child) )
1180                 path->elem[path->depth - 1].index = (index < 0) ? INDEX_UNDEFINED : index;
1181         else
1182                 path->elem[path->depth - 1].index = INDEX_FORBIDDEN;
1183 
1184         path->elem[path->depth - 1].class = idmef_class_get_child_class(class, child);
1185         path->elem[path->depth - 1].value_type = idmef_class_get_child_value_type(class, child);
1186 
1187         return 0;
1188 }
1189 
1190 
1191 /**
1192  * idmef_path_make_parent:
1193  * @path: Pointer to an #idmef_path_t object.
1194  *
1195  * Removes the last element of the path. That is, if @path is currently pointing to
1196  * alert.classification, @path will be modified to point to alert.
1197  *
1198  * Returns: 0 on success, or a negative value if an error occured.
1199  */
idmef_path_make_parent(idmef_path_t * path)1200 int idmef_path_make_parent(idmef_path_t *path)
1201 {
1202         int ret;
1203         char *ptr;
1204 
1205         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1206 
1207         if ( path->depth == 0 )
1208                 return prelude_error(PRELUDE_ERROR_IDMEF_PATH_PARENT_ROOT);
1209 
1210         ret = invalidate(path);
1211         if ( ret < 0 )
1212                 return ret;
1213 
1214         path->depth--;
1215 
1216         if ( path->name[0] ) {
1217                 ptr = strrchr(path->name, '.');
1218                 if ( ! ptr )
1219                         ptr = path->name; /* top-level path */
1220 
1221                 *ptr = '\0';
1222         }
1223 
1224         return 0;
1225 }
1226 
1227 
1228 
1229 /**
1230  * idmef_path_destroy:
1231  * @path: Pointer to an #idmef_path_t object.
1232  *
1233  * Destroys the provided @path object.
1234  */
idmef_path_destroy(idmef_path_t * path)1235 void idmef_path_destroy(idmef_path_t *path)
1236 {
1237         prelude_return_if_fail(path);
1238 
1239         gl_lock_lock(path->mutex);
1240 
1241         if ( --path->refcount ) {
1242                 gl_lock_unlock(path->mutex);
1243                 return;
1244         }
1245 
1246         gl_lock_unlock(path->mutex);
1247         gl_lock_destroy(path->mutex);
1248         free(path);
1249 }
1250 
1251 
1252 
1253 /**
1254  * idmef_path_ncompare:
1255  * @p1: Pointer to an #idmef_path_t object.
1256  * @p2: Pointer to another #idmef_path_t object.
1257  * @depth: Maximum depth to use for path comparison.
1258  *
1259  * Compares @p1 and @p2 elements up to @depth.
1260  *
1261  * Returns: 0 if both element match, a negative value otherwise.
1262  */
idmef_path_ncompare(const idmef_path_t * p1,const idmef_path_t * p2,unsigned int depth)1263 int idmef_path_ncompare(const idmef_path_t *p1, const idmef_path_t *p2, unsigned int depth)
1264 {
1265         unsigned int i;
1266 
1267         prelude_return_val_if_fail(p1, prelude_error(PRELUDE_ERROR_ASSERTION));
1268         prelude_return_val_if_fail(p2, prelude_error(PRELUDE_ERROR_ASSERTION));
1269 
1270         for ( i = 0; i < depth; i++ ) {
1271 
1272                 if ( p1->elem[i].index != p2->elem[i].index )
1273                         return -1;
1274 
1275                 if ( p1->elem[i].index == INDEX_KEY && strcmp(p1->elem[i].index_key, p2->elem[i].index_key) != 0 )
1276                         return -1;
1277 
1278                 if ( p1->elem[i].position - p2->elem[i].position )
1279                         return -1;
1280         }
1281 
1282         return 0;
1283 }
1284 
1285 
1286 
1287 /**
1288  * idmef_path_compare:
1289  * @p1: Pointer to an #idmef_path_t object.
1290  * @p2: Pointer to another #idmef_path_t object.
1291  *
1292  * Compares @p1 and @p2 elements.
1293  *
1294  * Returns: 0 if both element match, a negative value otherwise.
1295  */
idmef_path_compare(const idmef_path_t * p1,const idmef_path_t * p2)1296 int idmef_path_compare(const idmef_path_t *p1, const idmef_path_t *p2)
1297 {
1298         prelude_return_val_if_fail(p1, prelude_error(PRELUDE_ERROR_ASSERTION));
1299         prelude_return_val_if_fail(p2, prelude_error(PRELUDE_ERROR_ASSERTION));
1300 
1301         if ( p1->depth != p2->depth )
1302                 return -1;
1303 
1304         return idmef_path_ncompare(p1, p2, p1->depth);
1305 }
1306 
1307 
1308 
1309 
1310 /**
1311  * idmef_path_clone:
1312  * @src: Pointer to an #idmef_path_t object.
1313  * @dst: Address where to store the copy of @src.
1314  *
1315  * Clones @src and stores the result in the provided @dst address.
1316  *
1317  * Returns: 0 on success, a negative value otherwise.
1318  */
idmef_path_clone(const idmef_path_t * src,idmef_path_t ** dst)1319 int idmef_path_clone(const idmef_path_t *src, idmef_path_t **dst)
1320 {
1321         prelude_return_val_if_fail(src, prelude_error(PRELUDE_ERROR_ASSERTION));
1322 
1323         *dst = calloc(1, sizeof(**dst));
1324         if ( ! *dst )
1325                 return prelude_error_from_errno(errno);
1326 
1327         (*dst)->refcount = 1;
1328         (*dst)->depth = src->depth;
1329 
1330         strncpy((*dst)->name, src->name, sizeof(src->name));
1331         memcpy((*dst)->elem, src->elem, src->depth * sizeof(idmef_path_element_t));
1332 
1333         gl_lock_init((*dst)->mutex);
1334 
1335         return 0;
1336 }
1337 
1338 
1339 
1340 /**
1341  * idmef_path_check_operator:
1342  * @path: Pointer to a #idmef_path_t object.
1343  * @op: Operator to check compatibility with.
1344  *
1345  * Check whether @op can apply to value pointed to by @path.
1346  *
1347  * Returns: 0 on success, a negative value if an error occured.
1348  */
idmef_path_check_operator(const idmef_path_t * path,idmef_criterion_operator_t op)1349 int idmef_path_check_operator(const idmef_path_t *path, idmef_criterion_operator_t op)
1350 {
1351         prelude_return_val_if_fail(path, prelude_error(PRELUDE_ERROR_ASSERTION));
1352         return idmef_value_type_check_operator(idmef_path_get_value_type(path, -1), op);
1353 }
1354 
1355 
1356 
1357 /**
1358  * idmef_path_get_applicable_operators:
1359  * @path: Pointer to a #idmef_path_t object.
1360  * @result: Pointer to storage for applicable operator.
1361  *
1362  * Retrieve all applicable operator that might be used by the type of
1363  * value pointed to by @path.
1364  *
1365  * Returns: 0 on success, a negative value if an error occured.
1366  */
idmef_path_get_applicable_operators(const idmef_path_t * path,idmef_criterion_operator_t * result)1367 int idmef_path_get_applicable_operators(const idmef_path_t *path, idmef_criterion_operator_t *result)
1368 {
1369         prelude_return_val_if_fail(path && result, prelude_error(PRELUDE_ERROR_ASSERTION));
1370         return idmef_value_type_get_applicable_operators(idmef_path_get_value_type(path, -1), result);
1371 }
1372 
1373 
1374 
1375 /**
1376  * idmef_path_ref:
1377  * @path: Pointer to an #idmef_path_t object.
1378  *
1379  * Increases @path reference count.
1380  *
1381  * idmef_path_destroy() will destroy the refcount until it reaches 0,
1382  * at which point the path will be destroyed.
1383  *
1384  * Returns: The provided @path is returned.
1385  */
idmef_path_ref(idmef_path_t * path)1386 idmef_path_t *idmef_path_ref(idmef_path_t *path)
1387 {
1388         prelude_return_val_if_fail(path, NULL);
1389 
1390         gl_lock_lock(path->mutex);
1391         path->refcount++;
1392         gl_lock_unlock(path->mutex);
1393 
1394         return path;
1395 }
1396 
1397 
1398 
1399 /**
1400  * idmef_path_is_ambiguous:
1401  * @path: Pointer to an #idmef_path_t object.
1402  *
1403  * Returns TRUE if @path contain elements that are supposed
1404  * to be listed, but for which no index were provided.
1405  *
1406  * Returns: TRUE if the object is ambiguous, FALSE otherwise.
1407  */
idmef_path_is_ambiguous(const idmef_path_t * path)1408 prelude_bool_t idmef_path_is_ambiguous(const idmef_path_t *path)
1409 {
1410         size_t i;
1411 
1412         prelude_return_val_if_fail(path, FALSE);
1413 
1414         for ( i = 0; i < path->depth; i++ ) {
1415                 if ( path->elem[i].index == INDEX_UNDEFINED )
1416                         return TRUE;
1417         }
1418 
1419         return FALSE;
1420 }
1421 
1422 
1423 
1424 /**
1425  * idmef_path_has_lists:
1426  * @path: Pointer to an #idmef_path_t object.
1427  *
1428  * Returns: the number of listed element within @path.
1429  */
idmef_path_has_lists(const idmef_path_t * path)1430 int idmef_path_has_lists(const idmef_path_t *path)
1431 {
1432         size_t i;
1433         int ret = 0;
1434 
1435         prelude_return_val_if_fail(path, 0);
1436 
1437         for ( i = 0; i < path->depth; i++ ) {
1438                 if ( path->elem[i].index != INDEX_FORBIDDEN )
1439                         ret++;
1440         }
1441 
1442         return ret;
1443 }
1444 
1445 
1446 
idmef_path_is_list(const idmef_path_t * path,int depth)1447 prelude_bool_t idmef_path_is_list(const idmef_path_t *path, int depth)
1448 {
1449         prelude_return_val_if_fail(path, FALSE);
1450 
1451         if ( depth < 0 )
1452                 depth = path->depth - 1;
1453 
1454         return path->elem[depth].index != INDEX_FORBIDDEN;
1455 }
1456 
1457 
1458 
1459 
1460 /**
1461  * idmef_path_get_depth:
1462  * @path: Pointer to an #idmef_path_t object.
1463  *
1464  * Returns: @depth number of elements.
1465  */
idmef_path_get_depth(const idmef_path_t * path)1466 unsigned int idmef_path_get_depth(const idmef_path_t *path)
1467 {
1468         prelude_return_val_if_fail(path, 0);
1469         return path->depth;
1470 }
1471 
1472 
1473 
1474 /**
1475  * idmef_path_get_name:
1476  * @path: Pointer to an #idmef_path_t object.
1477  * @depth: Depth of the @path element to get the name from.
1478  *
1479  * Returns the full path name if the provided @depth is -1, or the specific
1480  * element name if depth is set. That is, for a @path pointing to
1481  * "alert.classification.text": A depth of -1 would return "alert.classification.text";
1482  * a depth of 0 would return "alert"; a depth of 1 would return "classification"; and
1483  * a depth of 2 would return "text".
1484  *
1485  * Returns: @path name relative to the provided @dept.
1486  */
idmef_path_get_name(const idmef_path_t * path,int depth)1487 const char *idmef_path_get_name(const idmef_path_t *path, int depth)
1488 {
1489         const char *ret;
1490         const idmef_path_element_t *elem;
1491 
1492         prelude_return_val_if_fail(path, NULL);
1493         prelude_return_val_if_fail(depth < 0 || (size_t) depth < path->depth, NULL);
1494 
1495         if ( depth < 0 )
1496                 return path->name;
1497 
1498         elem = &path->elem[depth];
1499 
1500         if ( depth > 0 && (elem->class < 0 || elem->value_type == IDMEF_VALUE_TYPE_ENUM) )
1501                 ret = idmef_class_get_child_name(path->elem[depth - 1].class, elem->position);
1502         else
1503                 ret = idmef_class_get_name(elem->class);
1504 
1505         return ret;
1506 }
1507 
1508 
1509 
_idmef_path_cache_lock(void)1510 void _idmef_path_cache_lock(void)
1511 {
1512         gl_lock_lock(cached_path_mutex);
1513 
1514         if ( cached_path )
1515                 prelude_hash_iterate(cached_path, path_lock_cb);
1516 }
1517 
1518 
1519 
_idmef_path_cache_reinit(void)1520 void _idmef_path_cache_reinit(void)
1521 {
1522         gl_lock_init(cached_path_mutex);
1523 
1524         if ( cached_path )
1525                 prelude_hash_iterate(cached_path, path_reinit_cb);
1526 }
1527 
1528 
1529 
1530 
_idmef_path_cache_unlock(void)1531 void _idmef_path_cache_unlock(void)
1532 {
1533         if ( cached_path )
1534                 prelude_hash_iterate(cached_path, path_unlock_cb);
1535 
1536         gl_lock_unlock(cached_path_mutex);
1537 }
1538 
1539 
1540 
_idmef_path_cache_destroy(void)1541 void _idmef_path_cache_destroy(void)
1542 {
1543         if ( ! cached_path )
1544                 return;
1545 
1546         flush_cache = TRUE;
1547         prelude_hash_destroy(cached_path);
1548         flush_cache = FALSE;
1549 }
1550