1 /*
2     etterfilter -- the actual compiler
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ef.h>
23 #include <ef_functions.h>
24 #include <ec_filter.h>
25 
26 #include <ctype.h>
27 
28 #include <regex.h>
29 #ifdef HAVE_PCRE
30    #include <pcre.h>
31 #endif
32 
33 /* protos */
34 
35 static char ** decode_args(char *args, int *nargs);
36 static char * strsep_quotes(char **stringp, const char delim);
37 
38 /*******************************************/
39 
40 /*
41  * search an offset and fill the filter_op structure
42  * return E_SUCCESS on error.
43  */
encode_offset(char * string,struct filter_op * fop)44 int encode_offset(char *string, struct filter_op *fop)
45 {
46    char *str, *p, *q, *tok;
47    int ret;
48 
49    memset(fop, 0, sizeof(struct filter_op));
50 
51    /* make the modifications on a copy */
52    str = strdup(string);
53 
54    /*
55     * the offset contains at least one '.'
56     * we are sure because the syntax parser
57     * will not have passed it here if it is not
58     * in the right form.
59     */
60    p = ec_strtok(str, ".", &tok);
61    q = ec_strtok(NULL, ".", &tok);
62 
63    /*
64     * the assumption above is not always true, e.g.:
65     * log(DATA,d "x.log");
66     * results in q == NULL.
67     */
68    if (q == NULL)
69       return -E_NOTFOUND;
70 
71    /* the the virtual pointer from the table */
72    ret = get_virtualpointer(p, q, &fop->op.test.level, &fop->op.test.offset, &fop->op.test.size);
73 
74    SAFE_FREE(str);
75 
76    return ret;
77 }
78 
79 /*
80  * assing the value of the const to the fop.value
81  *
82  * all the value are integer32 and are saved in host order
83  */
encode_const(char * string,struct filter_op * fop)84 int encode_const(char *string, struct filter_op *fop)
85 {
86    char *p;
87 
88    memset(fop, 0, sizeof(struct filter_op));
89 
90    /* it is an hexadecimal value */
91    if (!strncmp(string, "0x", 2) && isxdigit((int)string[2])) {
92       fop->op.test.value = strtoul(string, NULL, 16);
93       return E_SUCCESS;
94 
95    /* it is an integer value */
96    } else if (isdigit((int)string[0])) {
97       fop->op.test.value = strtoul(string, NULL, 10);
98       return E_SUCCESS;
99 
100    /* it is an ip address */
101    } else if (string[0] == '\'' && string[strlen(string) - 1] == '\'') {
102       struct ip_addr ipaddr;
103 
104       /* remove the single quote */
105       p = strchr(string + 1, '\'');
106       *p = '\0';
107 
108       if (ip_addr_pton(string + 1, &ipaddr) == E_SUCCESS) {
109          switch (ntohs(ipaddr.addr_type)) {
110             case AF_INET:
111                /* 4-bytes - handle as a integer */
112                fop->op.test.value = ntohl(ipaddr.addr32[0]);
113                break;
114             case AF_INET6:
115                /* 16-bytes - handle as a byte pointer */
116                ip_addr_cpy((u_char*)&fop->op.test.ipaddr, &ipaddr);
117                break;
118             default:
119                return -E_FATAL;
120          }
121       }
122       else {
123          return -E_FATAL;
124       }
125 
126       return E_SUCCESS;
127 
128    /* it is a string */
129    } else if (string[0] == '\"' && string[strlen(string) - 1] == '\"') {
130 
131       /* remove the quotes */
132       p = strchr(string + 1, '\"');
133       *p = '\0';
134 
135       /* copy the string */
136       fop->op.test.string = (u_char*)strdup(string + 1);
137 
138       /* escape it in the structure */
139       fop->op.test.slen = strescape((char*)fop->op.test.string,
140             (char*)fop->op.test.string, strlen(fop->op.test.string)+1);
141 
142       return E_SUCCESS;
143 
144    /* it is a constant */
145    } else if (isalpha((int)string[0])) {
146       return get_constant(string, &fop->op.test.value);
147    }
148 
149    /* anything else is an error */
150    return -E_NOTFOUND;
151 }
152 
153 
154 /*
155  * parse a function and its arguments and fill the structure
156  */
encode_function(char * string,struct filter_op * fop)157 int encode_function(char *string, struct filter_op *fop)
158 {
159    char *str = strdup(string);
160    int ret = -E_NOTFOUND;
161    char *name, *args;
162    int nargs = 0, i;
163    char **dec_args = NULL;
164    char *tok;
165 
166    memset(fop, 0, sizeof(struct filter_op));
167 
168    /* get the name of the function */
169    name = ec_strtok(string, "(", &tok);
170    /* get all the args */
171    args = name + strlen(name) + 1;
172 
173    /* analyze the arguments */
174    dec_args = decode_args(args, &nargs);
175 
176    /* this fop is a function */
177    fop->opcode = FOP_FUNC;
178 
179    /* check if it is a known function */
180    if (!strcmp(name, "search")) {
181       if (nargs == 2) {
182          /* get the level (DATA or DECODED) */
183          if (encode_offset(dec_args[0], fop) == E_SUCCESS) {
184             /* encode offset wipe the fop !! */
185             fop->opcode = FOP_FUNC;
186             fop->op.func.op = FFUNC_SEARCH;
187             fop->op.func.string = (u_char*)strdup(dec_args[1]);
188             fop->op.func.slen = strescape((char*)fop->op.func.string,
189                   (char*)fop->op.func.string, strlen(fop->op.func.string)+1);
190             ret = E_SUCCESS;
191          } else
192             SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
193       } else
194          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
195    } else if (!strcmp(name, "regex")) {
196       if (nargs == 2) {
197          int err;
198          regex_t regex;
199          char errbuf[100];
200 
201          /* get the level (DATA or DECODED) */
202          if (encode_offset(dec_args[0], fop) == E_SUCCESS) {
203             /* encode offset wipe the fop !! */
204             fop->opcode = FOP_FUNC;
205             fop->op.func.op = FFUNC_REGEX;
206             fop->op.func.string = (u_char*)strdup(dec_args[1]);
207             fop->op.func.slen = strescape((char*)fop->op.func.string,
208                   (char*)fop->op.func.string, strlen(fop->op.func.string)+1);
209             ret = E_SUCCESS;
210          } else
211             SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
212 
213          /* check if the regex is valid */
214          err = regcomp(&regex, (const char*)fop->op.func.string, REG_EXTENDED | REG_NOSUB | REG_ICASE );
215          if (err) {
216             regerror(err, &regex, errbuf, sizeof(errbuf));
217             SCRIPT_ERROR("%s", errbuf);
218          }
219 
220          regfree(&regex);
221 
222       } else
223          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
224    } else if (!strcmp(name, "pcre_regex")) {
225 #ifndef HAVE_PCRE
226       WARNING("The script contains pcre_regex, but you don't have support for it.");
227 #else
228       pcre *pregex;
229       const char *errbuf = NULL;
230       int erroff;
231 
232       if (nargs == 2) {
233 
234          /* get the level (DATA or DECODED) */
235          if (encode_offset(dec_args[0], fop) == E_SUCCESS) {
236             /* encode offset wipe the fop !! */
237             fop->opcode = FOP_FUNC;
238             fop->op.func.op = FFUNC_PCRE;
239             fop->op.func.string = strdup(dec_args[1]);
240             fop->op.func.slen = strlen(fop->op.func.string);
241             ret = E_SUCCESS;
242          } else
243             SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
244 
245          /* check if the pcre is valid */
246          pregex = pcre_compile(fop->op.func.string, 0, &errbuf, &erroff, NULL );
247          if (pregex == NULL)
248             SCRIPT_ERROR("%s\n", errbuf);
249 
250          pcre_free(pregex);
251       } else if (nargs == 3) {
252 
253          fop->opcode = FOP_FUNC;
254          fop->op.func.op = FFUNC_PCRE;
255          /* substitution always at layer DATA */
256          fop->op.func.level = 5;
257          fop->op.func.string = strdup(dec_args[1]);
258          fop->op.func.slen = strlen(fop->op.func.string);
259          fop->op.func.replace = strdup(dec_args[2]);
260          fop->op.func.rlen = strlen(fop->op.func.replace);
261          ret = E_SUCCESS;
262 
263          /* check if the pcre is valid */
264          pregex = pcre_compile(fop->op.func.string, 0, &errbuf, &erroff, NULL );
265          if (pregex == NULL)
266             SCRIPT_ERROR("%s\n", errbuf);
267 
268          pcre_free(pregex);
269       } else
270          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
271 #endif
272    } else if (!strcmp(name, "replace")) {
273       if (nargs == 2) {
274          fop->op.func.op = FFUNC_REPLACE;
275          /* replace always operate at DATA level */
276          fop->op.func.level = 5;
277          fop->op.func.string = (u_char*)strdup(dec_args[0]);
278          fop->op.func.slen = strescape((char*)fop->op.func.string,
279                (char*)fop->op.func.string, strlen(fop->op.func.string)+1);
280          fop->op.func.replace = (u_char*)strdup(dec_args[1]);
281          fop->op.func.rlen = strescape((char*)fop->op.func.replace,
282                (char*)fop->op.func.replace, strlen(fop->op.func.replace)+1);
283          ret = E_SUCCESS;
284       } else
285          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
286    } else if (!strcmp(name, "inject")) {
287       if (nargs == 1) {
288          fop->op.func.op = FFUNC_INJECT;
289          /* inject always operate at DATA level */
290          fop->op.func.level = 5;
291          fop->op.func.string = (u_char*)strdup(dec_args[0]);
292          fop->op.func.slen = strlen((const char*)fop->op.func.string);
293          ret = E_SUCCESS;
294       } else
295          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
296    } else if (!strcmp(name, "execinject")) {
297       if (nargs == 1) {
298          fop->op.func.op = FFUNC_EXECINJECT;
299          /* execinject always operate at DATA level */
300          fop->op.func.level = 5;
301          fop->op.func.string = (u_char*)strdup(dec_args[0]);
302          fop->op.func.slen = strlen((const char*)fop->op.func.string);
303          ret = E_SUCCESS;
304       } else
305          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
306    } else if (!strcmp(name, "execreplace")) {
307       if (nargs == 1) {
308          fop->op.func.op = FFUNC_EXECREPLACE;
309          /* execreplace always operate at DATA level */
310          fop->op.func.level = 5;
311          fop->op.func.string = (u_char*)strdup(dec_args[0]);
312          fop->op.func.slen = strlen((const char*)fop->op.func.string);
313          ret = E_SUCCESS;
314       } else
315          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
316    } else if (!strcmp(name, "log")) {
317       if (nargs == 2) {
318          /* get the level (DATA or DECODED) */
319          if (encode_offset(dec_args[0], fop) == E_SUCCESS) {
320             /* encode offset wipe the fop !! */
321             fop->opcode = FOP_FUNC;
322             fop->op.func.op = FFUNC_LOG;
323             fop->op.func.string = (u_char*)strdup(dec_args[1]);
324             fop->op.func.slen = strlen((const char*)fop->op.func.string);
325             ret = E_SUCCESS;
326          } else
327             SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
328       } else
329          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
330    } else if (!strcmp(name, "drop")) {
331       if (nargs == 0) {
332          fop->op.func.op = FFUNC_DROP;
333          ret = E_SUCCESS;
334       } else
335          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
336    } else if (!strcmp(name, "kill")) {
337       if (nargs == 0) {
338          fop->op.func.op = FFUNC_KILL;
339          ret = E_SUCCESS;
340       } else
341          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
342    } else if (!strcmp(name, "msg")) {
343       if (nargs == 1) {
344          fop->op.func.op = FFUNC_MSG;
345          fop->op.func.string = (u_char*)strdup(dec_args[0]);
346          fop->op.func.slen = strescape((char*)fop->op.func.string,
347                (char*)fop->op.func.string, strlen(fop->op.func.string)+1);
348          ret = E_SUCCESS;
349       } else
350          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
351    } else if (!strcmp(name, "exec")) {
352       if (nargs == 1) {
353          fop->op.func.op = FFUNC_EXEC;
354          fop->op.func.string = (u_char*)strdup(dec_args[0]);
355          fop->op.func.slen = strlen((const char*)fop->op.func.string);
356          ret = E_SUCCESS;
357       } else
358          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
359    } else if (!strcmp(name, "exit")) {
360       if (nargs == 0) {
361          fop->opcode = FOP_EXIT;
362          ret = E_SUCCESS;
363       } else
364          SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
365    }
366 
367    /* free the array */
368    for (i = 0; i < nargs; i++)
369       SAFE_FREE(dec_args[i]);
370 
371    SAFE_FREE(dec_args);
372    SAFE_FREE(str);
373    return ret;
374 }
375 
376 /*
377  * split the args of a function and return
378  * the number of found args
379  */
decode_args(char * args,int * nargs)380 static char ** decode_args(char *args, int *nargs)
381 {
382    char *p, *q, *arg;
383    int i = 0;
384    char **parsed;
385 
386    *nargs = 0;
387 
388    /* get the end */
389    if ((p = strrchr(args, ')')) != NULL)
390       *p = '\0';
391 
392    /* trim the empty spaces */
393    for (; *args == ' '; args++);
394    for (q = args + strlen(args) - 1; *q == ' '; q--)
395       *q = '\0';
396 
397    /* there are no arguments */
398    if (!strchr(args, ',') && strlen(args) == 0)
399       return NULL;
400 
401    SAFE_CALLOC(parsed, 1, sizeof(char *));
402 
403    /* split the arguments */
404    for (p = strsep_quotes(&args, ','), i = 1; p != NULL; p = strsep_quotes(&args, ','), i++) {
405 
406       /* alloc the array for the arguments */
407       SAFE_REALLOC(parsed, (i + 1) * sizeof(char *));
408 
409       /* trim the empty spaces */
410       for (arg = p; *arg == ' '; arg++);
411       for (q = arg + strlen(arg) - 1; *q == ' '; q--)
412          *q = '\0';
413 
414       /* remove the quotes (if there are) */
415       if (*arg == '\"' && arg[strlen(arg) - 1] == '\"') {
416          arg[strlen(arg) - 1] = '\0';
417          arg++;
418       }
419       /* put in in the array */
420       parsed[i - 1] = strdup(arg);
421 
422       ef_debug(5, "ARGUMENT: %s\n", arg);
423    }
424 
425    /* return the number of args */
426    *nargs = i - 1;
427 
428    return parsed;
429 }
430 
431 
432 
433 /*
434  * split the string in tokens separated by 'delim'.
435  * ignore 'delim' if it is between two quotes "..."
436  */
strsep_quotes(char ** stringp,const char delim)437 static char * strsep_quotes(char **stringp, const char delim)
438 {
439 	char *s;
440 	int c;
441 	char *tok;
442 
443    /* sanity check */
444 	if ((s = *stringp) == NULL)
445 		return (NULL);
446 
447    /* parse the string */
448 	for (tok = s;;) {
449 
450       /* XXX -
451        * this does not parses correctly string in the form:
452        *
453        *  "foo, bar, "tic,tac""
454        */
455 
456       /* skip string between quotes */
457       if (*s == '\"')
458          while(*(++s) != '\"' && *s != '\0');
459 
460       c = *s++;
461 
462       /* search for the delimiter */
463       if ( c == delim || c == 0) {
464          if (c == 0)
465             s = NULL;
466          else
467             s[-1] = 0;
468 
469          *stringp = s;
470 
471          return (tok);
472       }
473 	}
474 	/* NOTREACHED */
475 }
476 
477 /* EOF */
478 
479 // vim:ts=3:expandtab
480 
481