00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00042 #include <xdas.h>
00043
00044 #include "xdasd_filter.h"
00045 #include "xdasd_parse.h"
00046 #include "xdasd_list.h"
00047 #include "xdasd_log.h"
00048
00049 #include <expat.h>
00050
00051 #ifdef _WIN32
00052 # define strcasecmp _stricmp
00053 # define strncasecmp _strnicmp
00054 # define strdup _strdup
00055 #endif
00056
00057 #include <stdio.h>
00058 #include <string.h>
00059 #include <ctype.h>
00060
00061 #ifdef XML_LARGE_SIZE
00062 # if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
00063 # define XML_FMT_INT_MOD "I64"
00064 # else
00065 # define XML_FMT_INT_MOD "ll"
00066 # endif
00067 #else
00068 # define XML_FMT_INT_MOD "l"
00069 #endif
00070
00071 #define FT_SUBMIT 0x00000001
00072 #define FT_IMPORT 0x00000002
00073
00076 typedef enum
00077 {
00078 OP_UNKNOWN = -1,
00079 OP_EQUAL,
00080 OP_NOT_EQUAL,
00081 OP_GREATER_THAN,
00082 OP_LESS_THAN,
00083 OP_GT_OR_EQUAL,
00084 OP_LT_OR_EQUAL,
00085 OP_BIT_TEST,
00086 OP_SUBSTRING,
00087 } Operator;
00088
00096 typedef enum
00097 {
00098 AT_UNKNOWN = -1,
00099 AT_HDR = 0,
00100 AT_HDRLEN,
00101 AT_HDRVER,
00102 AT_HDRTMOFFS,
00103 AT_HDRTUINT,
00104 AT_HDRTUIND,
00105 AT_HDRTMSRC,
00106 AT_HDRTMZONE,
00107 AT_HDREVENT,
00108 AT_HDROUTCOME,
00109 AT_ORG,
00110 AT_ORGLOC,
00111 AT_ORGADDR,
00112 AT_ORGTYPE,
00113 AT_ORGAUT,
00114 AT_ORGNAME,
00115 AT_ORGID,
00116 AT_INT,
00117 AT_INTAUTH,
00118 AT_INTNAME,
00119 AT_INTID,
00120 AT_TGT,
00121 AT_TGTLOC,
00122 AT_TGTADDR,
00123 AT_TGTTYPE,
00124 AT_TGTAUTH,
00125 AT_TGTNAME,
00126 AT_TGTID,
00127 AT_SRC,
00128 AT_SRCDPTR,
00129 AT_EVT,
00130 AT_EVTINFO,
00131 AT_END,
00132 } Attribute;
00133
00136 typedef enum
00137 {
00138 ACT_LOG,
00139 ACT_ALARM,
00140 ACT_TRIGGER,
00141 } ActionType;
00142
00145 typedef struct match_tag
00146 {
00147 XDLItem elem;
00148 int inverse;
00149 Attribute attribute;
00150 Operator op;
00151 unsigned number;
00152 char * text;
00153 } Match;
00154
00157 typedef struct action_tag
00158 {
00159 XDLItem elem;
00160 ActionType atype;
00161 int severity;
00162 char * text;
00163 } Action;
00164
00167 typedef struct filter_tag
00168 {
00169 XDLItem elem;
00170 char * name;
00171 int status;
00172 unsigned ftype;
00173 XDList matches;
00174 XDList actions;
00175 } Filter;
00176
00179 typedef enum
00180 {
00181 PS_INIT,
00182 PS_FILTER_EXPECTED,
00183 PS_MATCH_OR_ACTION_EXPECTED,
00184 PS_MATCH_EXPECTED,
00185 PS_ALLOW_IN_PROGRESS,
00186 PS_DENY_IN_PROGRESS,
00187 PS_ACTION_EXPECTED,
00188 PS_LOG_IN_PROGRESS,
00189 PS_ALARM_IN_PROGRESS,
00190 PS_TRIGGER_IN_PROGRESS,
00191 PS_TERMINATE,
00192 } ParserState;
00193
00196 typedef struct parser_tag
00197 {
00198 XML_Parser xp;
00199 ParserState state;
00200 char fversion[32];
00201 XDList filters;
00202 Filter * f;
00203 Match * m;
00204 Action * a;
00205 } Parser;
00206
00207
00208 static char g_filter_version[32];
00209 static XDList g_filters = {0, 0, 0};
00210
00211
00212
00213
00214
00227 static char * strncasestr(const char * haystack, const char * needle,
00228 size_t haystacksz)
00229 {
00230 int nlen = (int)strlen(needle);
00231 const char * limit = haystack + haystacksz;
00232 while (haystack < limit)
00233 {
00234 if (tolower(*haystack) == tolower(*needle) && nlen <= limit - haystack
00235 && strncasecmp(needle, haystack, nlen) == 0)
00236 return (char *)haystack;
00237 haystack++;
00238 }
00239 return 0;
00240 }
00241
00246 static char * strcasestr(const char * haystack, const char * needle)
00247 { return strncasestr(haystack, needle, strlen(haystack)); }
00248
00261 static int xf_parse_filter_list_version(char * fv, size_t fvsz,
00262 const char ** attrs)
00263 {
00264 const char ** p;
00265 for (p = attrs; *p; p += 2)
00266 {
00267 if (strcmp(p[0], "version") == 0)
00268 {
00269 strncpy(fv, p[1], fvsz - 1);
00270 fv[fvsz-1] = 0;
00271 }
00272 else
00273 xdasd_log(0, "xfilter: Ignoring unknown <filter-list> "
00274 "attribute, %s='%s'.\n", p[0], p[1]);
00275 }
00276 if (*fv == 0)
00277 {
00278 xdasd_log(0, "xfilter: Missing <filter-list> version attribute.\n");
00279 return -1;
00280 }
00281 if (strcmp(fv, "OX1") != 0)
00282 {
00283 xdasd_log(0, "xfilter: Incorrect <filter-list> version (%s) - "
00284 "this parser only supports 'OX1'.\n", fv);
00285 return -1;
00286 }
00287 return 0;
00288 }
00289
00298 static int xf_parse_filter_status(const char * status)
00299 {
00300 return strcasecmp(status, "on") == 0
00301 || strcasecmp(status, "yes") == 0
00302 || strcasecmp(status, "true") == 0? 1: 0;
00303 }
00304
00313 static unsigned xf_parse_filter_type(const char * ftype)
00314 {
00315 unsigned rv = 0;
00316 if (strcasestr(ftype, "Submit") != 0)
00317 rv |= FT_SUBMIT;
00318 if (strcasestr(ftype, "Import") != 0)
00319 rv |= FT_IMPORT;
00320 return rv;
00321 }
00322
00332 static int xf_process_filter_attrs(Filter * f, const char ** attrs)
00333 {
00334 const char ** p;
00335 f->status = 1;
00336 f->ftype = FT_SUBMIT;
00337 for (p = attrs; *p; p += 2)
00338 {
00339 if (strcmp(p[0], "name") == 0)
00340 {
00341 free(f->name);
00342 if ((f->name = strdup(p[1])) == 0)
00343 {
00344 xdasd_log(0, "xfilter: Memory allocation failure "
00345 "during <filter> attribute parse.\n");
00346 return -1;
00347 }
00348 }
00349 else if (strcmp(p[0], "status") == 0)
00350 f->status = xf_parse_filter_status(p[1]);
00351 else if (strcmp(p[0], "type") == 0)
00352 f->ftype = xf_parse_filter_type(p[1]);
00353 else
00354 xdasd_log(0, "xfilter: Ignoring unknown <filter> "
00355 "attribute, %s='%s'.\n", p[0], p[1]);
00356 }
00357 if (f->name == 0)
00358 {
00359 xdasd_log(0, "xfilter: Anonymous XDAS filters are illegal.\n");
00360 return -1;
00361 }
00362 return 0;
00363 }
00364
00374 static Filter * xf_create_filter(const char ** attrs)
00375 {
00376 Filter * f;
00377 if ((f = (Filter *)malloc(sizeof(*f))) == 0)
00378 xdasd_log(0, "xfilter: Memory allocation failure during filter parse.\n");
00379 else
00380 {
00381 memset(f, 0, sizeof(*f));
00382 if (xf_process_filter_attrs(f, attrs) != 0)
00383 free(f), f = 0;
00384 }
00385 return f;
00386 }
00387
00392 static Filter * xf_find_filter(const char * name, XDList * fl)
00393 {
00394 Filter * f = (Filter *)fl->head;
00395 while (f && strcmp(name, f->name) != 0)
00396 f = (Filter *)f->elem.next;
00397 return f;
00398 }
00399
00404 static int xf_is_dup_filter(const char * name, XDList * f)
00405 {
00406 if (xf_find_filter(name, f) != 0)
00407 {
00408 xdasd_log(0, "xfilter: Duplicate filter name specified.\n");
00409 return 1;
00410 }
00411 return 0;
00412 }
00413
00423 static Attribute xf_parse_match_attr(const char * avalue)
00424 {
00425 static const struct { const char * astr; Attribute tok; } g_attrmap[] =
00426 {
00427 {"HDRLEN", AT_HDRLEN}, {"HDRVER", AT_HDRVER},
00428 {"HDRTMOFF", AT_HDRTMOFFS}, {"HDRTUINT",AT_HDRTUINT},
00429 {"HDRTUIND", AT_HDRTUIND}, {"HDRTMSRC",AT_HDRTMSRC},
00430 {"HDRTMZONE", AT_HDRTMZONE}, {"HDREVENT",AT_HDREVENT},
00431 {"HDROUTCOME",AT_HDROUTCOME},{"ORGLOC", AT_ORGLOC},
00432 {"ORGADDR", AT_ORGADDR}, {"ORGTYPE", AT_ORGTYPE},
00433 {"ORGAUT", AT_ORGAUT}, {"ORGNAME", AT_ORGNAME},
00434 {"ORGID", AT_ORGID}, {"INTAUTH", AT_INTAUTH},
00435 {"INTNAME", AT_INTNAME}, {"INTID", AT_INTID},
00436 {"TGTLOC", AT_TGTLOC}, {"TGTADDR", AT_TGTADDR},
00437 {"TGTTYPE", AT_TGTTYPE}, {"TGTAUTH", AT_TGTAUTH},
00438 {"TGTNAME", AT_TGTNAME}, {"TGTID", AT_TGTID},
00439 {"SRCDPTR", AT_SRCDPTR}, {"EVTINFO", AT_EVTINFO},
00440 };
00441 unsigned i;
00442
00443 for (i = 0; i < sizeof(g_attrmap)/sizeof(*g_attrmap); i++)
00444 if (strcasecmp(avalue, g_attrmap[i].astr) == 0)
00445 return g_attrmap[i].tok;
00446
00447 return AT_UNKNOWN;
00448 }
00449
00459 static Operator xf_parse_match_op(const char * avalue)
00460 {
00461 static struct { char * ostr; Operator tok; } omap[] =
00462 {
00463 {"EQ", OP_EQUAL}, {"NE", OP_NOT_EQUAL},
00464 {"GT", OP_GREATER_THAN}, {"LT", OP_LESS_THAN},
00465 {"GE", OP_GT_OR_EQUAL}, {"LE", OP_LT_OR_EQUAL},
00466 {"BT", OP_BIT_TEST}, {"SS", OP_SUBSTRING},
00467 };
00468 unsigned i;
00469
00470 for (i = 0; i < sizeof(omap)/sizeof(*omap); i++)
00471 if (strcasecmp(avalue, omap[i].ostr) == 0)
00472 return omap[i].tok;
00473
00474 return OP_UNKNOWN;
00475 }
00476
00486 static int xf_process_match_attrs(Match * m, const char ** attrs)
00487 {
00488 const char ** p;
00489 m->attribute = AT_UNKNOWN;
00490 m->op = OP_UNKNOWN;
00491 for (p = attrs; *p; p += 2)
00492 {
00493 if (strcmp(p[0], "attr") == 0)
00494 m->attribute = xf_parse_match_attr(p[1]);
00495 else if (strcmp(p[0], "op") == 0)
00496 m->op = xf_parse_match_op(p[1]);
00497 else
00498 xdasd_log(0, "xfilter: Ignoring unknown <allow/deny> "
00499 "attribute, %s='%s'.\n", p[0], p[1]);
00500 }
00501 if (m->attribute == AT_UNKNOWN)
00502 {
00503 xdasd_log(0, "xfilter: Missing or unknown 'attr' "
00504 "value in <allow/deny> definition.\n");
00505 return -1;
00506 }
00507 if (m->op == OP_UNKNOWN)
00508 {
00509 xdasd_log(0, "xfilter: Missing or unknown 'op' "
00510 "value in <allow/deny> definition.\n");
00511 return -1;
00512 }
00513 return 0;
00514 }
00515
00526 static Match * xf_create_match(ParserState state, const char ** attrs)
00527 {
00528 Match * m;
00529 if ((m = (Match *)malloc(sizeof(*m))) == 0)
00530 xdasd_log(0, "xfilter: Memory allocation failure "
00531 "during <allow/deny> parse.\n");
00532 else
00533 {
00534 memset(m, 0, sizeof(*m));
00535 m->inverse = state == PS_DENY_IN_PROGRESS? 1: 0;
00536 if (xf_process_match_attrs(m, attrs) != 0)
00537 free(m), m = 0;
00538 }
00539 return m;
00540 }
00541
00551 static int xf_process_alarm_attrs(Action * a, const char ** attrs)
00552 {
00553 const char ** p;
00554 for (p = attrs; *p; p += 2)
00555 {
00556 if (strcmp(p[0], "severity") == 0)
00557 a->severity = strtoul(p[1], 0, 0);
00558 else
00559 xdasd_log(0, "xfilter: Ignoring unknown <alarm> "
00560 "attribute, %s='%s'.\n", p[0], p[1]);
00561 }
00562 return 0;
00563 }
00564
00572 static void xf_process_unknown_attrs(const char * el, const char ** attrs)
00573 {
00574 const char ** p;
00575 for (p = attrs; *p; p += 2)
00576 xdasd_log(0, "xfilter: Ignoring unknown <%s> "
00577 "attribute, %s='%s'.\n", el, p[0], p[1]);
00578 }
00579
00588 static ActionType xf_map_state_to_action(ParserState state)
00589 {
00590 switch(state)
00591 {
00592 case PS_LOG_IN_PROGRESS: return ACT_LOG;
00593 case PS_ALARM_IN_PROGRESS: return ACT_ALARM;
00594 case PS_TRIGGER_IN_PROGRESS: return ACT_TRIGGER;
00595 }
00596 return -1;
00597 }
00598
00609 static int xf_process_action_attrs(ParserState state, Action * a,
00610 const char ** attrs)
00611 {
00612 if (state == PS_ALARM_IN_PROGRESS)
00613 return xf_process_alarm_attrs(a, attrs);
00614 xf_process_unknown_attrs(state == PS_LOG_IN_PROGRESS?
00615 "log": "trigger", attrs);
00616 return 0;
00617 }
00618
00629 static Action * xf_create_action(ParserState state, const char ** attrs)
00630 {
00631 Action * a;
00632 if ((a = (Action *)malloc(sizeof(*a))) == 0)
00633 xdasd_log(0, "xfilter: Memory allocation failure during <action> parse.\n");
00634 else
00635 {
00636 memset(a, 0, sizeof(*a));
00637 a->atype = xf_map_state_to_action(state);
00638 if (xf_process_action_attrs(state, a, attrs) != 0)
00639 free(a), a = 0;
00640 }
00641 return a;
00642 }
00643
00656 static int xf_is_valid_filter_attr(unsigned ftype, Attribute attr)
00657 {
00658 if ((attr < AT_HDRVER || attr > AT_TGTID)
00659 || (attr >= AT_HDRTUINT && attr <= AT_HDRTMZONE)
00660 || (attr == AT_ORG || attr == AT_INT || attr == AT_TGT)
00661 || (ftype & FT_SUBMIT) == 0
00662 && attr != AT_HDRVER && attr != AT_HDREVENT
00663 && attr != AT_HDROUTCOME && attr != AT_INTAUTH)
00664 {
00665 xdasd_log(0, "xfilter: Invalid filter attribute for specified filter type.\n");
00666 return 0;
00667 }
00668 return 1;
00669 }
00670
00679 static void XMLCALL xf_start_tag(void * data, const char * el,
00680 const char ** attrs)
00681 {
00682 Parser * ps = (Parser *)data;
00683
00684 switch(ps->state)
00685 {
00686 case PS_INIT:
00687 if (strcmp(el, "filter-list") == 0)
00688 {
00689 ps->state = PS_FILTER_EXPECTED;
00690 if (xf_parse_filter_list_version(ps->fversion,
00691 sizeof(ps->fversion), attrs) != 0)
00692 XML_StopParser(ps->xp, XML_FALSE);
00693 }
00694 else
00695 XML_StopParser(ps->xp, XML_FALSE);
00696 break;
00697
00698 case PS_FILTER_EXPECTED:
00699 if (strcmp(el, "filter") == 0)
00700 {
00701 ps->state = PS_MATCH_OR_ACTION_EXPECTED;
00702 if ((ps->f = xf_create_filter(attrs)) == 0
00703 || xf_is_dup_filter(ps->f->name, &ps->filters))
00704 XML_StopParser(ps->xp, XML_FALSE);
00705 }
00706 else
00707 XML_StopParser(ps->xp, XML_FALSE);
00708 break;
00709
00710 case PS_MATCH_OR_ACTION_EXPECTED:
00711 if (strcmp(el, "match") == 0)
00712 ps->state = PS_MATCH_EXPECTED;
00713 else if (strcmp(el, "action") == 0)
00714 ps->state = PS_ACTION_EXPECTED;
00715 else
00716 XML_StopParser(ps->xp, XML_FALSE);
00717 break;
00718
00719 case PS_MATCH_EXPECTED:
00720 {
00721 if (strcmp(el, "allow") == 0)
00722 ps->state = PS_ALLOW_IN_PROGRESS;
00723 else if (strcmp(el, "deny") == 0)
00724 ps->state = PS_DENY_IN_PROGRESS;
00725 if (ps->state == PS_MATCH_EXPECTED
00726 || (ps->m = xf_create_match(ps->state, attrs)) == 0
00727 || !xf_is_valid_filter_attr(ps->f->ftype, ps->m->attribute))
00728 XML_StopParser(ps->xp, XML_FALSE);
00729 break;
00730 }
00731 case PS_ACTION_EXPECTED:
00732 if (strcmp(el, "log") == 0)
00733 ps->state = PS_LOG_IN_PROGRESS;
00734 else if (strcmp(el, "alarm") == 0)
00735 ps->state = PS_ALARM_IN_PROGRESS;
00736 else if (strcmp(el, "trigger") == 0)
00737 ps->state = PS_TRIGGER_IN_PROGRESS;
00738 if (ps->state == PS_ACTION_EXPECTED
00739 || (ps->a = xf_create_action(ps->state, attrs)) == 0)
00740 XML_StopParser(ps->xp, XML_FALSE);
00741 break;
00742
00743 default:
00744 XML_StopParser(ps->xp, XML_FALSE);
00745 break;
00746 }
00747 }
00748
00765 static int xf_gather_text_data(char ** tpp, const char * s, int len, int raw)
00766 {
00767 if (!raw || *tpp == 0)
00768 {
00769
00770 while (len > 0 && isspace(s[len-1]))
00771 len--;
00772
00773
00774 while (len > 0 && isspace(*s))
00775 s++, len--;
00776 }
00777 if (len > 0)
00778 {
00779 size_t osz = *tpp? strlen(*tpp): 0;
00780 size_t sz = osz + len + 1;
00781
00782 char * tp;
00783 if ((tp = (char *)malloc(sz + 1)) == 0)
00784 {
00785 xdasd_log(0, "xfilter: Memory allocation failure "
00786 "during element data parse.\n");
00787 return -1;
00788 }
00789 memcpy(tp, *tpp, osz);
00790 memcpy(tp + osz, s, len);
00791 tp[sz - 1] = 0;
00792 free(*tpp);
00793 *tpp = tp;
00794 }
00795 return 0;
00796 }
00797
00806 static void XMLCALL xf_elem_data(void * data, const XML_Char * s, int len)
00807 {
00808 Parser * ps = (Parser *)data;
00809
00810 switch(ps->state)
00811 {
00812 case PS_ALLOW_IN_PROGRESS:
00813 case PS_DENY_IN_PROGRESS:
00814 if (xf_gather_text_data(&ps->m->text, s, len, 0) != 0)
00815 XML_StopParser(ps->xp, XML_FALSE);
00816 break;
00817
00818 case PS_TRIGGER_IN_PROGRESS:
00819 if (xf_gather_text_data(&ps->a->text, s, len, 1) != 0)
00820 XML_StopParser(ps->xp, XML_FALSE);
00821 break;
00822 }
00823 }
00824
00837 static int xf_replace_script_varnames(char * script, char * limit)
00838 {
00839 while ((script = strcasestr(script, "$XDAS(")) != 0)
00840 {
00841 Attribute attr;
00842 size_t vlen, flen;
00843 char * ep, fnstr[3];
00844
00845
00846 script += 6;
00847 ep = script;
00848 while (ep < limit && *ep != ')') ep++;
00849 if (ep >= limit)
00850 {
00851 xdasd_log(0, "xfilter: Bad script variable format - no closing paren.\n");
00852 return -1;
00853 }
00854
00855
00856 vlen = ep - script;
00857 *ep = 0;
00858 attr = xf_parse_match_attr(script);
00859 *ep = ')';
00860 if (attr == AT_UNKNOWN)
00861 {
00862 xdasd_log(0, "xfilter: Bad script variable format - "
00863 "unknown field name %.*s.\n", vlen, script);
00864 return -1;
00865 }
00866
00867
00868 sprintf(fnstr, "%d", attr);
00869 flen = strlen(fnstr);
00870 memmove(script + flen, ep, limit - ep);
00871 memcpy(script, fnstr, flen);
00872
00873
00874 limit -= vlen - flen;
00875
00876
00877 script = ep + 1;
00878 }
00879 *limit = 0;
00880 return 0;
00881 }
00882
00894 static int xf_cleanup_trigger_script(Action * a)
00895 {
00896 if (a->text)
00897 {
00898 char * bp = a->text;
00899 char * ep = a->text + strlen(a->text);
00900
00901
00902 while (bp < ep && isspace(*bp)) bp++;
00903 while (ep - 1 > bp && isspace(ep[-1])) ep--;
00904
00905 if (bp >= ep)
00906 {
00907 free(a->text);
00908 a->text = 0;
00909 }
00910 else
00911 {
00912 memmove(a->text, bp, ep - bp);
00913 a->text[ep++ - bp] = '\n';
00914 a->text[ep - bp] = 0;
00915 if (xf_replace_script_varnames(a->text, a->text + (ep - bp)) != 0)
00916 return -1;
00917 }
00918 }
00919 return 0;
00920 }
00921
00930 static int xf_is_attr_numeric(Attribute attr)
00931 {
00932 return (attr == AT_HDRLEN || attr == AT_HDRTMOFFS
00933 || attr == AT_HDRTUINT || attr == AT_HDRTUIND
00934 || attr == AT_HDREVENT || attr == AT_HDROUTCOME)? 1: 0;
00935 }
00936
00944 static void XMLCALL xf_end_tag(void * data, const char * el)
00945 {
00946 Parser * ps = (Parser *)data;
00947
00948 switch(ps->state)
00949 {
00950 case PS_FILTER_EXPECTED:
00951 if (strcmp(el, "filter-list") == 0)
00952 ps->state = PS_TERMINATE;
00953 else
00954 XML_StopParser(ps->xp, XML_FALSE);
00955 break;
00956
00957 case PS_MATCH_OR_ACTION_EXPECTED:
00958 if (strcmp(el, "filter") == 0)
00959 {
00960 ps->state = PS_FILTER_EXPECTED;
00961 if (ps->f)
00962 {
00963 xdasd_list_link_tail(&ps->filters, &ps->f->elem);
00964 ps->f = 0;
00965 }
00966 }
00967 else if (strcmp(el, "match") != 0
00968 && strcmp(el, "action") != 0)
00969 XML_StopParser(ps->xp, XML_FALSE);
00970 break;
00971
00972 case PS_MATCH_EXPECTED:
00973 if (strcmp(el, "match") == 0)
00974 ps->state = PS_MATCH_OR_ACTION_EXPECTED;
00975 else if (strcmp(el, "allow") != 0
00976 && strcmp(el, "deny") != 0)
00977 XML_StopParser(ps->xp, XML_FALSE);
00978 break;
00979
00980 case PS_ACTION_EXPECTED:
00981 if (strcmp(el, "action") == 0)
00982 ps->state = PS_MATCH_OR_ACTION_EXPECTED;
00983 else if (strcmp(el, "log") != 0
00984 && strcmp(el, "alarm") != 0
00985 && strcmp(el, "trigger") != 0)
00986 XML_StopParser(ps->xp, XML_FALSE);
00987 break;
00988
00989 case PS_ALLOW_IN_PROGRESS:
00990 case PS_DENY_IN_PROGRESS:
00991 if (ps->m)
00992 {
00993
00994 if (ps->m->text != 0 && xf_is_attr_numeric(ps->m->attribute))
00995 ps->m->number = strtoul(ps->m->text, 0, 16);
00996 xdasd_list_link_tail(&ps->f->matches, &ps->m->elem);
00997 ps->m = 0;
00998 }
00999 ps->state = PS_MATCH_EXPECTED;
01000 break;
01001
01002 case PS_LOG_IN_PROGRESS:
01003 case PS_ALARM_IN_PROGRESS:
01004 case PS_TRIGGER_IN_PROGRESS:
01005 if (ps->a)
01006 {
01007 if (ps->a->text != 0)
01008 {
01009 if (ps->a->atype == ACT_ALARM)
01010 ps->a->severity = strtoul(ps->a->text, 0, 0);
01011 else if (ps->a->atype == ACT_TRIGGER
01012 && xf_cleanup_trigger_script(ps->a) != 0)
01013 XML_StopParser(ps->xp, XML_FALSE);
01014 }
01015 xdasd_list_link_tail(&ps->f->actions, &ps->a->elem);
01016 ps->a = 0;
01017 }
01018 ps->state = PS_ACTION_EXPECTED;
01019 break;
01020
01021 default:
01022 XML_StopParser(ps->xp, XML_FALSE);
01023 break;
01024 }
01025 }
01026
01027 #ifdef LOG_TO_STDOUT
01028
01034 static void xf_display_filters(XDList * filters)
01035 {
01036 Filter * f = (Filter *)filters->head;
01037 printf("XDAS Filter Version: %s\n", g_filter_version);
01038 while (f)
01039 {
01040 Match * m = (Match *)f->matches.head;
01041 Action * a = (Action *)f->actions.head;
01042 printf("Filter: %s\n", f->name);
01043 printf(" Matches:\n");
01044 while (m)
01045 {
01046 printf(" %c %d %d %s\n", m->inverse? '-': '+',
01047 m->attribute, m->op, m->text);
01048 m = (Match *)m->elem.next;
01049 }
01050 printf(" Actions:\n");
01051 while (a)
01052 {
01053 printf(" %d %s\n", a->atype, a->text? a->text: "");
01054 a = (Action *)a->elem.next;
01055 }
01056 f = (Filter *)f->elem.next;
01057 }
01058 }
01059 #endif
01060
01069 static int xf_parse_xml_filter(const char * xmlfile)
01070 {
01071 int done, err = 0;
01072 XML_Parser xp;
01073 FILE * fp = 0;
01074 Parser ps;
01075 char buf[4096];
01076
01077 if ((fp = fopen(xmlfile, "r")) == 0)
01078 {
01079 xdasd_log(0, "xfilter: No filter file found.\n");
01080 return 0;
01081 }
01082 if ((xp = XML_ParserCreate(0)) == 0)
01083 {
01084 xdasd_log(0, "xfilter: XML parser creation failed.\n");
01085 fclose(fp);
01086 return -1;
01087 }
01088
01089
01090 memset(&ps, 0, sizeof(ps));
01091 ps.state = PS_INIT;
01092 ps.xp = xp;
01093 XML_SetUserData(xp, &ps);
01094
01095
01096 XML_SetElementHandler(xp, xf_start_tag, xf_end_tag);
01097 XML_SetCharacterDataHandler(xp, xf_elem_data);
01098
01099 do
01100 {
01101 size_t len = fread(buf, 1, sizeof(buf), fp);
01102 if (ferror(fp))
01103 {
01104 xdasd_log(0, "xfilter: Filter file I/O error.\n");
01105 err = -1;
01106 break;
01107 }
01108 done = feof(fp);
01109 if (XML_Parse(xp, buf, (int)len, done) == XML_STATUS_ERROR)
01110 {
01111 xdasd_log(0, "xfilter: Filter file XML parse error"
01112 " at line %" XML_FMT_INT_MOD "u: %s\n",
01113 XML_GetCurrentLineNumber(xp),
01114 XML_ErrorString(XML_GetErrorCode(xp)));
01115 err = -1;
01116 break;
01117 }
01118 } while (!done);
01119
01120 XML_ParserFree(xp);
01121 fclose(fp);
01122
01123 if (!err)
01124 {
01125 xdasd_filter_exit();
01126 memcpy(&g_filters, &ps.filters, sizeof(g_filters));
01127 memcpy(g_filter_version, ps.fversion, sizeof(g_filter_version));
01128 #ifdef LOG_TO_STDOUT
01129 xf_display_filters(&g_filters);
01130 #endif
01131 }
01132 return err;
01133 }
01134
01135
01136
01137
01138
01145 static void xf_free_match(Match * m)
01146 {
01147 free(m->text);
01148 free(m);
01149 }
01150
01157 static void xf_free_action(Action * a)
01158 {
01159 free(a->text);
01160 free(a);
01161 }
01162
01169 static void xf_free_filter(Filter * f)
01170 {
01171 XDLItem * ip = f->matches.head;
01172 while (ip)
01173 {
01174 XDLItem * del = ip;
01175 ip = ip->next;
01176 xf_free_match((Match *)del);
01177 }
01178
01179 ip = f->actions.head;
01180 while (ip)
01181 {
01182 XDLItem * del = ip;
01183 ip = ip->next;
01184 xf_free_action((Action *)del);
01185 }
01186 free(f->name);
01187 free(f);
01188 }
01189
01201 static int xf_is_numeric_field_match(unsigned fld,
01202 Operator op, unsigned number)
01203 {
01204 switch(op)
01205 {
01206 case OP_EQUAL: return fld == number;
01207 case OP_NOT_EQUAL: return fld != number;
01208 case OP_GREATER_THAN: return fld > number;
01209 case OP_LESS_THAN: return fld < number;
01210 case OP_GT_OR_EQUAL: return fld >= number;
01211 case OP_LT_OR_EQUAL: return fld <= number;
01212 case OP_BIT_TEST: return !!(fld & number);
01213 }
01214 return 0;
01215 }
01216
01229 static int xf_is_text_field_match(const char * fld, size_t fldsz,
01230 Operator op, const char * text)
01231 {
01232 switch(op)
01233 {
01234 case OP_EQUAL: return strncasecmp(fld, text, fldsz) == 0;
01235 case OP_NOT_EQUAL: return strncasecmp(fld, text, fldsz) != 0;
01236 case OP_GREATER_THAN: return strncasecmp(fld, text, fldsz) > 0;
01237 case OP_LESS_THAN: return strncasecmp(fld, text, fldsz) < 0;
01238 case OP_GT_OR_EQUAL: return strncasecmp(fld, text, fldsz) >= 0;
01239 case OP_LT_OR_EQUAL: return strncasecmp(fld, text, fldsz) <= 0;
01240 case OP_SUBSTRING: return strncasestr(fld, text, fldsz) != 0;
01241 }
01242 return 0;
01243 }
01244
01256 static int xf_filter_matches(Parsed * parsed, XDList * matches)
01257 {
01258 int fstate = -1;
01259 Match * m = (Match *)matches->head;
01260
01261 while (m)
01262 {
01263 const char ** p = parsed->parsed + m->attribute;
01264 size_t fldlen = p[1] - p[0] - 1;
01265
01266 if (fldlen == 0)
01267 return -2;
01268
01269
01270 if (xf_is_attr_numeric(m->attribute)?
01271 xf_is_numeric_field_match(strtoul(p[0], 0, 16), m->op, m->number):
01272 xf_is_text_field_match(p[0], fldlen, m->op, m->text))
01273 fstate = m->inverse? 0: 1;
01274
01275 m = (Match *)m->elem.next;
01276 }
01277 return fstate;
01278 }
01279
01280
01281
01282
01283
01325 int xdasd_filter_check(Parsed * parsed, int onlycheck)
01326 {
01327 int log = -1;
01328 int severity = 0;
01329 int imported = (parsed->flags & PMF_IMPORTED) != 0;
01330 int triggers = 0;
01331 Filter * f = (Filter *)g_filters.head;
01332
01333 xdasd_parse_clear_actions(parsed);
01334
01335 while (f)
01336 {
01337
01338 if (f->status
01339 && ((imported && (f->ftype & FT_IMPORT) != 0)
01340 || (!imported && (f->ftype & FT_SUBMIT) != 0)))
01341 {
01342 Action * a;
01343 int fstate = xf_filter_matches(parsed, &f->matches);
01344
01345 if (fstate == -2)
01346 return -2;
01347
01348 a = (Action *)f->actions.head;
01349 while (a)
01350 {
01351 switch(a->atype)
01352 {
01353 case ACT_LOG:
01354
01355
01356 if (fstate != -1 && log != 1)
01357 log = fstate;
01358 break;
01359
01360 case ACT_ALARM:
01361
01362
01363 if (fstate == 1 && severity < a->severity)
01364 severity = a->severity;
01365 break;
01366
01367 case ACT_TRIGGER:
01368
01369 if (fstate == 1)
01370 {
01371 triggers++;
01372 if (xdasd_parse_set_trigger(parsed, onlycheck? 0: a->text) != 0)
01373 return -1;
01374 }
01375 break;
01376 }
01377 a = (Action *)a->elem.next;
01378 }
01379 }
01380 f = (Filter *)f->elem.next;
01381 }
01382
01383
01384 if (log == 0 && severity == 0 && triggers == 0)
01385 return 0;
01386
01387
01388 xdasd_parse_set_log_state(parsed, log);
01389 xdasd_parse_set_alarm_severity(parsed, severity);
01390
01391 return 1;
01392 }
01393
01413 int xdasd_filter_process(int * minorp, xdas_buffer req, xdas_buffer * rspp)
01414 {
01415 (void)minorp;
01416 (void)req;
01417 (void)rspp;
01418
01421 return 0;
01422 }
01423
01432 int xdasd_filter_init(const char * filter_file)
01433 { return xf_parse_xml_filter(filter_file); }
01434
01439 void xdasd_filter_exit(void)
01440 {
01441 XDLItem * ip = g_filters.head;
01442 while (ip)
01443 {
01444 XDLItem * del = ip;
01445 ip = ip->next;
01446 xf_free_filter((Filter *)del);
01447 }
01448 }
01449
01450
01451
01452 #ifdef XDASD_FILTER_TEST
01453
01454 #include <stdarg.h>
01455
01462 void xdasd_log(int level, const char * fmt, ... )
01463 {
01464 #ifdef LOG_TO_STDOUT
01465 va_list args;
01466 va_start(args, fmt);
01467 vprintf(fmt, args);
01468 va_end(args);
01469 #else
01470 (void)fmt;
01471 #endif
01472 }
01473
01480 int xdasd_log_level(void) { return 0; }
01481
01500 int main(int argc, char ** argv)
01501 {
01502 #define DEF_TEST_FILTER_FILE "xdasd.filter"
01503
01506 static char test_spec[] =
01507 "<filter-list version='OX1'>\n"
01508 " <filter name='Account Created' status='On' type='Submit, Import'>\n"
01509 " <match>\n"
01510 " <allow attr='HdrEvent' op='EQ'>0x10000001</allow>\n"
01511 " <deny attr='HdrOutcome' op='NE'>0</deny>\n"
01512 " </match>\n"
01513 " <action>\n"
01514 " <log />\n"
01515 " <alarm severity='3' />\n"
01516 " <trigger>\n"
01517 " <![CDATA[\n"
01518 "mailx -s \"OpenXDAS: Account $XDAS(TGTNAME) created by $XDAS(INTNAME)\" admin@some.com <<InputToHERE\n"
01519 "$XDAS\n"
01520 "InputToHERE\n"
01521 " ]]>\n"
01522 " </trigger>\n"
01523 " </action>\n"
01524 " </filter>\n"
01525 " <filter name='Account Deleted' status='On' type='Submit, Import'>\n"
01526 " <match>\n"
01527 " <allow attr='HdrEvent' op='EQ'>0x10000002</allow>\n"
01528 " <deny attr='HdrOutcome' op='NE'>0</deny>\n"
01529 " </match>\n"
01530 " <action>\n"
01531 " <log />\n"
01532 " <alarm severity='4' />\n"
01533 " <trigger>\n"
01534 " <![CDATA[\n"
01535 "echo \"Sending mail message.\"\n"
01536 "mailx -s \"OpenXDAS: Account $XDAS(TGTNAME) deleted by $XDAS(INTNAME)\" admin@some.com <<InputToHERE\n"
01537 "\"$XDAS\"\n"
01538 "InputToHERE\n"
01539 " ]]>\n"
01540 " </trigger>\n"
01541 " </action>\n"
01542 " </filter>\n"
01543 "</filter-list>\n";
01544
01545 FILE * fp;
01546 Filter * f;
01547 int rv = 0, fcnt, macnt;
01548 char * filter_file = DEF_TEST_FILTER_FILE;
01549
01550
01551 if (argc > 1)
01552 filter_file = argv[1];
01553
01554
01555 if ((fp = fopen(filter_file, "w+")) == 0)
01556 {
01557 fprintf(stderr, "Could not open filter file: %s.\n", filter_file);
01558 return -1;
01559 }
01560 fwrite(test_spec, 1, sizeof(test_spec) - 1, fp);
01561 fclose(fp);
01562
01563
01564 if (xdasd_filter_init(filter_file) != 0)
01565 return -2;
01566
01567
01568 f = (Filter *)g_filters.head;
01569 fcnt = 0;
01570 while (f)
01571 {
01572 Match * m = (Match *)f->matches.head;
01573 Action * a = (Action *)f->actions.head;
01574 if (f->name == 0) rv++;
01575 macnt = 0;
01576 while (m)
01577 {
01578 if (m->attribute == AT_UNKNOWN) rv++;
01579 if (m->op == OP_UNKNOWN) rv++;
01580 if (m->text == 0) rv++;
01581 macnt++;
01582 m = (Match *)m->elem.next;
01583 }
01584 if (macnt != 2) rv++;
01585 macnt = 0;
01586 while (a)
01587 {
01588 macnt++;
01589 a = (Action *)a->elem.next;
01590 }
01591 if (macnt != 3) rv++;
01592 fcnt++;
01593 f = (Filter *)f->elem.next;
01594 }
01595 if (fcnt != 2) rv++;
01596
01597
01598 xdasd_filter_exit();
01599 return rv;
01600 }
01601
01602 #endif
01603