1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Endace Technology Limited - Jason Ish <jason.ish@endace.com>
22  *
23  * This file provides a basic configuration system for the IDPS
24  * engine.
25  *
26  * NOTE: Setting values should only be done from one thread during
27  * engine initialization.  Multiple threads should be able access read
28  * configuration data.  Allowing run time changes to the configuration
29  * will require some locks.
30  *
31  * \todo Consider having the in-memory configuration database a direct
32  *   reflection of the configuration file and moving command line
33  *   parameters to a primary lookup table?
34  *
35  * \todo Get rid of allow override and go with a simpler first set,
36  *   stays approach?
37  */
38 
39 #include "suricata-common.h"
40 #include "conf.h"
41 #include "util-unittest.h"
42 #include "util-debug.h"
43 #include "util-path.h"
44 
45 /** Maximum size of a complete domain name. */
46 #define NODE_NAME_MAX 1024
47 
48 static ConfNode *root = NULL;
49 static ConfNode *root_backup = NULL;
50 
51 /**
52  * \brief Helper function to get a node, creating it if it does not
53  * exist.
54  *
55  * This function exits on memory failure as creating configuration
56  * nodes is usually part of application initialization.
57  *
58  * \param name The name of the configuration node to get.
59  * \param final Flag to set created nodes as final or not.
60  *
61  * \retval The existing configuration node if it exists, or a newly
62  *   created node for the provided name.  On error, NULL will be returned.
63  */
ConfGetNodeOrCreate(const char * name,int final)64 static ConfNode *ConfGetNodeOrCreate(const char *name, int final)
65 {
66     ConfNode *parent = root;
67     ConfNode *node = NULL;
68     char node_name[NODE_NAME_MAX];
69     char *key;
70     char *next;
71 
72     if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
73         SCLogError(SC_ERR_CONF_NAME_TOO_LONG,
74             "Configuration name too long: %s", name);
75         return NULL;
76     }
77 
78     key = node_name;
79 
80     do {
81         if ((next = strchr(key, '.')) != NULL)
82             *next++ = '\0';
83         if ((node = ConfNodeLookupChild(parent, key)) == NULL) {
84             node = ConfNodeNew();
85             if (unlikely(node == NULL)) {
86                 SCLogWarning(SC_ERR_MEM_ALLOC,
87                     "Failed to allocate memory for configuration.");
88                 goto end;
89             }
90             node->name = SCStrdup(key);
91             if (unlikely(node->name == NULL)) {
92                 ConfNodeFree(node);
93                 node = NULL;
94                 SCLogWarning(SC_ERR_MEM_ALLOC,
95                     "Failed to allocate memory for configuration.");
96                 goto end;
97             }
98             node->parent = parent;
99             node->final = final;
100             TAILQ_INSERT_TAIL(&parent->head, node, next);
101         }
102         key = next;
103         parent = node;
104     } while (next != NULL);
105 
106 end:
107     return node;
108 }
109 
110 /**
111  * \brief Initialize the configuration system.
112  */
ConfInit(void)113 void ConfInit(void)
114 {
115     if (root != NULL) {
116         SCLogDebug("already initialized");
117         return;
118     }
119     root = ConfNodeNew();
120     if (root == NULL) {
121             FatalError(SC_ERR_FATAL,
122                        "ERROR: Failed to allocate memory for root configuration node, "
123                        "aborting.");
124     }
125     SCLogDebug("configuration module initialized");
126 }
127 
128 /**
129  * \brief Allocate a new configuration node.
130  *
131  * \retval An allocated configuration node on success, NULL on failure.
132  */
ConfNodeNew(void)133 ConfNode *ConfNodeNew(void)
134 {
135     ConfNode *new;
136 
137     new = SCCalloc(1, sizeof(*new));
138     if (unlikely(new == NULL)) {
139         return NULL;
140     }
141     TAILQ_INIT(&new->head);
142 
143     return new;
144 }
145 
146 /**
147  * \brief Free a ConfNode and all of its children.
148  *
149  * \param node The configuration node to SCFree.
150  */
ConfNodeFree(ConfNode * node)151 void ConfNodeFree(ConfNode *node)
152 {
153     ConfNode *tmp;
154 
155     while ((tmp = TAILQ_FIRST(&node->head))) {
156         TAILQ_REMOVE(&node->head, tmp, next);
157         ConfNodeFree(tmp);
158     }
159 
160     if (node->name != NULL)
161         SCFree(node->name);
162     if (node->val != NULL)
163         SCFree(node->val);
164     SCFree(node);
165 }
166 
167 /**
168  * \brief Get a ConfNode by name.
169  *
170  * \param name The full name of the configuration node to lookup.
171  *
172  * \retval A pointer to ConfNode is found or NULL if the configuration
173  *    node does not exist.
174  */
ConfGetNode(const char * name)175 ConfNode *ConfGetNode(const char *name)
176 {
177     ConfNode *node = root;
178     char node_name[NODE_NAME_MAX];
179     char *key;
180     char *next;
181 
182     if (strlcpy(node_name, name, sizeof(node_name)) >= sizeof(node_name)) {
183         SCLogError(SC_ERR_CONF_NAME_TOO_LONG,
184             "Configuration name too long: %s", name);
185         return NULL;
186     }
187 
188     key = node_name;
189     do {
190         if ((next = strchr(key, '.')) != NULL)
191             *next++ = '\0';
192         node = ConfNodeLookupChild(node, key);
193         key = next;
194     } while (next != NULL && node != NULL);
195 
196     return node;
197 }
198 
199 /**
200  * \brief Get the root configuration node.
201  */
ConfGetRootNode(void)202 ConfNode *ConfGetRootNode(void)
203 {
204     return root;
205 }
206 
207 /**
208  * \brief Set a configuration value.
209  *
210  * Configuration values set with this function may be overridden by
211  * subsequent calls, or if the value appears multiple times in a
212  * configuration file.
213  *
214  * \param name The name of the configuration parameter to set.
215  * \param val The value of the configuration parameter.
216  *
217  * \retval 1 if the value was set otherwise 0.
218  */
ConfSet(const char * name,const char * val)219 int ConfSet(const char *name, const char *val)
220 {
221     ConfNode *node = ConfGetNodeOrCreate(name, 0);
222     if (node == NULL || node->final) {
223         return 0;
224     }
225     if (node->val != NULL)
226         SCFree(node->val);
227     node->val = SCStrdup(val);
228     if (unlikely(node->val == NULL)) {
229         return 0;
230     }
231     return 1;
232 }
233 
234 /**
235  * \brief Set a configuration parameter from a string.
236  *
237  * Where the input string is something like:
238  *    stream.midstream=true
239  *
240  * \param input the input string to be parsed.
241  *
242  * \retval 1 if the value of set, otherwise 0.
243  */
ConfSetFromString(const char * input,int final)244 int ConfSetFromString(const char *input, int final)
245 {
246     int retval = 0;
247     char *name = SCStrdup(input), *val = NULL;
248     if (unlikely(name == NULL)) {
249         goto done;
250     }
251     val = strchr(name, '=');
252     if (val == NULL) {
253         goto done;
254     }
255     *val++ = '\0';
256 
257     while (isspace((int)name[strlen(name) - 1])) {
258         name[strlen(name) - 1] = '\0';
259     }
260 
261     while (isspace((int)*val)) {
262         val++;
263     }
264 
265     if (final) {
266         if (!ConfSetFinal(name, val)) {
267             goto done;
268         }
269     }
270     else {
271         if (!ConfSet(name, val)) {
272             goto done;
273         }
274     }
275 
276     retval = 1;
277 done:
278     if (name != NULL) {
279         SCFree(name);
280     }
281     return retval;
282 }
283 
284 /**
285  * \brief Set a final configuration value.
286  *
287  * A final configuration value is a value that cannot be overridden by
288  * the configuration file.  Its mainly useful for setting values that
289  * are supplied on the command line prior to the configuration file
290  * being loaded.  However, a subsequent call to this function can
291  * override a previously set value.
292  *
293  * \param name The name of the configuration parameter to set.
294  * \param val The value of the configuration parameter.
295  *
296  * \retval 1 if the value was set otherwise 0.
297  */
ConfSetFinal(const char * name,const char * val)298 int ConfSetFinal(const char *name, const char *val)
299 {
300     ConfNode *node = ConfGetNodeOrCreate(name, 1);
301     if (node == NULL) {
302         return 0;
303     }
304     if (node->val != NULL)
305         SCFree(node->val);
306     node->val = SCStrdup(val);
307     if (unlikely(node->val == NULL)) {
308         return 0;
309     }
310     node->final = 1;
311     return 1;
312 }
313 
314 /**
315  * \brief Retrieve the value of a configuration node.
316  *
317  * This function will return the value for a configuration node based
318  * on the full name of the node.  It is possible that the value
319  * returned could be NULL, this could happen if the requested node
320  * does exist but is not a node that contains a value, but contains
321  * children ConfNodes instead.
322  *
323  * \param name Name of configuration parameter to get.
324  * \param vptr Pointer that will be set to the configuration value parameter.
325  *   Note that this is just a reference to the actual value, not a copy.
326  *
327  * \retval 1 will be returned if the name is found, otherwise 0 will
328  *   be returned.
329  */
ConfGet(const char * name,const char ** vptr)330 int ConfGet(const char *name, const char **vptr)
331 {
332     ConfNode *node = ConfGetNode(name);
333     if (node == NULL) {
334         SCLogDebug("failed to lookup configuration parameter '%s'", name);
335         return 0;
336     }
337     else {
338         *vptr = node->val;
339         return 1;
340     }
341 }
342 
343 /**
344  * \brief Retrieve the value of a configuration node.
345  *
346  * This function will return the value for a configuration node based
347  * on the full name of the node. This function notifies if vptr returns NULL
348  * or if name is set to NULL.
349  *
350  * \param name Name of configuration parameter to get.
351  * \param vptr Pointer that will be set to the configuration value parameter.
352  *   Note that this is just a reference to the actual value, not a copy.
353  *
354  * \retval 0 will be returned if name was not found,
355  *    1 will be returned if the name and it's value was found,
356  *   -1 if the value returns NULL,
357  *   -2 if name is NULL.
358  */
ConfGetValue(const char * name,const char ** vptr)359 int ConfGetValue(const char *name, const char **vptr)
360 {
361     ConfNode *node;
362 
363     if (name == NULL) {
364         SCLogError(SC_ERR_INVALID_ARGUMENT,"parameter 'name' is NULL");
365         return -2;
366     }
367 
368     node = ConfGetNode(name);
369 
370     if (node == NULL) {
371         SCLogDebug("failed to lookup configuration parameter '%s'", name);
372         return 0;
373     }
374     else {
375 
376         if (node->val == NULL) {
377             SCLogDebug("value for configuration parameter '%s' is NULL", name);
378             return -1;
379         }
380 
381         *vptr = node->val;
382         return 1;
383     }
384 
385 }
386 
ConfGetChildValue(const ConfNode * base,const char * name,const char ** vptr)387 int ConfGetChildValue(const ConfNode *base, const char *name, const char **vptr)
388 {
389     ConfNode *node = ConfNodeLookupChild(base, name);
390 
391     if (node == NULL) {
392         SCLogDebug("failed to lookup configuration parameter '%s'", name);
393         return 0;
394     }
395     else {
396         *vptr = node->val;
397         return 1;
398     }
399 }
400 
ConfGetChildWithDefault(const ConfNode * base,const ConfNode * dflt,const char * name)401 ConfNode *ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt,
402     const char *name)
403 {
404     ConfNode *node = ConfNodeLookupChild(base, name);
405     if (node != NULL)
406         return node;
407 
408     /* Get 'default' value */
409     if (dflt) {
410         return ConfNodeLookupChild(dflt, name);
411     }
412     return NULL;
413 }
414 
ConfGetChildValueWithDefault(const ConfNode * base,const ConfNode * dflt,const char * name,const char ** vptr)415 int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt,
416     const char *name, const char **vptr)
417 {
418     int ret = ConfGetChildValue(base, name, vptr);
419     /* Get 'default' value */
420     if (ret == 0 && dflt) {
421         return ConfGetChildValue(dflt, name, vptr);
422     }
423     return ret;
424 }
425 
426 /**
427  * \brief Retrieve a configuration value as an integer.
428  *
429  * \param name Name of configuration parameter to get.
430  * \param val Pointer to an intmax_t that will be set the
431  * configuration value.
432  *
433  * \retval 1 will be returned if the name is found and was properly
434  * converted to an interger, otherwise 0 will be returned.
435  */
ConfGetInt(const char * name,intmax_t * val)436 int ConfGetInt(const char *name, intmax_t *val)
437 {
438     const char *strval = NULL;
439     intmax_t tmpint;
440     char *endptr;
441 
442     if (ConfGet(name, &strval) == 0)
443         return 0;
444 
445     if (strval == NULL) {
446         SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "malformed integer value "
447                 "for %s: NULL", name);
448         return 0;
449     }
450 
451     errno = 0;
452     tmpint = strtoimax(strval, &endptr, 0);
453     if (strval[0] == '\0' || *endptr != '\0') {
454         SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "malformed integer value "
455                 "for %s: '%s'", name, strval);
456         return 0;
457     }
458     if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
459         SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "integer value for %s out "
460                 "of range: '%s'", name, strval);
461         return 0;
462     }
463 
464     *val = tmpint;
465     return 1;
466 }
467 
ConfGetChildValueInt(const ConfNode * base,const char * name,intmax_t * val)468 int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
469 {
470     const char *strval = NULL;
471     intmax_t tmpint;
472     char *endptr;
473 
474     if (ConfGetChildValue(base, name, &strval) == 0)
475         return 0;
476     errno = 0;
477     tmpint = strtoimax(strval, &endptr, 0);
478     if (strval[0] == '\0' || *endptr != '\0') {
479         SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "malformed integer value "
480                 "for %s with base %s: '%s'", name, base->name, strval);
481         return 0;
482     }
483     if (errno == ERANGE && (tmpint == INTMAX_MAX || tmpint == INTMAX_MIN)) {
484         SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "integer value for %s with "
485                 " base %s out of range: '%s'", name, base->name, strval);
486         return 0;
487     }
488 
489     *val = tmpint;
490     return 1;
491 
492 }
493 
ConfGetChildValueIntWithDefault(const ConfNode * base,const ConfNode * dflt,const char * name,intmax_t * val)494 int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt,
495     const char *name, intmax_t *val)
496 {
497     int ret = ConfGetChildValueInt(base, name, val);
498     /* Get 'default' value */
499     if (ret == 0 && dflt) {
500         return ConfGetChildValueInt(dflt, name, val);
501     }
502     return ret;
503 }
504 
505 
506 /**
507  * \brief Retrieve a configuration value as an boolen.
508  *
509  * \param name Name of configuration parameter to get.
510  * \param val Pointer to an int that will be set to 1 for true, or 0
511  * for false.
512  *
513  * \retval 1 will be returned if the name is found and was properly
514  * converted to a boolean, otherwise 0 will be returned.
515  */
ConfGetBool(const char * name,int * val)516 int ConfGetBool(const char *name, int *val)
517 {
518     const char *strval = NULL;
519 
520     *val = 0;
521     if (ConfGetValue(name, &strval) != 1)
522         return 0;
523 
524     *val = ConfValIsTrue(strval);
525 
526     return 1;
527 }
528 
ConfGetChildValueBool(const ConfNode * base,const char * name,int * val)529 int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)
530 {
531     const char *strval = NULL;
532 
533     *val = 0;
534     if (ConfGetChildValue(base, name, &strval) == 0)
535         return 0;
536 
537     *val = ConfValIsTrue(strval);
538 
539     return 1;
540 }
541 
ConfGetChildValueBoolWithDefault(const ConfNode * base,const ConfNode * dflt,const char * name,int * val)542 int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt,
543     const char *name, int *val)
544 {
545     int ret = ConfGetChildValueBool(base, name, val);
546     /* Get 'default' value */
547     if (ret == 0 && dflt) {
548         return ConfGetChildValueBool(dflt, name, val);
549     }
550     return ret;
551 }
552 
553 
554 /**
555  * \brief Check if a value is true.
556  *
557  * The value is considered true if it is a string with the value of 1,
558  * yes, true or on.  The test is not case sensitive, any other value
559  * is false.
560  *
561  * \param val The string to test for a true value.
562  *
563  * \retval 1 If the value is true, 0 if not.
564  */
ConfValIsTrue(const char * val)565 int ConfValIsTrue(const char *val)
566 {
567     const char *trues[] = {"1", "yes", "true", "on"};
568     size_t u;
569 
570     for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) {
571         if (strcasecmp(val, trues[u]) == 0) {
572             return 1;
573         }
574     }
575 
576     return 0;
577 }
578 
579 /**
580  * \brief Check if a value is false.
581  *
582  * The value is considered false if it is a string with the value of 0,
583  * no, false or off.  The test is not case sensitive, any other value
584  * is not false.
585  *
586  * \param val The string to test for a false value.
587  *
588  * \retval 1 If the value is false, 0 if not.
589  */
ConfValIsFalse(const char * val)590 int ConfValIsFalse(const char *val)
591 {
592     const char *falses[] = {"0", "no", "false", "off"};
593     size_t u;
594 
595     for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) {
596         if (strcasecmp(val, falses[u]) == 0) {
597             return 1;
598         }
599     }
600 
601     return 0;
602 }
603 
604 /**
605  * \brief Retrieve a configuration value as a double
606  *
607  * \param name Name of configuration parameter to get.
608  * \param val Pointer to an double that will be set the
609  * configuration value.
610  *
611  * \retval 1 will be returned if the name is found and was properly
612  * converted to a double, otherwise 0 will be returned.
613  */
ConfGetDouble(const char * name,double * val)614 int ConfGetDouble(const char *name, double *val)
615 {
616     const char *strval = NULL;
617     double tmpdo;
618     char *endptr;
619 
620     if (ConfGet(name, &strval) == 0)
621         return 0;
622 
623     errno = 0;
624     tmpdo = strtod(strval, &endptr);
625     if (strval[0] == '\0' || *endptr != '\0')
626         return 0;
627     if (errno == ERANGE)
628         return 0;
629 
630     *val = tmpdo;
631     return 1;
632 }
633 
634 /**
635  * \brief Retrieve a configuration value as a float
636  *
637  * \param name Name of configuration parameter to get.
638  * \param val Pointer to an float that will be set the
639  * configuration value.
640  *
641  * \retval 1 will be returned if the name is found and was properly
642  * converted to a double, otherwise 0 will be returned.
643  */
ConfGetFloat(const char * name,float * val)644 int ConfGetFloat(const char *name, float *val)
645 {
646     const char *strval = NULL;
647     double tmpfl;
648     char *endptr;
649 
650     if (ConfGet(name, &strval) == 0)
651         return 0;
652 
653     errno = 0;
654     tmpfl = strtof(strval, &endptr);
655     if (strval[0] == '\0' || *endptr != '\0')
656         return 0;
657     if (errno == ERANGE)
658         return 0;
659 
660     *val = tmpfl;
661     return 1;
662 }
663 
664 /**
665  * \brief Remove (and SCFree) the provided configuration node.
666  */
ConfNodeRemove(ConfNode * node)667 void ConfNodeRemove(ConfNode *node)
668 {
669     if (node->parent != NULL)
670         TAILQ_REMOVE(&node->parent->head, node, next);
671     ConfNodeFree(node);
672 }
673 
674 /**
675  * \brief Remove a configuration parameter from the configuration db.
676  *
677  * \param name The name of the configuration parameter to remove.
678  *
679  * \retval Returns 1 if the parameter was removed, otherwise 0 is returned
680  *   most likely indicating the parameter was not set.
681  */
ConfRemove(const char * name)682 int ConfRemove(const char *name)
683 {
684     ConfNode *node;
685 
686     node = ConfGetNode(name);
687     if (node == NULL)
688         return 0;
689     else {
690         ConfNodeRemove(node);
691         return 1;
692     }
693 }
694 
695 /**
696  * \brief Creates a backup of the conf_hash hash_table used by the conf API.
697  */
ConfCreateContextBackup(void)698 void ConfCreateContextBackup(void)
699 {
700     root_backup = root;
701     root = NULL;
702 
703     return;
704 }
705 
706 /**
707  * \brief Restores the backup of the hash_table present in backup_conf_hash
708  *        back to conf_hash.
709  */
ConfRestoreContextBackup(void)710 void ConfRestoreContextBackup(void)
711 {
712     root = root_backup;
713     root_backup = NULL;
714 
715     return;
716 }
717 
718 /**
719  * \brief De-initializes the configuration system.
720  */
ConfDeInit(void)721 void ConfDeInit(void)
722 {
723     if (root != NULL) {
724         ConfNodeFree(root);
725         root = NULL;
726     }
727 
728     SCLogDebug("configuration module de-initialized");
729 }
730 
ConfPrintNameArray(char ** name_arr,int level)731 static char *ConfPrintNameArray(char **name_arr, int level)
732 {
733     static char name[128*128];
734     int i;
735 
736     name[0] = '\0';
737     for (i = 0; i <= level; i++) {
738         strlcat(name, name_arr[i], sizeof(name));
739         if (i < level)
740             strlcat(name, ".", sizeof(name));
741     }
742 
743     return name;
744 }
745 
746 /**
747  * \brief Dump a configuration node and all its children.
748  */
ConfNodeDump(const ConfNode * node,const char * prefix)749 void ConfNodeDump(const ConfNode *node, const char *prefix)
750 {
751     ConfNode *child;
752 
753     static char *name[128];
754     static int level = -1;
755 
756     level++;
757     TAILQ_FOREACH(child, &node->head, next) {
758         name[level] = SCStrdup(child->name);
759         if (unlikely(name[level] == NULL)) {
760             continue;
761         }
762         if (prefix == NULL) {
763             printf("%s = %s\n", ConfPrintNameArray(name, level),
764                 child->val);
765         }
766         else {
767             printf("%s.%s = %s\n", prefix,
768                 ConfPrintNameArray(name, level), child->val);
769         }
770         ConfNodeDump(child, prefix);
771         SCFree(name[level]);
772     }
773     level--;
774 }
775 
776 /**
777  * \brief Dump configuration to stdout.
778  */
ConfDump(void)779 void ConfDump(void)
780 {
781     ConfNodeDump(root, NULL);
782 }
783 
784 /**
785  * \brief Check if a node has any children.
786  *
787  * Checks if the provided node has any children. Any node that is a
788  * YAML map or array will have children.
789  *
790  * \param node The node to check.
791  *
792  * \retval true if node has children
793  * \retval false if node does not have children
794  */
ConfNodeHasChildren(const ConfNode * node)795 bool ConfNodeHasChildren(const ConfNode *node)
796 {
797     if (TAILQ_EMPTY(&node->head)) {
798         return false;
799     }
800     return true;
801 }
802 
803 /**
804  * \brief Lookup a child configuration node by name.
805  *
806  * Given a ConfNode this function will lookup an immediate child
807  * ConfNode by name and return the child ConfNode.
808  *
809  * \param node The parent configuration node.
810  * \param name The name of the child node to lookup.
811  *
812  * \retval A pointer the child ConfNode if found otherwise NULL.
813  */
ConfNodeLookupChild(const ConfNode * node,const char * name)814 ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name)
815 {
816     ConfNode *child;
817 
818     if (node == NULL || name == NULL) {
819         return NULL;
820     }
821 
822     TAILQ_FOREACH(child, &node->head, next) {
823         if (child->name != NULL && strcmp(child->name, name) == 0)
824             return child;
825     }
826 
827     return NULL;
828 }
829 
830 /**
831  * \brief Lookup the value of a child configuration node by name.
832  *
833  * Given a parent ConfNode this function will return the value of a
834  * child configuration node by name returning a reference to that
835  * value.
836  *
837  * \param node The parent configuration node.
838  * \param name The name of the child node to lookup.
839  *
840  * \retval A pointer the child ConfNodes value if found otherwise NULL.
841  */
ConfNodeLookupChildValue(const ConfNode * node,const char * name)842 const char *ConfNodeLookupChildValue(const ConfNode *node, const char *name)
843 {
844     ConfNode *child;
845 
846     child = ConfNodeLookupChild(node, name);
847     if (child != NULL)
848         return child->val;
849 
850     return NULL;
851 }
852 
853 /**
854  * \brief Lookup for a key value under a specific node
855  *
856  * \return the ConfNode matching or NULL
857  */
858 
ConfNodeLookupKeyValue(const ConfNode * base,const char * key,const char * value)859 ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key,
860     const char *value)
861 {
862     ConfNode *child;
863 
864     TAILQ_FOREACH(child, &base->head, next) {
865         if (!strncmp(child->val, key, strlen(child->val))) {
866             ConfNode *subchild;
867             TAILQ_FOREACH(subchild, &child->head, next) {
868                 if ((!strcmp(subchild->name, key)) && (!strcmp(subchild->val, value))) {
869                     return child;
870                 }
871             }
872         }
873     }
874 
875     return NULL;
876 }
877 
878 /**
879  * \brief Test if a configuration node has a true value.
880  *
881  * \param node The parent configuration node.
882  * \param name The name of the child node to test.
883  *
884  * \retval 1 if the child node has a true value, otherwise 0 is
885  *     returned, even if the child node does not exist.
886  */
ConfNodeChildValueIsTrue(const ConfNode * node,const char * key)887 int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key)
888 {
889     const char *val;
890 
891     val = ConfNodeLookupChildValue(node, key);
892 
893     return val != NULL ? ConfValIsTrue(val) : 0;
894 }
895 
896 /**
897  *  \brief Create the path for an include entry
898  *  \param file The name of the file
899  *  \retval str Pointer to the string path + sig_file
900  */
ConfLoadCompleteIncludePath(const char * file)901 char *ConfLoadCompleteIncludePath(const char *file)
902 {
903     const char *defaultpath = NULL;
904     char *path = NULL;
905 
906     /* Path not specified */
907     if (PathIsRelative(file)) {
908         if (ConfGet("include-path", &defaultpath) == 1) {
909             SCLogDebug("Default path: %s", defaultpath);
910             size_t path_len = sizeof(char) * (strlen(defaultpath) +
911                           strlen(file) + 2);
912             path = SCMalloc(path_len);
913             if (unlikely(path == NULL))
914                 return NULL;
915             strlcpy(path, defaultpath, path_len);
916             if (path[strlen(path) - 1] != '/')
917                 strlcat(path, "/", path_len);
918             strlcat(path, file, path_len);
919        } else {
920             path = SCStrdup(file);
921             if (unlikely(path == NULL))
922                 return NULL;
923         }
924     } else {
925         path = SCStrdup(file);
926         if (unlikely(path == NULL))
927             return NULL;
928     }
929     return path;
930 }
931 
932 /**
933  * \brief Prune a configuration node.
934  *
935  * Pruning a configuration is similar to freeing, but only fields that
936  * may be overridden are, leaving final type parameters.  Additional
937  * the value of the provided node is also free'd, but the node itself
938  * is left.
939  *
940  * \param node The configuration node to prune.
941  */
ConfNodePrune(ConfNode * node)942 void ConfNodePrune(ConfNode *node)
943 {
944     ConfNode *item, *it;
945 
946     for (item = TAILQ_FIRST(&node->head); item != NULL; item = it) {
947         it = TAILQ_NEXT(item, next);
948         if (!item->final) {
949             ConfNodePrune(item);
950             if (TAILQ_EMPTY(&item->head)) {
951                 TAILQ_REMOVE(&node->head, item, next);
952                 if (item->name != NULL)
953                     SCFree(item->name);
954                 if (item->val != NULL)
955                     SCFree(item->val);
956                 SCFree(item);
957             }
958         }
959     }
960 
961     if (node->val != NULL) {
962         SCFree(node->val);
963         node->val = NULL;
964     }
965 }
966 
967 /**
968  * \brief Check if a node is a sequence or node.
969  *
970  * \param node the node to check.
971  *
972  * \return 1 if node is a seuence, otherwise 0.
973  */
ConfNodeIsSequence(const ConfNode * node)974 int ConfNodeIsSequence(const ConfNode *node)
975 {
976     return node->is_seq == 0 ? 0 : 1;
977 }
978 
979 #ifdef UNITTESTS
980 
981 /**
982  * Lookup a non-existant value.
983  */
ConfTestGetNonExistant(void)984 static int ConfTestGetNonExistant(void)
985 {
986     char name[] = "non-existant-value";
987     const char *value;
988 
989     FAIL_IF(ConfGet(name, &value));
990     PASS;
991 }
992 
993 /**
994  * Set then lookup a value.
995  */
ConfTestSetAndGet(void)996 static int ConfTestSetAndGet(void)
997 {
998     char name[] = "some-name";
999     char value[] = "some-value";
1000     const char *value0 = NULL;
1001 
1002     FAIL_IF(ConfSet(name, value) != 1);
1003     FAIL_IF(ConfGet(name, &value0) != 1);
1004     FAIL_IF(value0 == NULL);
1005     FAIL_IF(strcmp(value, value0) != 0);
1006 
1007     /* Cleanup. */
1008     ConfRemove(name);
1009 
1010     PASS;
1011 }
1012 
1013 /**
1014  * Test that overriding a value is allowed provided allow_override is
1015  * true and that the config parameter gets the new value.
1016  */
ConfTestOverrideValue1(void)1017 static int ConfTestOverrideValue1(void)
1018 {
1019     char name[] = "some-name";
1020     char value0[] = "some-value";
1021     char value1[] = "new-value";
1022     const char *val = NULL;
1023 
1024     FAIL_IF(ConfSet(name, value0) != 1);
1025     FAIL_IF(ConfSet(name, value1) != 1);
1026     FAIL_IF(ConfGet(name, &val) != 1);
1027     FAIL_IF(val == NULL);
1028     FAIL_IF(strcmp(val, value1) != 0);
1029 
1030     /* Cleanup. */
1031     ConfRemove(name);
1032 
1033     PASS;
1034 }
1035 
1036 /**
1037  * Test that a final value will not be overrided by a ConfSet.
1038  */
ConfTestOverrideValue2(void)1039 static int ConfTestOverrideValue2(void)
1040 {
1041     char name[] = "some-name";
1042     char value0[] = "some-value";
1043     char value1[] = "new-value";
1044     const char *val = NULL;
1045 
1046     FAIL_IF(ConfSetFinal(name, value0) != 1);
1047     FAIL_IF(ConfSet(name, value1) != 0);
1048     FAIL_IF(ConfGet(name, &val) != 1);
1049     FAIL_IF(val == NULL);
1050     FAIL_IF(strcmp(val, value0) != 0);
1051 
1052     /* Cleanup. */
1053     ConfRemove(name);
1054 
1055     PASS;
1056 }
1057 
1058 /**
1059  * Test retrieving an integer value from the configuration db.
1060  */
ConfTestGetInt(void)1061 static int ConfTestGetInt(void)
1062 {
1063     char name[] = "some-int.x";
1064     intmax_t val;
1065 
1066     FAIL_IF(ConfSet(name, "0") != 1);
1067     FAIL_IF(ConfGetInt(name, &val) != 1);
1068     FAIL_IF(val != 0);
1069 
1070     FAIL_IF(ConfSet(name, "-1") != 1);
1071     FAIL_IF(ConfGetInt(name, &val) != 1);
1072     FAIL_IF(val != -1);
1073 
1074     FAIL_IF(ConfSet(name, "0xffff") != 1);
1075     FAIL_IF(ConfGetInt(name, &val) != 1);
1076     FAIL_IF(val != 0xffff);
1077 
1078     FAIL_IF(ConfSet(name, "not-an-int") != 1);
1079     FAIL_IF(ConfGetInt(name, &val) != 0);
1080 
1081     PASS;
1082 }
1083 
1084 /**
1085  * Test retrieving a boolean value from the configuration db.
1086  */
ConfTestGetBool(void)1087 static int ConfTestGetBool(void)
1088 {
1089     char name[] = "some-bool";
1090     const char *trues[] = {
1091         "1",
1092         "on", "ON",
1093         "yes", "YeS",
1094         "true", "TRUE",
1095     };
1096     const char *falses[] = {
1097         "0",
1098         "something",
1099         "off", "OFF",
1100         "false", "FalSE",
1101         "no", "NO",
1102     };
1103     int val;
1104     size_t u;
1105 
1106     for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) {
1107         FAIL_IF(ConfSet(name, trues[u]) != 1);
1108         FAIL_IF(ConfGetBool(name, &val) != 1);
1109         FAIL_IF(val != 1);
1110     }
1111 
1112     for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) {
1113         FAIL_IF(ConfSet(name, falses[u]) != 1);
1114         FAIL_IF(ConfGetBool(name, &val) != 1);
1115         FAIL_IF(val != 0);
1116     }
1117 
1118     PASS;
1119 }
1120 
ConfNodeLookupChildTest(void)1121 static int ConfNodeLookupChildTest(void)
1122 {
1123     const char *test_vals[] = { "one", "two", "three" };
1124     size_t u;
1125 
1126     ConfNode *parent = ConfNodeNew();
1127     ConfNode *child;
1128 
1129     for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) {
1130         child = ConfNodeNew();
1131         child->name = SCStrdup(test_vals[u]);
1132         child->val = SCStrdup(test_vals[u]);
1133         TAILQ_INSERT_TAIL(&parent->head, child, next);
1134     }
1135 
1136     child = ConfNodeLookupChild(parent, "one");
1137     FAIL_IF(child == NULL);
1138     FAIL_IF(strcmp(child->name, "one") != 0);
1139     FAIL_IF(strcmp(child->val, "one") != 0);
1140 
1141     child = ConfNodeLookupChild(parent, "two");
1142     FAIL_IF(child == NULL);
1143     FAIL_IF(strcmp(child->name, "two") != 0);
1144     FAIL_IF(strcmp(child->val, "two") != 0);
1145 
1146     child = ConfNodeLookupChild(parent, "three");
1147     FAIL_IF(child == NULL);
1148     FAIL_IF(strcmp(child->name, "three") != 0);
1149     FAIL_IF(strcmp(child->val, "three") != 0);
1150 
1151     child = ConfNodeLookupChild(parent, "four");
1152     FAIL_IF(child != NULL);
1153 
1154     FAIL_IF(ConfNodeLookupChild(NULL, NULL) != NULL);
1155 
1156     if (parent != NULL) {
1157         ConfNodeFree(parent);
1158     }
1159 
1160     PASS;
1161 }
1162 
ConfNodeLookupChildValueTest(void)1163 static int ConfNodeLookupChildValueTest(void)
1164 {
1165     const char *test_vals[] = { "one", "two", "three" };
1166     size_t u;
1167 
1168     ConfNode *parent = ConfNodeNew();
1169     ConfNode *child;
1170     const char *value;
1171 
1172     for (u = 0; u < sizeof(test_vals)/sizeof(test_vals[0]); u++) {
1173         child = ConfNodeNew();
1174         child->name = SCStrdup(test_vals[u]);
1175         child->val = SCStrdup(test_vals[u]);
1176         TAILQ_INSERT_TAIL(&parent->head, child, next);
1177     }
1178 
1179     value = (char *)ConfNodeLookupChildValue(parent, "one");
1180     FAIL_IF(value == NULL);
1181     FAIL_IF(strcmp(value, "one") != 0);
1182 
1183     value = (char *)ConfNodeLookupChildValue(parent, "two");
1184     FAIL_IF(value == NULL);
1185     FAIL_IF(strcmp(value, "two") != 0);
1186 
1187     value = (char *)ConfNodeLookupChildValue(parent, "three");
1188     FAIL_IF(value == NULL);
1189     FAIL_IF(strcmp(value, "three") != 0);
1190 
1191     value = (char *)ConfNodeLookupChildValue(parent, "four");
1192     FAIL_IF(value != NULL);
1193 
1194     ConfNodeFree(parent);
1195 
1196     PASS;
1197 }
1198 
ConfGetChildValueWithDefaultTest(void)1199 static int ConfGetChildValueWithDefaultTest(void)
1200 {
1201     const char  *val = "";
1202     ConfCreateContextBackup();
1203     ConfInit();
1204     ConfSet("af-packet.0.interface", "eth0");
1205     ConfSet("af-packet.1.interface", "default");
1206     ConfSet("af-packet.1.cluster-type", "cluster_cpu");
1207 
1208     ConfNode *myroot = ConfGetNode("af-packet.0");
1209     ConfNode *dflt = ConfGetNode("af-packet.1");
1210     ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val);
1211     FAIL_IF(strcmp(val, "cluster_cpu"));
1212 
1213     ConfSet("af-packet.0.cluster-type", "cluster_flow");
1214     ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val);
1215 
1216     FAIL_IF(strcmp(val, "cluster_flow"));
1217 
1218     ConfDeInit();
1219     ConfRestoreContextBackup();
1220     PASS;
1221 }
1222 
ConfGetChildValueIntWithDefaultTest(void)1223 static int ConfGetChildValueIntWithDefaultTest(void)
1224 {
1225     intmax_t val = 0;
1226     ConfCreateContextBackup();
1227     ConfInit();
1228     ConfSet("af-packet.0.interface", "eth0");
1229     ConfSet("af-packet.1.interface", "default");
1230     ConfSet("af-packet.1.threads", "2");
1231 
1232     ConfNode *myroot = ConfGetNode("af-packet.0");
1233     ConfNode *dflt = ConfGetNode("af-packet.1");
1234     ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val);
1235     FAIL_IF(val != 2);
1236 
1237     ConfSet("af-packet.0.threads", "1");
1238     ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val);
1239     FAIL_IF(val != 1);
1240 
1241     ConfDeInit();
1242     ConfRestoreContextBackup();
1243 
1244     PASS;
1245 }
1246 
ConfGetChildValueBoolWithDefaultTest(void)1247 static int ConfGetChildValueBoolWithDefaultTest(void)
1248 {
1249     int val;
1250     ConfCreateContextBackup();
1251     ConfInit();
1252     ConfSet("af-packet.0.interface", "eth0");
1253     ConfSet("af-packet.1.interface", "default");
1254     ConfSet("af-packet.1.use-mmap", "yes");
1255 
1256     ConfNode *myroot = ConfGetNode("af-packet.0");
1257     ConfNode *dflt = ConfGetNode("af-packet.1");
1258     ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val);
1259     FAIL_IF(val == 0);
1260 
1261     ConfSet("af-packet.0.use-mmap", "no");
1262     ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val);
1263     FAIL_IF(val);
1264 
1265     ConfDeInit();
1266     ConfRestoreContextBackup();
1267 
1268     PASS;
1269 }
1270 
1271 /**
1272  * Test the removal of a configuration node.
1273  */
ConfNodeRemoveTest(void)1274 static int ConfNodeRemoveTest(void)
1275 {
1276     ConfCreateContextBackup();
1277     ConfInit();
1278 
1279     FAIL_IF(ConfSet("some.nested.parameter", "blah") != 1);
1280 
1281     ConfNode *node = ConfGetNode("some.nested.parameter");
1282     FAIL_IF(node == NULL);
1283     ConfNodeRemove(node);
1284 
1285     node = ConfGetNode("some.nested.parameter");
1286     FAIL_IF(node != NULL);
1287 
1288     ConfDeInit();
1289     ConfRestoreContextBackup();
1290 
1291     PASS;
1292 }
1293 
ConfSetTest(void)1294 static int ConfSetTest(void)
1295 {
1296     ConfCreateContextBackup();
1297     ConfInit();
1298 
1299     /* Set some value with 2 levels. */
1300     FAIL_IF(ConfSet("one.two", "three") != 1);
1301     ConfNode *n = ConfGetNode("one.two");
1302     FAIL_IF(n == NULL);
1303 
1304     /* Set another 2 level parameter with the same first level, this
1305      * used to trigger a bug that caused the second level of the name
1306      * to become a first level node. */
1307     FAIL_IF(ConfSet("one.three", "four") != 1);
1308 
1309     n = ConfGetNode("one.three");
1310     FAIL_IF(n == NULL);
1311 
1312     /* A top level node of "three" should not exist. */
1313     n = ConfGetNode("three");
1314     FAIL_IF(n != NULL);
1315 
1316     ConfDeInit();
1317     ConfRestoreContextBackup();
1318 
1319     PASS;
1320 }
1321 
ConfGetNodeOrCreateTest(void)1322 static int ConfGetNodeOrCreateTest(void)
1323 {
1324     ConfNode *node;
1325 
1326     ConfCreateContextBackup();
1327     ConfInit();
1328 
1329     /* Get a node that should not exist, give it a value, re-get it
1330      * and make sure the second time it returns the existing node. */
1331     node = ConfGetNodeOrCreate("node0", 0);
1332     FAIL_IF(node == NULL);
1333     FAIL_IF(node->parent == NULL || node->parent != root);
1334     FAIL_IF(node->val != NULL);
1335     node->val = SCStrdup("node0");
1336     node = ConfGetNodeOrCreate("node0", 0);
1337     FAIL_IF(node == NULL);
1338     FAIL_IF(node->val == NULL);
1339     FAIL_IF(strcmp(node->val, "node0") != 0);
1340 
1341     /* Do the same, but for something deeply nested. */
1342     node = ConfGetNodeOrCreate("parent.child.grandchild", 0);
1343     FAIL_IF(node == NULL);
1344     FAIL_IF(node->parent == NULL || node->parent == root);
1345     FAIL_IF(node->val != NULL);
1346     node->val = SCStrdup("parent.child.grandchild");
1347     node = ConfGetNodeOrCreate("parent.child.grandchild", 0);
1348     FAIL_IF(node == NULL);
1349     FAIL_IF(node->val == NULL);
1350     FAIL_IF(strcmp(node->val, "parent.child.grandchild") != 0);
1351 
1352     /* Test that 2 child nodes have the same root. */
1353     ConfNode *child1 = ConfGetNodeOrCreate("parent.kids.child1", 0);
1354     ConfNode *child2 = ConfGetNodeOrCreate("parent.kids.child2", 0);
1355     FAIL_IF(child1 == NULL || child2 == NULL);
1356     FAIL_IF(child1->parent != child2->parent);
1357     FAIL_IF(strcmp(child1->parent->name, "kids") != 0);
1358 
1359     ConfDeInit();
1360     ConfRestoreContextBackup();
1361 
1362     PASS;
1363 }
1364 
ConfNodePruneTest(void)1365 static int ConfNodePruneTest(void)
1366 {
1367     ConfNode *node;
1368 
1369     ConfCreateContextBackup();
1370     ConfInit();
1371 
1372     /* Test that final nodes exist after a prune. */
1373     FAIL_IF(ConfSet("node.notfinal", "notfinal") != 1);
1374     FAIL_IF(ConfSetFinal("node.final", "final") != 1);
1375     FAIL_IF(ConfGetNode("node.notfinal") == NULL);
1376     FAIL_IF(ConfGetNode("node.final") == NULL);
1377     FAIL_IF((node = ConfGetNode("node")) == NULL);
1378     ConfNodePrune(node);
1379     FAIL_IF(ConfGetNode("node.notfinal") != NULL);
1380     FAIL_IF(ConfGetNode("node.final") == NULL);
1381 
1382     /* Test that everything under a final node exists after a prune. */
1383     FAIL_IF(ConfSet("node.final.one", "one") != 1);
1384     FAIL_IF(ConfSet("node.final.two", "two") != 1);
1385     ConfNodePrune(node);
1386     FAIL_IF(ConfNodeLookupChild(node, "final") == NULL);
1387     FAIL_IF(ConfGetNode("node.final.one") == NULL);
1388     FAIL_IF(ConfGetNode("node.final.two") == NULL);
1389 
1390     ConfDeInit();
1391     ConfRestoreContextBackup();
1392 
1393     PASS;
1394 }
1395 
ConfNodeIsSequenceTest(void)1396 static int ConfNodeIsSequenceTest(void)
1397 {
1398     ConfNode *node = ConfNodeNew();
1399     FAIL_IF(node == NULL);
1400     FAIL_IF(ConfNodeIsSequence(node));
1401     node->is_seq = 1;
1402     FAIL_IF(!ConfNodeIsSequence(node));
1403 
1404     if (node != NULL) {
1405         ConfNodeFree(node);
1406     }
1407     PASS;
1408 }
1409 
ConfSetFromStringTest(void)1410 static int ConfSetFromStringTest(void)
1411 {
1412     ConfNode *n;
1413 
1414     ConfCreateContextBackup();
1415     ConfInit();
1416 
1417     FAIL_IF_NOT(ConfSetFromString("stream.midstream=true", 0));
1418     n = ConfGetNode("stream.midstream");
1419     FAIL_IF_NULL(n);
1420     FAIL_IF_NULL(n->val);
1421     FAIL_IF(strcmp("true", n->val));
1422 
1423     FAIL_IF_NOT(ConfSetFromString("stream.midstream =false", 0));
1424     n = ConfGetNode("stream.midstream");
1425     FAIL_IF_NULL(n);
1426     FAIL_IF(n->val == NULL || strcmp("false", n->val));
1427 
1428     FAIL_IF_NOT(ConfSetFromString("stream.midstream= true", 0));
1429     n = ConfGetNode("stream.midstream");
1430     FAIL_IF_NULL(n);
1431     FAIL_IF(n->val == NULL || strcmp("true", n->val));
1432 
1433     FAIL_IF_NOT(ConfSetFromString("stream.midstream = false", 0));
1434     n = ConfGetNode("stream.midstream");
1435     FAIL_IF_NULL(n);
1436     FAIL_IF(n->val == NULL || strcmp("false", n->val));
1437 
1438     ConfDeInit();
1439     ConfRestoreContextBackup();
1440     PASS;
1441 }
1442 
ConfNodeHasChildrenTest(void)1443 static int ConfNodeHasChildrenTest(void)
1444 {
1445     ConfCreateContextBackup();
1446     ConfInit();
1447 
1448     /* Set a plain key with value. */
1449     ConfSet("no-children", "value");
1450     ConfNode *n = ConfGetNode("no-children");
1451     FAIL_IF_NULL(n);
1452     FAIL_IF(ConfNodeHasChildren(n));
1453 
1454     /* Set a key with a sub key to a value. This makes the first key a
1455      * map. */
1456     ConfSet("parent.child", "value");
1457     n = ConfGetNode("parent");
1458     FAIL_IF_NULL(n);
1459     FAIL_IF(!ConfNodeHasChildren(n));
1460 
1461     ConfDeInit();
1462     ConfRestoreContextBackup();
1463     PASS;
1464 }
1465 
ConfRegisterTests(void)1466 void ConfRegisterTests(void)
1467 {
1468     UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant);
1469     UtRegisterTest("ConfSetTest", ConfSetTest);
1470     UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet);
1471     UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1);
1472     UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2);
1473     UtRegisterTest("ConfTestGetInt", ConfTestGetInt);
1474     UtRegisterTest("ConfTestGetBool", ConfTestGetBool);
1475     UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest);
1476     UtRegisterTest("ConfNodeLookupChildValueTest",
1477                    ConfNodeLookupChildValueTest);
1478     UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest);
1479     UtRegisterTest("ConfGetChildValueWithDefaultTest",
1480                    ConfGetChildValueWithDefaultTest);
1481     UtRegisterTest("ConfGetChildValueIntWithDefaultTest",
1482                    ConfGetChildValueIntWithDefaultTest);
1483     UtRegisterTest("ConfGetChildValueBoolWithDefaultTest",
1484                    ConfGetChildValueBoolWithDefaultTest);
1485     UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest);
1486     UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest);
1487     UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest);
1488     UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest);
1489     UtRegisterTest("ConfNodeHasChildrenTest", ConfNodeHasChildrenTest);
1490 }
1491 
1492 #endif /* UNITTESTS */
1493