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