38 #include <libxml/tree.h>
39 #include <libxml/parser.h>
40 #include <libxml/xpath.h>
41 #include <libxml/xpathInternals.h>
42 #include <libxml/relaxng.h>
48 #define StrFree(ptr) {if(ptr != NULL) {free(ptr); (ptr) = NULL;}}
50 void log_init(
int facility,
const char *program_name)
52 openlog(program_name, 0, facility);
59 openlog(program_name, 0, facility);
68 va_start(args, format);
71 if (strncmp(format,
"ERROR:", 6) == 0) {
72 vsyslog(LOG_ERR, format, args);
74 else if (strncmp(format,
"WARNING:", 8) == 0) {
75 vsyslog(LOG_WARNING, format, args);
77 else if (strncmp(format,
"DEBUG:", 6) == 0) {
78 vsyslog(LOG_DEBUG, format, args);
81 vsyslog(LOG_INFO, format, args);
84 vprintf(format, args2);
92 int check_rng(
const char *filename,
const char *rngfilename) {
95 xmlDocPtr rngdoc = NULL;
96 xmlRelaxNGParserCtxtPtr rngpctx = NULL;
97 xmlRelaxNGValidCtxtPtr rngctx = NULL;
98 xmlRelaxNGPtr schema = NULL;
101 dual_log(
"DEBUG: About to check XML validity in %s", filename);
105 doc = xmlParseFile(filename);
107 dual_log(
"ERROR: unable to parse file \"%s\"", filename);
115 rngdoc = xmlParseFile(rngfilename);
116 if (rngdoc == NULL) {
117 dual_log(
"ERROR: unable to parse file \"%s\"", rngfilename);
127 rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
128 if (rngpctx == NULL) {
129 dual_log(
"ERROR: unable to create XML RelaxNGs parser context");
137 xmlRelaxNGSetParserErrors(rngpctx,
138 (xmlRelaxNGValidityErrorFunc) fprintf,
139 (xmlRelaxNGValidityWarningFunc) fprintf,
143 schema = xmlRelaxNGParse(rngpctx);
144 if (schema == NULL) {
145 dual_log(
"ERROR: unable to parse a schema definition resource");
147 xmlRelaxNGFreeParserCtxt(rngpctx);
155 rngctx = xmlRelaxNGNewValidCtxt(schema);
156 if (rngctx == NULL) {
157 dual_log(
"ERROR: unable to create RelaxNGs validation context based on the schema");
159 xmlRelaxNGFree(schema);
160 xmlRelaxNGFreeParserCtxt(rngpctx);
167 xmlRelaxNGSetValidErrors(rngctx,
168 (xmlRelaxNGValidityErrorFunc) fprintf,
169 (xmlRelaxNGValidityWarningFunc) fprintf,
173 if (xmlRelaxNGValidateDoc(rngctx,doc) != 0) {
174 dual_log(
"ERROR: %s fails to validate", filename);
176 xmlRelaxNGFreeValidCtxt(rngctx);
177 xmlRelaxNGFree(schema);
178 xmlRelaxNGFreeParserCtxt(rngpctx);
185 xmlRelaxNGFreeValidCtxt(rngctx);
186 xmlRelaxNGFree(schema);
187 xmlRelaxNGFreeParserCtxt(rngpctx);
194 int check_file(
const char *filename,
const char *log_string) {
195 struct stat stat_ret;
197 if (stat(filename, &stat_ret) != 0) {
199 if (errno != ENOENT) {
200 dual_log(
"ERROR: cannot stat file %s: %s",
201 filename, strerror(errno));
205 dual_log(
"ERROR: %s (%s) does not exist", log_string, filename);
209 if (S_ISREG(stat_ret.st_mode)) {
214 dual_log(
"ERROR: %s (%s) does not exist", log_string, filename);
220 xmlXPathObjectPtr xpath_obj;
221 char* temp_char = NULL;
224 xpath_obj = xmlXPathEvalExpression(file_xexpr, xpath_ctx);
225 if(xpath_obj == NULL) {
226 dual_log(
"ERROR: unable to evaluate xpath expression: %s", file_xexpr);
229 if (xpath_obj->nodesetval != NULL && xpath_obj->nodesetval->nodeNr > 0) {
230 temp_char = (
char*) xmlXPathCastToString(xpath_obj);
233 str = strrchr(temp_char,
' ');
243 xmlXPathFreeObject(xpath_obj);
247 xmlXPathFreeObject(xpath_obj);
251 int check_path(
const char *pathname,
const char *log_string) {
252 struct stat stat_ret;
254 if (stat(pathname, &stat_ret) != 0) {
255 if (errno != ENOENT) {
256 dual_log(
"ERROR: cannot stat directory %s: %s",
257 pathname, strerror(errno));
261 dual_log(
"ERROR: %s (%s) does not exist", log_string, pathname);
265 if (S_ISDIR(stat_ret.st_mode)) {
270 dual_log(
"ERROR: %s (%s) is not a directory", log_string, pathname);
276 xmlXPathObjectPtr xpath_obj;
277 char* temp_char = NULL;
279 xpath_obj = xmlXPathEvalExpression(path_xexpr, xpath_ctx);
280 if(xpath_obj == NULL) {
281 dual_log(
"ERROR: unable to evaluate xpath expression: %s", path_xexpr);
284 if (xpath_obj->nodesetval != NULL && xpath_obj->nodesetval->nodeNr > 0) {
285 temp_char = (
char*) xmlXPathCastToString(xpath_obj);
292 xmlXPathFreeObject(xpath_obj);
296 xmlXPathFreeObject(xpath_obj);
300 int check_user_group(xmlXPathContextPtr xpath_ctx,
const xmlChar *user_xexpr,
const xmlChar *group_xexpr) {
302 xmlXPathObjectPtr xpath_obj;
303 char* temp_char = NULL;
309 xpath_obj = xmlXPathEvalExpression(group_xexpr, xpath_ctx);
310 if(xpath_obj == NULL) {
311 dual_log(
"ERROR: unable to evaluate xpath expression: %s", group_xexpr);
314 if (xpath_obj->nodesetval != NULL && xpath_obj->nodesetval->nodeNr > 0) {
315 temp_char = (
char*) xmlXPathCastToString(xpath_obj);
317 if ((grp = getgrnam(temp_char)) == NULL) {
318 dual_log(
"ERROR: Group '%s' does not exist", temp_char);
325 xmlXPathFreeObject(xpath_obj);
328 xpath_obj = xmlXPathEvalExpression(user_xexpr, xpath_ctx);
329 if(xpath_obj == NULL) {
330 dual_log(
"ERROR: unable to evaluate xpath expression: %s", user_xexpr);
333 if (xpath_obj->nodesetval != NULL && xpath_obj->nodesetval->nodeNr > 0) {
334 temp_char = (
char*) xmlXPathCastToString(xpath_obj);
336 if ((pwd = getpwnam(temp_char)) == NULL) {
337 dual_log(
"ERROR: User '%s' does not exist", temp_char);
345 xmlXPathFreeObject(xpath_obj);
350 int check_time_def(
const char *time_expr,
const char *location,
const char *field,
const char *filename,
int* interval) {
357 dual_log(
"WARNING: In %s M used in duration field for %s (%s) in %s - this will be interpreted as 31 days", location, field, time_expr, filename);
360 dual_log(
"WARNING: In %s Y used in duration field for %s (%s) in %s - this will be interpreted as 365 days", location, field, time_expr, filename);
363 dual_log(
"WARNING: In %s M & Y used in duration field for %s (%s) in %s - these will be interpreted as 31 and 365 days respectively", location, field, time_expr, filename);
366 dual_log(
"ERROR: unable to translate %s (%s) to seconds.", field, time_expr);
369 dual_log(
"ERROR: %s (%s) too long to be an int. E.g. Maximum is ~68 years on a system with 32-bit integers.", field, time_expr);
372 dual_log(
"ERROR: invalid pointers or text string NULL in %s (%s).", field, time_expr);
375 dual_log(
"ERROR: unknown error converting %s (%s) to seconds", field, time_expr);
387 int check_time_def_from_xpath(xmlXPathContextPtr xpath_ctx,
const xmlChar *time_xexpr,
const char *location,
const char *field,
const char *filename) {
389 xmlXPathObjectPtr xpath_obj;
390 char* temp_char = NULL;
394 xpath_obj = xmlXPathEvalExpression(time_xexpr, xpath_ctx);
395 if(xpath_obj == NULL) {
396 dual_log(
"ERROR: unable to evaluate xpath expression: %s", time_xexpr);
399 if (xpath_obj->nodesetval != NULL && xpath_obj->nodesetval->nodeNr > 0) {
400 temp_char = (
char *)xmlXPathCastToString(xpath_obj);
401 status +=
check_time_def(temp_char, location, field, filename, &ignore);
405 xmlXPathFreeObject(xpath_obj);
413 char* temp_char = NULL;
419 int resigns_per_day = 0;
434 char *ksk_repo = NULL;
438 char *zsk_repo = NULL;
444 if (xmlStrEqual(curNode->name, (
const xmlChar *)
"Signatures")) {
445 childNode = curNode->children;
447 if (xmlStrEqual(childNode->name, (
const xmlChar *)
"Resign")) {
448 temp_char = (
char *) xmlNodeGetContent(childNode);
449 status +=
check_time_def(temp_char, my_policy,
"Signatures/Resign", kasp, &resign);
452 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"Refresh")) {
453 temp_char = (
char *) xmlNodeGetContent(childNode);
454 status +=
check_time_def(temp_char, my_policy,
"Signatures/Refresh", kasp, &refresh);
457 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"Validity")) {
458 childNode2 = childNode->children;
460 if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Default")) {
461 temp_char = (
char *) xmlNodeGetContent(childNode2);
462 status +=
check_time_def(temp_char, my_policy,
"Signatures/Validity/Default", kasp, &defalt);
465 else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Denial")) {
466 temp_char = (
char *) xmlNodeGetContent(childNode2);
467 status +=
check_time_def(temp_char, my_policy,
"Signatures/Validity/Denial", kasp, &denial);
470 childNode2 = childNode2->next;
473 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"Jitter")) {
474 temp_char = (
char *) xmlNodeGetContent(childNode);
475 status +=
check_time_def(temp_char, my_policy,
"Signatures/Jitter", kasp, &jitter);
478 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"InceptionOffset")) {
479 temp_char = (
char *) xmlNodeGetContent(childNode);
480 status +=
check_time_def(temp_char, my_policy,
"Signatures/InceptionOffset", kasp, &inception);
484 childNode = childNode->next;
487 else if (xmlStrEqual(curNode->name, (
const xmlChar *)
"Denial")) {
488 childNode = curNode->children;
491 if (xmlStrEqual(childNode->name, (
const xmlChar *)
"NSEC")) {
494 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"NSEC3")) {
496 childNode2 = childNode->children;
499 if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Resalt")) {
500 temp_char = (
char *) xmlNodeGetContent(childNode2);
501 status +=
check_time_def(temp_char, my_policy,
"Denial/NSEC3/Resalt", kasp, &resalt);
503 }
else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Hash")) {
504 childNode3 = childNode2->children;
507 if (xmlStrEqual(childNode3->name, (
const xmlChar *)
"Algorithm")) {
508 temp_char = (
char *) xmlNodeGetContent(childNode3);
510 hash_algo = atoi(temp_char);
511 if (hash_algo != 1) {
512 dual_log(
"ERROR: NSEC3 Hash algorithm for %s Policy "
513 "in %s is %d but should be 1", policy_name,
519 childNode3 = childNode3->next;
524 childNode2 = childNode2->next;
528 childNode = childNode->next;
531 else if (xmlStrEqual(curNode->name, (
const xmlChar *)
"Keys")) {
532 childNode = curNode->children;
535 if (xmlStrEqual(childNode->name, (
const xmlChar *)
"TTL")) {
536 temp_char = (
char *) xmlNodeGetContent(childNode);
537 status +=
check_time_def(temp_char, my_policy,
"Keys/TTL", kasp, &ttl);
540 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"RetireSafety")) {
541 temp_char = (
char *) xmlNodeGetContent(childNode);
542 status +=
check_time_def(temp_char, my_policy,
"Keys/RetireSafety", kasp, &retire);
545 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"PublishSafety")) {
546 temp_char = (
char *) xmlNodeGetContent(childNode);
547 status +=
check_time_def(temp_char, my_policy,
"Keys/PublishSafety", kasp, &publish);
550 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"KSK")) {
551 childNode2 = childNode->children;
554 if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Algorithm")) {
555 temp_char = (
char *) xmlNodeGetContent(childNode2);
559 temp_char = (
char *)xmlGetProp(childNode2, (
const xmlChar *)
"length");
563 else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Lifetime")) {
564 temp_char = (
char *) xmlNodeGetContent(childNode2);
565 status +=
check_time_def(temp_char, my_policy,
"Keys/KSK Lifetime", kasp, &ksk_life);
568 else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Repository")) {
569 ksk_repo = (
char *) xmlNodeGetContent(childNode2);
572 childNode2 = childNode2->next;
575 else if (xmlStrEqual(childNode->name, (
const xmlChar *)
"ZSK")) {
576 childNode2 = childNode->children;
579 if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Algorithm")) {
580 temp_char = (
char *) xmlNodeGetContent(childNode2);
584 temp_char = (
char *)xmlGetProp(childNode2, (
const xmlChar *)
"length");
589 else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Lifetime")) {
590 temp_char = (
char *) xmlNodeGetContent(childNode2);
591 status +=
check_time_def(temp_char, my_policy,
"Keys/ZSK Lifetime", kasp, &zsk_life);
594 else if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Repository")) {
595 zsk_repo = (
char *) xmlNodeGetContent(childNode2);
598 childNode2 = childNode2->next;
602 childNode = childNode->next;
605 else if (xmlStrEqual(curNode->name, (
const xmlChar *)
"Zone")) {
606 childNode = curNode->children;
609 if (xmlStrEqual(childNode->name, (
const xmlChar *)
"SOA")) {
610 childNode2 = childNode->children;
613 if (xmlStrEqual(childNode2->name, (
const xmlChar *)
"Serial")) {
614 serial = (
char *) xmlNodeGetContent(childNode2);
617 childNode2 = childNode2->next;
621 childNode = childNode->next;
626 curNode = curNode->next;
634 if (refresh && refresh <= resign) {
635 dual_log(
"ERROR: The Refresh interval (%d seconds) for "
636 "%s Policy in %s is less than or equal to the Resign interval "
637 "(%d seconds)", refresh, policy_name, kasp, resign);
643 if (defalt <= refresh) {
644 dual_log(
"ERROR: Validity/Default (%d seconds) for "
645 "%s policy in %s is less than or equal to the Refresh interval "
646 "(%d seconds)", defalt, policy_name, kasp, refresh);
649 if (denial <= refresh) {
650 dual_log(
"ERROR: Validity/Denial (%d seconds) for "
651 "%s policy in %s is less than or equal to the Refresh interval "
652 "(%d seconds)", denial, policy_name, kasp, refresh);
660 if (defalt > denial) {
661 if (jitter > (defalt * 0.5)) {
662 dual_log(
"WARNING: Jitter time (%d seconds) is large "
663 "compared to Validity/Default (%d seconds) "
664 "for %s policy in %s", jitter, defalt, policy_name, kasp);
667 if (jitter > (denial * 0.5)) {
668 dual_log(
"WARNING: Jitter time (%d seconds) is large "
669 "compared to Validity/Denial (%d seconds) "
670 "for %s policy in %s", jitter, denial, policy_name, kasp);
678 if (inception > 3600) {
679 dual_log(
"WARNING: InceptionOffset is higher than expected "
680 "(%d seconds) for %s policy in %s",
681 inception, policy_name, kasp);
686 if (publish < (ttl * 0.1)) {
687 dual_log(
"WARNING: Keys/PublishSafety (%d seconds) is less than "
688 "0.1 * TTL (%d seconds) for %s policy in %s",
689 publish, ttl, policy_name, kasp);
691 else if (publish > (ttl * 5)) {
692 dual_log(
"WARNING: Keys/PublishSafety (%d seconds) is greater than "
693 "5 * TTL (%d seconds) for %s policy in %s",
694 publish, ttl, policy_name, kasp);
697 if (retire < (ttl * 0.1)) {
698 dual_log(
"WARNING: Keys/RetireSafety (%d seconds) is less than "
699 "0.1 * TTL (%d seconds) for %s policy in %s",
700 retire, ttl, policy_name, kasp);
702 else if (retire > (ttl * 5)) {
703 dual_log(
"WARNING: Keys/RetireSafety (%d seconds) is greater than "
704 "5 * TTL (%d seconds) for %s policy in %s",
705 retire, ttl, policy_name, kasp);
712 else if (nsec == 3) {
714 dual_log(
"ERROR: In policy %s, incompatible algorithm (%d) used for "
715 "KSK NSEC3 in %s. Policy must have id greater than 5.", policy_name, ksk_algo, kasp);
719 dual_log(
"ERROR: In policy %s, incompatible algorithm (%d) used for "
720 "ZSK NSEC3 in %s. Policy must have id greater than 5.", policy_name, zsk_algo, kasp);
725 if (resalt < resign) {
726 dual_log(
"WARNING: NSEC3 resalt interval (%d secs) is less than "
727 "signature resign interval (%d secs) for %s Policy",
728 resalt, resign, policy_name);
736 if (serial != NULL && strncmp(serial,
"datecounter", 11) == 0) {
738 resigns_per_day = (60 * 60 * 24) / resign;
739 if (resigns_per_day > 99) {
740 dual_log(
"ERROR: In %s, policy %s, serial type datecounter used "
741 "but %d re-signs requested. No more than 99 re-signs per "
742 "day should be used with datecounter as only 2 digits are "
743 "allocated for the version number.",
744 kasp, policy_name, resigns_per_day);
753 if (ksk_algo == 5 || ksk_algo == 7 || ksk_algo == 8 || ksk_algo == 10) {
754 if (ksk_length < 1024) {
755 dual_log(
"WARNING: Key length of %d used for KSK in %s policy in %s. Should "
756 "probably be 1024 or more", ksk_length, policy_name, kasp);
758 else if (ksk_length > 4096) {
759 dual_log(
"ERROR: Key length of %d used for KSK in %s policy in %s. Should "
760 "be 4096 or less", ksk_length, policy_name, kasp);
764 if (zsk_algo == 5 || zsk_algo == 7 || zsk_algo == 8 || zsk_algo == 10) {
765 if (zsk_length < 1024) {
766 dual_log(
"WARNING: Key length of %d used for ZSK in %s policy in %s. Should "
767 "probably be 1024 or more", zsk_length, policy_name, kasp);
769 else if (zsk_length > 4096) {
770 dual_log(
"ERROR: Key length of %d used for ZSK in %s policy in %s. Should "
771 "be 4096 or less", zsk_length, policy_name, kasp);
778 if (ksk_repo != NULL) {
780 if (strcmp(ksk_repo, repo_list[i]) == 0) {
784 if (i >= repo_count) {
785 dual_log(
"ERROR: Unknown repository (%s) defined for KSK in "
786 "%s policy in %s", ksk_repo, policy_name, kasp);
791 if (zsk_repo != NULL) {
793 if (strcmp(zsk_repo, repo_list[i]) == 0) {
797 if (i >= repo_count) {
798 dual_log(
"ERROR: Unknown repository (%s) defined for ZSK in "
799 "%s policy", zsk_repo, policy_name);
805 if (ksk_life < zsk_life) {
806 dual_log(
"WARNING: KSK minimum lifetime (%d seconds) is less than "
807 "ZSK minimum lifetime (%d seconds) for %s Policy in %s",
808 ksk_life, zsk_life, policy_name, kasp);
814 if (jitter > defalt) {
815 dual_log(
"ERROR: Jitter time (%d seconds) is greater than the "
816 "Default Validity (%d seconds) for %s policy in %s",
817 jitter, defalt, policy_name, kasp);
820 if (jitter > denial) {
821 dual_log(
"ERROR: Jitter time (%d seconds) is greater than the "
822 "Denial Validity (%d seconds) for %s policy in %s",
823 jitter, denial, policy_name, kasp);
897 const char *ptr = text;
899 long temp_interval = 0;
901 if (!text || !interval || !*text)
return 4;
902 length = strlen(text);
903 if (length <= 2)
return 2;
909 if (*ptr !=
'P')
return 2;
916 if (!got_temp || !is_time)
return 2;
917 temp_interval += temp;
923 if (!got_temp)
return 2;
925 temp_interval += 60 * temp;
927 temp_interval += 31 * 24 * 60 * 60 * temp;
935 if (!got_temp || !is_time)
return 2;
936 temp_interval += 60 * 60 * temp;
942 if (!got_temp || is_time)
return 2;
943 temp_interval += 24 * 60 * 60 * temp;
949 if (!got_temp || is_time)
return 2;
950 temp_interval += 7 * 24 * 60 * 60 * temp;
956 if (!got_temp || is_time)
return 2;
957 temp_interval += 365 * 24 * 60 * 60 * temp;
979 temp = strtol(ptr, &endptr, 10);
980 if (temp == LONG_MIN || temp == LONG_MAX)
989 if (ptr != end)
return 2;
996 if (temp && !is_time)
return 2;
997 temp_interval += temp;
999 if (is_neg) temp_interval *= -1;
1000 *interval = (int) temp_interval;
1030 if (value == NULL) {
1031 dual_log(
"ERROR: NULL value passed to StrStrtoi");
1036 if ((longval >= INT_MIN) && (longval <= INT_MAX)) {
1037 *value = (int) longval;
1076 if (value == NULL) {
1077 dual_log(
"ERROR: NULL value passed to StrStrtol");
1089 *value = strtol(start, &endptr, 10);
1094 status = (*endptr ==
'\0') ? 0 : 1;
1125 char* duplicate = NULL;
1128 duplicate = strdup(
string);
1129 if (duplicate == NULL) {
1130 dual_log(
"ERROR: StrStrdup: Call to malloc() returned null - out of swap space?");
1174 len2 = strlen(str2);
1176 len1 = strlen(*str1);
1180 *str1 =
MemRealloc(*str1, (len1 + len2 + 1) *
sizeof(
char));
1181 strcat(*str1, str2);
1216 int textlen = strlen(text);
1217 while (-- textlen >= 0) {
1218 if (! isspace((
int) text[textlen])) {
1219 text[textlen + 1] =
'\0';
1252 while (*text && isspace((
int) *text)) {
1262 void *ptr = calloc(nmemb, size);
1264 dual_log(
"ERROR: calloc: Out of swap space");
1272 void *ptr1 = realloc(ptr, size);
1274 dual_log(
"ERROR: realloc: Out of swap space");
int check_time_def(const char *time_expr, const char *location, const char *field, const char *filename, int *interval)
char * StrStrdup(const char *string)
int check_path(const char *pathname, const char *log_string)
void * MemRealloc(void *ptr, size_t size)
int DtXMLIntervalSeconds(const char *text, int *interval)
void StrTrimR(char *text)
int check_policy(xmlNode *curNode, const char *policy_name, char **repo_list, int repo_count, const char *kasp)
void * MemCalloc(size_t nmemb, size_t size)
int check_rng(const char *filename, const char *rngfilename)
void log_switch(int facility, const char *program_name)
int check_path_from_xpath(xmlXPathContextPtr xpath_ctx, const char *log_string, const xmlChar *path_xexpr)
int check_file(const char *filename, const char *log_string)
int StrStrtol(const char *string, long *value)
void log_init(int facility, const char *program_name)
int StrStrtoi(const char *string, int *value)
void dual_log(const char *format,...)
void StrAppend(char **str1, const char *str2)
int check_time_def_from_xpath(xmlXPathContextPtr xpath_ctx, const xmlChar *time_xexpr, const char *location, const char *field, const char *filename)
int check_user_group(xmlXPathContextPtr xpath_ctx, const xmlChar *user_xexpr, const xmlChar *group_xexpr)
int check_file_from_xpath(xmlXPathContextPtr xpath_ctx, const char *log_string, const xmlChar *file_xexpr)
char * StrTrimL(char *text)