xdasd_filter.c

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------------
00002  * Copyright (c) 2006, Novell, Inc.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions are 
00007  * met:
00008  * 
00009  *     * Redistributions of source code must retain the above copyright 
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright 
00012  *       notice, this list of conditions and the following disclaimer in the 
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Novell nor the names of its contributors 
00015  *       may be used to endorse or promote products derived from this 
00016  *       software without specific prior written permission.
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00020  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00021  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
00022  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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;            /* allow = 0, deny = 1 */
00149    Attribute attribute;
00150    Operator op;
00151    unsigned number;        /* numeric value (if applicable) */
00152    char * text;            /* text literal */
00153 } Match;
00154 
00157 typedef struct action_tag
00158 {
00159    XDLItem elem;           
00160    ActionType atype;
00161    int severity;           /* if atype is alarm, text is severity */
00162    char * text;            /* if atype if trigger, text is script */
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;       /* the XML parser */
00199    ParserState state;   /* current parser state */
00200    char fversion[32];   /* filter list version string */
00201    XDList filters;      /* filter list being built */
00202    Filter * f;          /* filter currently being built */
00203    Match * m;           /* match currently being built */
00204    Action * a;          /* action currently being built */
00205 } Parser;
00206 
00207 /* module static globals */
00208 static char g_filter_version[32];
00209 static XDList g_filters = {0, 0, 0};
00210 
00211 
00212 /* ---------------------- Begin XML Filter Parser ---------------------- */
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;          /* default filters to 'ON' */
00336    f->ftype = FT_SUBMIT;   /* default filter type to submit only */
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;  /* should never happen */
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       /* strip trailing white space */
00770       while (len > 0 && isspace(s[len-1]))
00771          len--;
00772 
00773       /* strip leading white space */
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) /* add one for trailing \n */
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];    /* can't be more than 2 chars + null */
00844 
00845       /* locate field if field value specified */
00846       script += 6;                     /* skip "$XDAS(" */
00847       ep = script;
00848       while (ep < limit && *ep != ')') ep++;  /* find close paren */
00849       if (ep >= limit)
00850       {
00851          xdasd_log(0, "xfilter: Bad script variable format - no closing paren.\n");
00852          return -1;
00853       }
00854 
00855       /* find the correct field number for this field name */
00856       vlen = ep - script;
00857       *ep = 0;                         /* temporarily terminate for lookup */
00858       attr = xf_parse_match_attr(script);
00859       *ep = ')';                       /* then restore close paren */
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       /* replace field name with field number - should always be shorter */
00868       sprintf(fnstr, "%d", attr);
00869       flen = strlen(fnstr);
00870       memmove(script + flen, ep, limit - ep);
00871       memcpy(script, fnstr, flen);
00872 
00873       /* reduce limit by difference in text lengths */
00874       limit -= vlen - flen; 
00875 
00876       /* move script (buffer pointer) past this macro */
00877       script = ep + 1;
00878    }
00879    *limit = 0;    /* terminate new shorter string */
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       /* remove leading and trailing white space */
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';  /* add trailing NL */
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             /* convert any hex numeric-literal fields */
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    /* set up context object */
01090    memset(&ps, 0, sizeof(ps));
01091    ps.state = PS_INIT;
01092    ps.xp = xp;
01093    XML_SetUserData(xp, &ps);
01094 
01095    /* set handlers */
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(); /* clean up any old filters */
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 /* ----------------------- End XML Filter Parser ----------------------- */
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;  /* start with no match */
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;  /* stop now - insufficient data */
01268 
01269       /* check for numeric or text match */
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;    /* returns either -1, 0, or 1 from here */
01278 }
01279 
01280 
01281 /* ----------------------- End module static code ----------------------- */
01282 
01283 
01325 int xdasd_filter_check(Parsed * parsed, int onlycheck)
01326 {
01327    int log = -1;        /* initialize to "Default" state    */
01328    int severity = 0;    /* initialize to "No Alarm" state   */
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       /* is filter enabled, and does filter type match message type? */
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;  /* insufficient information */
01347 
01348          a = (Action *)f->actions.head;
01349          while (a)
01350          {
01351             switch(a->atype)
01352             {
01353                case ACT_LOG:
01354                   /* This filter only applies to logging if fstate is
01355                      not "no-match" and log is not already explicitly set. */
01356                   if (fstate != -1 && log != 1)
01357                      log = fstate;
01358                   break;
01359 
01360                case ACT_ALARM:   
01361                   /* This filter only applies to alarms if fstate is true
01362                      and a previously applied alarm has a lesser severity. */
01363                   if (fstate == 1 && severity < a->severity)
01364                      severity = a->severity;
01365                   break;
01366 
01367                case ACT_TRIGGER:
01368                   /* This filter only applies to triggers if fstate is true. */
01369                   if (fstate == 1)
01370                   {
01371                      triggers++;
01372                      if (xdasd_parse_set_trigger(parsed, onlycheck? 0: a->text) != 0)
01373                         return -1;  /* memory allocation failure */
01374                   }
01375                   break;
01376             }
01377             a = (Action *)a->elem.next;
01378          }
01379       }
01380       f = (Filter *)f->elem.next;
01381    }
01382 
01383    /* check for XDAS_S_NO_AUDIT condition, bail early on "no audit" */
01384    if (log == 0 && severity == 0 && triggers == 0)
01385       return 0;   /* no audit is required */
01386 
01387    /* apply log and alarm states after all filters have been processed */
01388    xdasd_parse_set_log_state(parsed, log);
01389    xdasd_parse_set_alarm_severity(parsed, severity);
01390 
01391    return 1;      /* audit is required */
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    /* if filter file specified on command-line, use it */
01551    if (argc > 1)
01552       filter_file = argv[1];
01553 
01554    /* create test filter file */
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    /* initialize filter module */
01564    if (xdasd_filter_init(filter_file) != 0)
01565       return -2;
01566 
01567    /* check filter database to ensure it contains what it should */
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    /* cleanup and return success */
01598    xdasd_filter_exit();
01599    return rv;
01600 }
01601 
01602 #endif
01603 

Generated on Thu Aug 20 22:33:05 2009 for OpenXDAS by  doxygen 1.5.6