From 0532d20e4dee3cb0cb25f005124f379a36318b06 Mon Sep 17 00:00:00 2001 From: Nick Galbreath Date: Mon, 27 May 2013 18:04:04 +0400 Subject: [PATCH 1/3] update to 3.0.0-pre2 --- apache2/libinjection/libinjection.h | 28 +- apache2/libinjection/libinjection_sqli.c | 781 +-- apache2/libinjection/libinjection_sqli_data.h | 4702 +++++++++++++---- 3 files changed, 3993 insertions(+), 1518 deletions(-) diff --git a/apache2/libinjection/libinjection.h b/apache2/libinjection/libinjection.h index 38fd9810..497fb2fe 100644 --- a/apache2/libinjection/libinjection.h +++ b/apache2/libinjection/libinjection.h @@ -37,7 +37,7 @@ extern "C" { * See python's normalized version * http://www.python.org/dev/peps/pep-0386/#normalizedversion */ -#define LIBINJECTION_VERSION "2.0.0" +#define LIBINJECTION_VERSION "3.0.0-pre2" #define ST_MAX_SIZE 32 #define MAX_TOKENS 5 @@ -50,6 +50,7 @@ typedef struct { char type; char str_open; char str_close; + char var_count; char val[ST_MAX_SIZE]; } stoken_t; @@ -62,18 +63,12 @@ typedef struct { size_t pos; int in_comment; - /* syntax fixups state */ - stoken_t syntax_current; - stoken_t syntax_last; - stoken_t syntax_comment; - - /* constant folding state */ - stoken_t fold_current; - stoken_t fold_last; - int fold_state; - /* final sqli data */ - stoken_t tokenvec[MAX_TOKENS]; + stoken_t *current; + + /* MAX TOKENS + 1 since use one extra token to determine + the type of the previous token */ + stoken_t tokenvec[MAX_TOKENS + 1]; /* +1 for ending null */ char pat[MAX_TOKENS + 1]; @@ -130,6 +125,15 @@ int libinjection_is_string_sqli(sfilter * sql_state, const char delim, ptr_fingerprints_fn fn, void* callbackarg); +/* FOR H@CKERS ONLY + * + */ + +void libinjection_sqli_init(sfilter* sql_state, const char* str, + size_t slen, char delim); + +int libinjection_sqli_tokenize(sfilter * sql_state, stoken_t *ouput); + #ifdef __cplusplus } #endif diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index b2d26221..4067c223 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -23,7 +23,7 @@ #endif #if 0 -#define FOLD_DEBUG printf("%d: Fold state = %d, current=%c, last=%c\n", __LINE__, sf->fold_state, current->type, last->type == CHAR_NULL ? '~': last->type) +#define FOLD_DEBUG printf("%d \t more=%d pos=%d left=%d\n", __LINE__, more, (int)pos, (int)left); #else #define FOLD_DEBUG #endif @@ -93,6 +93,21 @@ strlenspn(const char *s, size_t len, const char *accept) return len; } +static size_t +strlencspn(const char *s, size_t len, const char *accept) +{ + size_t i; + for (i = 0; i < len; ++i) { + /* likely we can do better by inlining this function + * but this works for now + */ + if (strchr(accept, s[i]) != NULL) { + return i; + } + } + return len; +} + /* * ASCII half-case-insenstive compare! * @@ -253,11 +268,6 @@ static void st_clear(stoken_t * st) st->val[0] = CHAR_NULL; } -static int st_is_empty(const stoken_t * st) -{ - return st->type == CHAR_NULL; -} - static void st_assign_char(stoken_t * st, const char stype, const char value) { st->type = stype; @@ -297,28 +307,11 @@ static int st_is_unary_op(const stoken_t * st) strcmp(st->val, "~"))); } -static int st_is_arith_op(const stoken_t * st) -{ - return (st->type == 'o' && !(strcmp(st->val, "-") && - strcmp(st->val, "+") && - strcmp(st->val, "~") && - strcmp(st->val, "!") && - strcmp(st->val, "/") && - strcmp(st->val, "%") && - strcmp(st->val, "*") && - strcmp(st->val, "|") && - strcmp(st->val, "&") && - /* arg1 = upper case only, arg1 = mixed case */ - cstrcasecmp("MOD", st->val) && - cstrcasecmp("DIV", st->val))); -} - /* Parsers * * */ - static size_t parse_white(sfilter * sf) { return sf->pos + 1; @@ -326,37 +319,33 @@ static size_t parse_white(sfilter * sf) static size_t parse_operator1(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; size_t pos = sf->pos; - st_assign_char(current, 'o', cs[pos]); + st_assign_char(sf->current, 'o', cs[pos]); return pos + 1; } static size_t parse_other(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; size_t pos = sf->pos; - st_assign_char(current, '?', cs[pos]); + st_assign_char(sf->current, '?', cs[pos]); return pos + 1; } static size_t parse_char(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; size_t pos = sf->pos; - st_assign_char(current, cs[pos], cs[pos]); + st_assign_char(sf->current, cs[pos], cs[pos]); return pos + 1; } static size_t parse_eol_comment(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -364,17 +353,16 @@ static size_t parse_eol_comment(sfilter * sf) const char *endpos = (const char *) memchr((const void *) (cs + pos), '\n', slen - pos); if (endpos == NULL) { - st_assign(current, 'c', cs + pos, slen - pos); + st_assign(sf->current, 'c', cs + pos, slen - pos); return slen; } else { - st_assign(current, 'c', cs + pos, endpos - cs - pos); + st_assign(sf->current, 'c', cs + pos, endpos - cs - pos); return (endpos - cs) + 1; } } static size_t parse_dash(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -384,7 +372,7 @@ static size_t parse_dash(sfilter * sf) if (pos1 < slen && cs[pos1] == '-') { return parse_eol_comment(sf); } else { - st_assign_char(current, 'o', '-'); + st_assign_char(sf->current, 'o', '-'); return pos1; } } @@ -431,7 +419,6 @@ static size_t is_mysql_comment(const char *cs, const size_t len, size_t pos) static size_t parse_slash(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -454,7 +441,7 @@ static size_t parse_slash(sfilter * sf) /* * unterminated comment */ - st_assign(current, 'c', cs + pos, slen - pos); + st_assign(sf->current, 'c', cs + pos, slen - pos); return slen; } else { /* @@ -468,7 +455,7 @@ static size_t parse_slash(sfilter * sf) if (memchr2(cur + 2, ptr - (cur + 1), '/', '*') != NULL) { ctype = 'X'; } - st_assign(current, ctype, cs + pos, clen); + st_assign(sf->current, ctype, cs + pos, clen); return pos + clen; } @@ -477,14 +464,13 @@ static size_t parse_slash(sfilter * sf) * MySQL Comment */ sf->in_comment = TRUE; - st_clear(current); + st_clear(sf->current); return pos + inc; } } static size_t parse_backslash(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -493,7 +479,7 @@ static size_t parse_backslash(sfilter * sf) * Weird MySQL alias for NULL, "\N" (capital N only) */ if (pos + 1 < slen && cs[pos + 1] == 'N') { - st_assign(current, '1', "NULL", 4); + st_assign(sf->current, '1', "NULL", 4); return pos + 2; } else { return parse_other(sf); @@ -510,7 +496,6 @@ static int is_operator2(const char *key) static size_t parse_operator2(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -532,25 +517,29 @@ static size_t parse_operator2(sfilter * sf) */ if (sf->in_comment && op2[0] == '*' && op2[1] == '/') { sf->in_comment = FALSE; - st_clear(current); + st_clear(sf->current); return pos + 2; } else if (pos + 2 < slen && op2[0] == '<' && op2[1] == '=' && cs[pos + 2] == '>') { /* * special 3-char operator */ - st_assign(current, 'o', "<=>", 3); + st_assign(sf->current, 'o', "<=>", 3); return pos + 3; } else if (is_operator2(op2)) { if (streq(op2, "&&") || streq(op2, "||")) { - st_assign(current, '&', op2, 2); + st_assign(sf->current, '&', op2, 2); } else { /* * normal 2 char operator */ - st_assign(current, 'o', op2, 2); + st_assign(sf->current, 'o', op2, 2); } return pos + 2; + } else if (op2[0] == ':') { + /* ':' is not an operator */ + st_assign_char(sf->current, ':', ':'); + return pos + 1; } else { /* * must be a single char operator @@ -614,7 +603,6 @@ static size_t parse_string_core(const char *cs, const size_t len, size_t pos, */ static size_t parse_string(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -622,34 +610,93 @@ static size_t parse_string(sfilter * sf) /* * assert cs[pos] == single or double quote */ - return parse_string_core(cs, slen, pos, current, cs[pos], 1); + return parse_string_core(cs, slen, pos, sf->current, cs[pos], 1); +} + +/** Parse MySQL `backtick` quoted strings + * + * Unforunately, the escaping rules for `-quoted strings is different + * when finding a "`" you need to look at NEXT CHAR to see if it's "`" + * If so, you need to jump two characters ahead + * + * In normal strings, you need to look at PREVIOUS CHAR... and if so + * just jump ahead one char. + * + * Also we don't need to code to fake an opening "`" + * + * Tried to keep code as similar to parse_string_core. + */ +static size_t parse_string_tick(sfilter *sf) +{ + const size_t offset = 1; + const char delim = '`'; + + const char *cs = sf->s; + const size_t len = sf->slen; + size_t pos = sf->pos; + stoken_t *st = sf->current; + + /* + * len -pos -1 : offset is to skip the perhaps first quote char + */ + const char *qpos = + (const char *) memchr((const void *) (cs + pos + offset), delim, + len - pos - offset); + + st->str_open = delim; + + while (TRUE) { + if (qpos == NULL) { + /* + * string ended with no trailing quote + * assign what we have + */ + st_assign(st, 's', cs + pos + offset, len - pos - offset); + st->str_close = CHAR_NULL; + return len; + } else if (qpos + 1 == (cs + len) || ((qpos + 1) < (cs + len) && *(qpos + 1) != delim)) { + /* + * ending quote is not escaped.. copy and end + */ + st_assign(st, 's', cs + pos + offset, + qpos - (cs + pos + offset)); + st->str_close = delim; + return qpos - cs + 1; + } else { + /* + * we got a `` so advance by 2 chars + */ + qpos = + (const char *) memchr((const void *) (qpos + 2), delim, + (cs + len) - (qpos + 2)); + } + } } static size_t parse_word(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; size_t pos = sf->pos; char *dot; char ch; size_t slen = - strlenspn(cs + pos, sf->slen - pos, - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$."); + strlencspn(cs + pos, sf->slen - pos, + " .`<>:\\?=@!#~+-*/&|^%(),';\r\n\t\"\013\014"); - st_assign(current, 'n', cs + pos, slen); + st_assign(sf->current, 'n', cs + pos, slen); - dot = strchr(current->val, '.'); + dot = strchr(sf->current->val, '.'); if (dot != NULL) { *dot = '\0'; - ch = is_keyword(current->val); + ch = is_keyword(sf->current->val); - if (ch == 'k' || ch == 'o') { + if (ch == 'k' || ch == 'o' || ch == 'E') { /* * we got something like "SELECT.1" */ - current->type = ch; - return pos + strlen(current->val); + sf->current->type = ch; + return pos + strlen(sf->current->val); } else { /* * something else, put back dot @@ -663,46 +710,103 @@ static size_t parse_word(sfilter * sf) */ if (slen < ST_MAX_SIZE) { - ch = is_keyword(current->val); + ch = is_keyword(sf->current->val); if (ch == CHAR_NULL) { ch = 'n'; } - current->type = ch; + sf->current->type = ch; } return pos + slen; } +/* MySQL backticks are a cross between string and + * and a bare word. + * + */ +static size_t parse_tick(sfilter* sf) +{ + /* first we pretend we are looking for a string */ + size_t slen = parse_string_tick(sf); + + /* we could check to see if start and end of + * of string are both "`", i.e. make sure we have + * matching set. `foo` vs. `foo + * but I don't think it matters much + */ + + + /* check value of string to see if it's a keyword, + * function, operator, etc + */ + char ch = is_keyword(sf->current->val); + if (ch == 'f') { + /* if it's a function, then convert token */ + sf->current->type = 'f'; + } else { + /* otherwise it's a 'n' type -- mysql treats + * everything as a bare word + */ + sf->current->type = 'n'; + } + return slen; +} + static size_t parse_var(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; - size_t pos = sf->pos; - size_t pos1 = pos + 1; + size_t pos = sf->pos + 1; size_t xlen; + /* + * var_count is only used to reconstruct + * the input. It counts the number of '@' + * seen 0 in the case of NULL, 1 or 2 + */ + /* * move past optional other '@' */ - if (pos1 < slen && cs[pos1] == '@') { - pos1 += 1; + if (pos < slen && cs[pos] == '@') { + pos += 1; + sf->current->var_count = 2; + } else { + sf->current->var_count = 1; } - xlen = strlenspn(cs + pos1, slen - pos1, - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$"); + /* + * MySQL allows @@`version` + */ + if (pos < slen) { + if (cs[pos] == '`') { + sf->pos = pos; + pos = parse_string_tick(sf); + sf->current->type = 'v'; + return pos; + } else if (cs[pos] == CHAR_SINGLE || cs[pos] == CHAR_DOUBLE) { + sf->pos = pos; + pos = parse_string(sf); + sf->current->type = 'v'; + return pos; + } + } + + + xlen = strlencspn(cs + pos, slen - pos, + " <>:\\?=@!#~+-*/&|^%(),';\r\n\t\"\013\014"); +// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$"); if (xlen == 0) { - st_assign(current, 'v', cs + pos, (pos1 - pos)); - return pos1; + st_assign(sf->current, 'v', cs + pos, 0); + return pos; } else { - st_assign(current, 'v', cs + pos, xlen + (pos1 - pos)); - return pos1 + xlen; + st_assign(sf->current, 'v', cs + pos, xlen); + return pos + xlen; } } static size_t parse_money(sfilter *sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -719,14 +823,13 @@ static size_t parse_money(sfilter *sf) */ return pos + 1; } else { - st_assign(current, '1', cs + pos, 1 + xlen); + st_assign(sf->current, '1', cs + pos, 1 + xlen); return pos + 1 + xlen; } } static size_t parse_number(sfilter * sf) { - stoken_t *current = &sf->syntax_current; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; @@ -740,10 +843,10 @@ static size_t parse_number(sfilter * sf) xlen = strlenspn(cs + pos + 2, slen - pos - 2, "0123456789ABCDEFabcdef"); if (xlen == 0) { - st_assign(current, 'n', "0X", 2); + st_assign(sf->current, 'n', "0X", 2); return pos + 2; } else { - st_assign(current, '1', cs + pos, 2 + xlen); + st_assign(sf->current, '1', cs + pos, 2 + xlen); return pos + 2 + xlen; } } @@ -758,7 +861,7 @@ static size_t parse_number(sfilter * sf) pos += 1; } if (pos - start == 1) { - st_assign_char(current, 'n', '.'); + st_assign_char(sf->current, 'n', '.'); return pos; } } @@ -779,24 +882,24 @@ static size_t parse_number(sfilter * sf) * the number part and leave the rest to be * parsed later */ - st_assign(current, '1', cs + start, pos - start); + st_assign(sf->current, '1', cs + start, pos - start); return pos; } } - st_assign(current, '1', cs + start, pos - start); + st_assign(sf->current, '1', cs + start, pos - start); return pos; } -int parse_token(sfilter * sf) +int libinjection_sqli_tokenize(sfilter * sf, stoken_t *current) { - stoken_t *current = &sf->syntax_current; const char *s = sf->s; const size_t slen = sf->slen; size_t *pos = &sf->pos; pt2Function fnptr; st_clear(current); + sf->current = current; /* * if we are at beginning of string @@ -812,17 +915,16 @@ int parse_token(sfilter * sf) /* * get current character */ - const int ch = (int) (s[*pos]); + const unsigned ch = (unsigned int) (s[*pos]); /* * if not ascii, then continue... * actually probably need to just assuming * it's a string */ - if (ch < 0 || ch > 127) { - *pos += 1; - continue; - } + if (ch > 127) { + fnptr = parse_word; + } else { /* * look up the parser, and call it @@ -831,6 +933,7 @@ int parse_token(sfilter * sf) * charparsers[ch]() */ fnptr = char_parse_map[ch]; + } *pos = (*fnptr) (sf); /* @@ -845,13 +948,14 @@ int parse_token(sfilter * sf) /** * Initializes parsing state - * TBD: explicity add parsing content (NULL, SINGLE, DOUBLE) + * */ -void sfilter_reset(sfilter * sf, const char *s, size_t len) +void libinjection_sqli_init(sfilter * sf, const char *s, size_t len, char delim) { memset(sf, 0, sizeof(sfilter)); sf->s = s; sf->slen = len; + sf->delim = delim; } /** See if two tokens can be merged since they are compound SQL phrases. @@ -880,7 +984,11 @@ static int syntax_merge_words(stoken_t * a, stoken_t * b) if (! (a->type == 'k' || a->type == 'n' || a->type == 'o' - || a->type == 'U')) { + || a->type == 'U' || a->type == 'E')) { + return FALSE; + } + + if (! st_is_multiword_start(a)) { return FALSE; } @@ -907,275 +1015,213 @@ static int syntax_merge_words(stoken_t * a, stoken_t * b) } } -/* This does some simple syntax cleanup based on the token - * - * - */ -int sqli_tokenize(sfilter * sf, stoken_t * sout) -{ - stoken_t *last = &sf->syntax_last; - stoken_t *current = &sf->syntax_current; - - while (parse_token(sf)) { - char ttype = current->type; - - /* - * TBD: hmm forgot logic here. - */ - if (ttype == 'c') { - st_copy(&sf->syntax_comment, current); - continue; - } - st_clear(&sf->syntax_comment); - - /* - * If we don't have a saved token, and we have - * a string: save it. if the next token is also a string - * then merge them. e.g. "A" "B" in SQL is actually "AB" - * a n/k/U/o type: save since next token my be merged together - * for example: "LEFT" + "JOIN" = "LEFT JOIN" - * a o/& type: TBD need to review. - * - */ - if (last->type == CHAR_NULL) { - switch (ttype) { - - /* - * items that have special needs - */ - case 's': - st_copy(last, current); - continue; - case 'n': - case 'k': - case 'U': - case '&': - case 'o': - if (st_is_multiword_start(current)) { - st_copy(last, current); - continue; - } else if (current->type == 'o' || current->type == '&') { - /* } else if (st_is_unary_op(current)) { */ - st_copy(last, current); - continue; - } else { - /* - * copy to out - */ - st_copy(sout, current); - return TRUE; - } - default: - /* - * copy to out - */ - st_copy(sout, current); - return TRUE; - } - } - /* - * We have a saved token - */ - - switch (ttype) { - case 's': - if (last->type == 's') { - /* - * "FOO" "BAR" == "FOO" (skip second string) - */ - continue; - } else { - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - case 'o': - /* - * first case to handle "IS" + "NOT" - */ - if (syntax_merge_words(last, current)) { - continue; - } else if (st_is_unary_op(current) - && (last->type == 'o' || last->type == '&' - || last->type == 'U')) { - /* - * if an operator is followed by a unary operator, skip it. - * 1, + ==> "+" is not unary, it's arithmetic - * AND, + ==> "+" is unary - */ - continue; - } else { - /* - * no match - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - case 'n': - case 'k': - if (syntax_merge_words(last, current)) { - continue; - } else { - /* - * total no match - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - default: - /* - * fix up for ambigous "IN" - * handle case where IN is typically a function - * but used in compound "IN BOOLEAN MODE" jive - * - * warning on cstrcasecmp arg0=upper case only, arg1 = mixed - */ - if (last->type == 'n' && !cstrcasecmp("IN", last->val)) { - st_copy(last, current); - st_assign(sout, 'f', "IN", 2); - return TRUE; - } else { - /* - * no match at all - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - } - } - - /* - * final cleanup - */ - if (last->type) { - st_copy(sout, last); - st_clear(last); - return TRUE; - } else if (sf->syntax_comment.type) { - /* - * TBD - */ - st_copy(sout, &sf->syntax_comment); - st_clear(&sf->syntax_comment); - return TRUE; - } else { - return FALSE; - } -} /* * My apologies, this code is a mess */ -int filter_fold(sfilter * sf, stoken_t * sout) +int filter_fold(sfilter * sf) { - stoken_t *last = &sf->fold_last; - stoken_t *current = &sf->fold_current; + stoken_t last_comment; - if (sf->fold_state == 4 && !st_is_empty(last)) { - st_copy(sout, last); - sf->fold_state = 2; - st_clear(last); - return FALSE; - } + stoken_t * current; - while (sqli_tokenize(sf, current)) { - /* - * 0 = start of statement - * skip ( and unary ops - */ - if (sf->fold_state == 0) { - if (current->type == '(') { - continue; - } - if (st_is_unary_op(current)) { - continue; - } - sf->fold_state = 1; - } + /* POS is the positive of where the NEXT token goes */ + size_t pos = 0; - if (st_is_empty(last)) { - FOLD_DEBUG; - if (current->type == '1' || current->type == 'n' - || current->type == '(') { - sf->fold_state = 2; - st_copy(last, current); - } - st_copy(sout, current); - return FALSE; - } else if (last->type == '(' && st_is_unary_op(current)) { - /* - * similar to beginning of statement - * an opening '(' resets state, and we should skip all - * unary operators - */ - continue; - } else if (last->type == '(' && current->type == '(') { - /* if we get another '(' after another - * emit 1, but keep state - */ - st_copy(sout, current); - return FALSE; - } else if ((last->type == '1' || last->type == 'n') - && st_is_arith_op(current)) { - FOLD_DEBUG; - st_copy(last, current); - } else if (last->type == 'o' - && (current->type == '1' || current->type == 'n')) { - FOLD_DEBUG; - st_copy(last, current); - } else { - if (sf->fold_state == 2) { - if (last->type != '1' && last->type != '(' - && last->type != 'n') { - FOLD_DEBUG; - st_copy(sout, last); - st_copy(last, current); - sf->fold_state = 4; - } else { - FOLD_DEBUG; - st_copy(sout, current); - st_clear(last); - } - return FALSE; - } else { - if (last->type == 'o') { - st_copy(sout, last); - st_copy(last, current); - sf->fold_state = 4; - } else { - sf->fold_state = 2; - st_copy(sout, current); - st_clear(last); - } - return FALSE; - } - } - } + /* LEFT is a count of how many tokens that are already + folded or processed (i.e. part of the fingerprint) */ + size_t left = 0; - if (!st_is_empty(last)) { - if (st_is_arith_op(last)) { - st_copy(sout, last); - st_clear(last); - return FALSE; - } else { - st_clear(last); - } - } + int more = 1; - /* - * all done: nothing more to parse + st_clear(&last_comment); + + /* Skip all initial comments, right-parens ( and unary operators + * */ - return TRUE; + current = &(sf->tokenvec[0]); + while (more) { + more = libinjection_sqli_tokenize(sf, current); + if ( ! (current->type == 'c' || current->type == '(' || st_is_unary_op(current))) { + break; + } + } + + if (! more) { + /* If input was only comments, unary or (, then exit */ + return 0; + } else { + /* it's some other token */ + pos += 1; + } + + while (1) { + FOLD_DEBUG + /* get up to two tokens */ + while (more && pos <= MAX_TOKENS && (pos - left) < 2) { + current = &(sf->tokenvec[pos]); + more = libinjection_sqli_tokenize(sf, current); + if (more) { + if (current->type == 'c') { + st_copy(&last_comment, current); + } else { + last_comment.type = CHAR_NULL; + pos += 1; + } + } + } + FOLD_DEBUG + /* did we get 2 tokens? if not then we are done */ + if (pos - left != 2) { + left = pos; + break; + } + + /* FOLD: "ss" -> "s" + * "foo" "bar" is valid SQL + * just ignore second string + */ + if (sf->tokenvec[left].type == 's' && sf->tokenvec[left+1].type == 's') { + pos -= 1; + continue; + } else if (sf->tokenvec[left].type =='o' && st_is_unary_op(&sf->tokenvec[left+1])) { + pos -= 1; + if (left > 0) { + left -= 1; + } + continue; + } else if (sf->tokenvec[left].type =='(' && st_is_unary_op(&sf->tokenvec[left+1])) { + pos -= 1; + if (left > 0) { + left -= 1; + } + continue; + } else if (syntax_merge_words(&sf->tokenvec[left], &sf->tokenvec[left+1])) { + pos -= 1; + continue; + } else if (sf->tokenvec[left].type == 'n' && + sf->tokenvec[left+1].type == '(' && ( + cstrcasecmp("IN", sf->tokenvec[left].val) == 0 || + cstrcasecmp("DATABASE", sf->tokenvec[left].val) == 0 || + cstrcasecmp("USER", sf->tokenvec[left].val) == 0 || + cstrcasecmp("PASSWORD", sf->tokenvec[left].val) == 0 + ) + ) { + + // pos is the same + // other conversions need to go here... for instance + // password CAN be a function, coalese CAN be a function + sf->tokenvec[left].type = 'f'; + continue; +#if 0 + } else if (sf->tokenvec[left].type == 'o' && cstrcasecmp("LIKE", sf->tokenvec[left].val) == 0 + && sf->tokenvec[left+1].type == '(') { + // two use cases "foo" LIKE "BAR" (normal operator) + // "foo" = LIKE(1,2) + sf->tokenvec[left].type = 'f'; + continue; +#endif + } + + /* all cases of handing 2 tokens is done + and nothing matched. Get one more token + */ + FOLD_DEBUG + while (more && pos <= MAX_TOKENS && pos - left < 3) { + current = &(sf->tokenvec[pos]); + more = libinjection_sqli_tokenize(sf, current); + if (more) { + if (current->type == 'c') { + st_copy(&last_comment, current); + } else { + last_comment.type = CHAR_NULL; + pos += 1; + } + } + } + + /* do we have three tokens? If not then we are done */ + if (pos -left != 3) { + left = pos; + break; + } + + /* + * now look for three token folding + */ + if (sf->tokenvec[left].type == '1' && + sf->tokenvec[left+1].type == 'o' && + sf->tokenvec[left+2].type == '1') { + pos -= 2; + continue; + } else if (sf->tokenvec[left].type == 'o' && + sf->tokenvec[left+1].type != '(' && + sf->tokenvec[left+2].type == 'o') { + if (left > 0) { + left -= 1; + } + pos -= 2; + continue; + } else if (sf->tokenvec[left].type == '&' && + sf->tokenvec[left+2].type == '&') { + pos -= 2; + continue; + } else if ((sf->tokenvec[left].type == 'n' || sf->tokenvec[left].type == '1' ) && + sf->tokenvec[left+1].type == 'o' && + (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n')) { + pos -= 2; + continue; +#if 0 + } else if ((sf->tokenvec[left].type == 'n' || sf->tokenvec[left].type == '1') && + sf->tokenvec[left+1].type == ',' && + (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n')) { + pos -= 2; + continue; +#endif + } else if ((sf->tokenvec[left].type == 'k' || sf->tokenvec[left].type == 'E') && + st_is_unary_op(&sf->tokenvec[left+1]) && + (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n' || sf->tokenvec[left+2].type == 'v' || sf->tokenvec[left+2].type == 's' || sf->tokenvec[left+2].type == 'f' )) { + // remove unary operators + // select - 1 + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + pos -= 1; + } else if (sf->tokenvec[left].type == 'n' && + sf->tokenvec[left+1].type == 'n' && sf->tokenvec[left+1].val[0] == '.' && + sf->tokenvec[left+2].type == 'n') { + /* ignore the '.n' + * typically is this dabasename.table + */ + pos -= 2; + continue; + } + + + /* no folding -- assume left-most token is + is good, now use the existing 2 tokens -- + do not get another + */ + + left += 1; + + } /* while(1) */ + + /* if we have 4 or less tokens, and we had a comment token + * at the end, add it back + */ + + if (left < MAX_TOKENS && last_comment.type == 'c') { + st_copy(&sf->tokenvec[left], &last_comment); + left += 1; + } + + /* sometimes we grab a 6th token to help + determine the type of token 5. + */ + if (left > MAX_TOKENS) { + left = MAX_TOKENS; + } + + return (int)left; } /* secondary api: detects SQLi in a string, GIVEN a context. @@ -1193,22 +1239,16 @@ int libinjection_is_string_sqli(sfilter * sql_state, const char delim, ptr_fingerprints_fn fn, void* callbackarg) { + int i; int tlen = 0; char ch; int patmatch; - int all_done; - sfilter_reset(sql_state, s, slen); - sql_state->delim = delim; + libinjection_sqli_init(sql_state, s, slen, delim); - while (tlen < MAX_TOKENS) { - all_done = filter_fold(sql_state, &(sql_state->tokenvec[tlen])); - if (all_done) { - break; - } - - sql_state->pat[tlen] = sql_state->tokenvec[tlen].type; - tlen += 1; + tlen = filter_fold(sql_state); + for (i = 0; i < tlen; ++i) { + sql_state->pat[i] = sql_state->tokenvec[i].type; } /* @@ -1350,7 +1390,8 @@ int libinjection_is_string_sqli(sfilter * sql_state, if (streq(sql_state->pat, "sos") || streq(sql_state->pat, "s&s")) { if ((sql_state->tokenvec[0].str_open == CHAR_NULL) - && (sql_state->tokenvec[2].str_close == CHAR_NULL)) { + && (sql_state->tokenvec[2].str_close == CHAR_NULL) + && (sql_state->tokenvec[0].str_close == sql_state->tokenvec[2].str_open)) { /* * if ....foo" + "bar.... */ @@ -1362,25 +1403,21 @@ int libinjection_is_string_sqli(sfilter * sql_state, sql_state->reason = __LINE__; return FALSE; } - break; - } - } /* case 3 */ - case 5: { - if (streq(sql_state->pat, "sosos")) { - if (sql_state->tokenvec[0].str_open == CHAR_NULL) { - /* - * if ....foo" + "bar.... - */ - return TRUE; - } else { - /* - * not sqli - */ + } else if (streq(sql_state->pat, "so1")) { + if (sql_state->tokenvec[0].str_open != CHAR_NULL) { + /* "foo" -1 is ok, foo"-1 is not */ sql_state->reason = __LINE__; return FALSE; } - break; + } else if ((sql_state->tokenvec[1].type == 'k') && cstrcasecmp("INTO OUTFILE", sql_state->tokenvec[1].val)) { + sql_state->reason = __LINE__; + return FALSE; } + break; + } /* case 3 */ + case 5: { + /* nothing right now */ + break; } /* case 5 */ } /* end switch */ diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h index bd0abd2b..1fcea59b 100644 --- a/apache2/libinjection/libinjection_sqli_data.h +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -23,6 +23,7 @@ static size_t parse_string(sfilter *sf); static size_t parse_word(sfilter * sf); static size_t parse_var(sfilter * sf); static size_t parse_number(sfilter * sf); +static size_t parse_tick(sfilter * sf); static const char* operators2[] = { @@ -84,7 +85,7 @@ static const keyword_t sql_keywords[] = { {"ARRAY_TO_JSON", 'f'}, {"ARRAY_TO_STRING", 'f'}, {"ARRAY_UPPER", 'f'}, - {"AS", 'k'}, + {"AS", 'n'}, {"ASC", 'k'}, {"ASCII", 'f'}, {"ASENSITIVE", 'k'}, @@ -96,7 +97,7 @@ static const keyword_t sql_keywords[] = { {"AUTOINCREMENT", 'k'}, {"AVG", 'f'}, {"BEFORE", 'k'}, - {"BEGIN", 'k'}, + {"BEGIN", 'E'}, {"BENCHMARK", 'f'}, {"BETWEEN", 'k'}, {"BIGINT", 'k'}, @@ -121,7 +122,7 @@ static const keyword_t sql_keywords[] = { {"BY", 'n'}, {"CALL", 'k'}, {"CASCADE", 'k'}, - {"CASE", 'o'}, + {"CASE", 'E'}, {"CAST", 'f'}, {"CBOOL", 'f'}, {"CBRT", 'f'}, @@ -179,7 +180,7 @@ static const keyword_t sql_keywords[] = { {"COUNT", 'f'}, {"COUNT_BIG", 'k'}, {"CRC32", 'f'}, - {"CREATE", 'k'}, + {"CREATE", 'E'}, {"CROSS", 'n'}, {"CSNG", 'f'}, {"CTXSYS.DRITHSX.SN", 'f'}, @@ -201,7 +202,7 @@ static const keyword_t sql_keywords[] = { {"CURSOR_STATUS", 'f'}, {"CURTIME", 'f'}, {"CVAR", 'f'}, - {"DATABASE", 'k'}, + {"DATABASE", 'n'}, {"DATABASEPROPERTYEX", 'f'}, {"DATABASES", 'k'}, {"DATABASE_PRINCIPAL_ID", 'f'}, @@ -232,13 +233,14 @@ static const keyword_t sql_keywords[] = { {"DAY_MICROSECOND", 'k'}, {"DAY_MINUTE", 'k'}, {"DAY_SECOND", 'k'}, + {"DBMS_LOCK.SLEEP", 'f'}, {"DBMS_PIPE.RECEIVE_MESSAGE", 'f'}, {"DB_ID", 'f'}, {"DB_NAME", 'f'}, {"DCOUNT", 'f'}, {"DEC", 'k'}, {"DECIMAL", 'k'}, - {"DECLARE", 'k'}, + {"DECLARE", 'E'}, {"DECODE", 'f'}, {"DECRYPTBYASMKEY", 'f'}, {"DECRYPTBYCERT", 'f'}, @@ -265,7 +267,7 @@ static const keyword_t sql_keywords[] = { {"DLOOKUP", 'f'}, {"DMAX", 'f'}, {"DMIN", 'f'}, - {"DROP", 'k'}, + {"DROP", 'E'}, {"DSUM", 'f'}, {"DUAL", 'k'}, {"EACH", 'k'}, @@ -285,7 +287,7 @@ static const keyword_t sql_keywords[] = { {"EOMONTH", 'f'}, {"ESCAPED", 'k'}, {"EVENTDATA", 'f'}, - {"EXEC", 'k'}, + {"EXEC", 'E'}, {"EXECUTE", 'k'}, {"EXISTS", 'k'}, {"EXIT", 'k'}, @@ -352,7 +354,7 @@ static const keyword_t sql_keywords[] = { {"IDENT_CURRENT", 'f'}, {"IDENT_INCR", 'f'}, {"IDENT_SEED", 'f'}, - {"IF", 'k'}, + {"IF", 'E'}, {"IFF", 'f'}, {"IFNULL", 'f'}, {"IGNORE", 'k'}, @@ -369,7 +371,7 @@ static const keyword_t sql_keywords[] = { {"INNER", 'k'}, {"INOUT", 'k'}, {"INSENSITIVE", 'k'}, - {"INSERT", 'k'}, + {"INSERT", 'E'}, {"INSTR", 'f'}, {"INSTRREV", 'f'}, {"INT", 'k'}, @@ -476,7 +478,7 @@ static const keyword_t sql_keywords[] = { {"NO_WRITE_TO_BINLOG", 'k'}, {"NTH_VALUE", 'f'}, {"NTILE", 'f'}, - {"NULL", '1'}, + {"NULL", 'v'}, {"NULLIF", 'f'}, {"NUMERIC", 'k'}, {"NZ", 'f'}, @@ -512,7 +514,7 @@ static const keyword_t sql_keywords[] = { {"OWN3D", 'k'}, {"PARSENAME", 'f'}, {"PARTITION", 'k'}, - {"PASSWORD", 'k'}, + {"PASSWORD", 'n'}, {"PATHINDEX", 'f'}, {"PATINDEX", 'f'}, {"PERCENTILE_COUNT", 'f'}, @@ -607,11 +609,11 @@ static const keyword_t sql_keywords[] = { {"SCOPE_IDENTITY", 'f'}, {"SECOND_MICROSECOND", 'k'}, {"SEC_TO_TIME", 'f'}, - {"SELECT", 'k'}, + {"SELECT", 'E'}, {"SENSITIVE", 'k'}, {"SEPARATOR", 'k'}, {"SESSION_USER", 'f'}, - {"SET", 'k'}, + {"SET", 'E'}, {"SETATTR", 'f'}, {"SETSEED", 'f'}, {"SETVAL", 'f'}, @@ -623,7 +625,7 @@ static const keyword_t sql_keywords[] = { {"SHA1", 'f'}, {"SHA2", 'f'}, {"SHOW", 'n'}, - {"SHUTDOWN", 'k'}, + {"SHUTDOWN", 'E'}, {"SIGN", 'f'}, {"SIGNAL", 'k'}, {"SIGNBYASMKEY", 'f'}, @@ -690,6 +692,7 @@ static const keyword_t sql_keywords[] = { {"TAN", 'f'}, {"TERMINATED", 'k'}, {"TERTIARY_WEIGHTS", 'f'}, + {"TEXTPOS", 'f'}, {"TEXTPTR", 'f'}, {"TEXTVALID", 'f'}, {"THEN", 'k'}, @@ -748,14 +751,15 @@ static const keyword_t sql_keywords[] = { {"UNLOCK", 'k'}, {"UNNEST", 'f'}, {"UNSIGNED", 'k'}, - {"UPDATE", 'k'}, + {"UPDATE", 'E'}, {"UPDATEXML", 'f'}, {"UPPER", 'f'}, {"UPPER_INC", 'f'}, {"UPPER_INF", 'f'}, {"USAGE", 'k'}, - {"USE", 'k'}, + {"USE", 'E'}, {"USER_ID", 'n'}, + {"USER_LOCK.SLEEP", 'f'}, {"USER_NAME", 'f'}, {"USING", 'f'}, {"UTC_DATE", 'k'}, @@ -777,14 +781,14 @@ static const keyword_t sql_keywords[] = { {"VERIFYSIGNEDBYASMKEY", 'f'}, {"VERIFYSIGNEDBYCERT", 'f'}, {"VERSION", 'f'}, - {"WAITFOR", 'k'}, + {"WAITFOR", 'n'}, {"WEEK", 'f'}, {"WEEKDAY", 'f'}, {"WEEKDAYNAME", 'f'}, {"WEEKOFYEAR", 'f'}, {"WHEN", 'k'}, {"WHERE", 'k'}, - {"WHILE", 'k'}, + {"WHILE", 'E'}, {"WIDTH_BUCKET", 'f'}, {"WITH", 'k'}, {"XMLAGG", 'f'}, @@ -808,17 +812,20 @@ static const keyword_t sql_keywords[] = { {"ZEROBLOB", 'f'}, {"ZEROFILL", 'k'}, }; -static const size_t sql_keywords_sz = 752; +static const size_t sql_keywords_sz = 755; static const char* multikeywords_start[] = { "ALTER", "AT", "AT TIME", + "CREATE", + "CREATE OR", "CROSS", "FULL", "GROUP", "IN", "IN BOOLEAN", "INTERSECT", + "INTO", "IS", "IS DISTINCT", "IS NOT", @@ -837,19 +844,22 @@ static const char* multikeywords_start[] = { "SIMILAR", "SOUNDS", "UNION", + "WAITFOR", }; -static const size_t multikeywords_start_sz = 27; +static const size_t multikeywords_start_sz = 31; static const keyword_t multikeywords[] = { {"ALTER DOMAIN", 'k'}, {"ALTER TABLE", 'k'}, {"AT TIME", 'n'}, {"AT TIME ZONE", 'k'}, + {"CREATE OR REPLACE", 'E'}, {"CROSS JOIN", 'k'}, {"FULL OUTER", 'k'}, {"GROUP BY", 'B'}, {"IN BOOLEAN", 'n'}, {"IN BOOLEAN MODE", 'k'}, {"INTERSECT ALL", 'o'}, + {"INTO OUTFILE", 'k'}, {"IS DISTINCT", 'n'}, {"IS DISTINCT FROM", 'k'}, {"IS NOT", 'o'}, @@ -879,12 +889,15 @@ static const keyword_t multikeywords[] = { {"READ WRITE", 'k'}, {"RIGHT JOIN", 'k'}, {"RIGHT OUTER", 'k'}, - {"SELECT ALL", 'k'}, + {"SELECT ALL", 'E'}, {"SIMILAR TO", 'o'}, {"SOUNDS LIKE", 'o'}, {"UNION ALL", 'U'}, + {"WAITFOR DELAY", 'E'}, + {"WAITFOR RECEIVE", 'E'}, + {"WAITFOR TIME", 'E'}, }; -static const size_t multikeywords_sz = 43; +static const size_t multikeywords_sz = 48; typedef size_t (*pt2Function)(sfilter *sf); static const pt2Function char_parse_map[] = { @@ -946,7 +959,7 @@ static const pt2Function char_parse_map[] = { &parse_number, /* 55 */ &parse_number, /* 56 */ &parse_number, /* 57 */ - &parse_char, /* 58 */ + &parse_operator2, /* 58 */ &parse_char, /* 59 */ &parse_operator2, /* 60 */ &parse_operator2, /* 61 */ @@ -984,7 +997,7 @@ static const pt2Function char_parse_map[] = { &parse_other, /* 93 */ &parse_operator1, /* 94 */ &parse_word, /* 95 */ - &parse_word, /* 96 */ + &parse_tick, /* 96 */ &parse_word, /* 97 */ &parse_word, /* 98 */ &parse_word, /* 99 */ @@ -1019,35 +1032,86 @@ static const pt2Function char_parse_map[] = { }; static const char* sql_fingerprints[] = { - "&1o1U", - "&1osU", - "&1ovU", + "&1UE1", + "&1UEf", + "&1UEs", + "&1UEv", + "&1of(", + "&1os1", + "&1osf", + "&1oso", + "&1osv", + "&1ovf", + "&1ovo", + "&1ovs", + "&f(((", + "&f(()", + "&f((1", + "&f((f", + "&f((s", + "&f((v", + "&f())", "&f()o", "&f(1)", "&f(1o", + "&f(f(", "&f(s)", + "&f(so", "&f(v)", "&f(vo", - "&so1U", - "&sosU", - "&sovU", - "&vo1U", - "&vosU", - "&vovU", + "&sUE1", + "&sUEf", + "&sUEs", + "&sUEv", + "&so1f", + "&so1o", + "&so1s", + "&so1v", + "&sof(", + "&son1", + "&sonf", + "&sos1", + "&sosf", + "&soso", + "&sosv", + "&sovf", + "&sovo", + "&sovs", + "&vUE1", + "&vUEf", + "&vUEs", + "&vUEv", + "&vo1f", + "&vo1o", + "&vo1s", + "&vo1v", + "&vof(", + "&von1", + "&vonf", + "&vos1", + "&vosf", + "&voso", + "&vosv", + "&vovf", + "&vovo", + "&vovs", + "1&(((", + "1&((1", + "1&((E", "1&((f", - "1&((k", + "1&((s", + "1&((v", "1&(1)", "1&(1,", "1&(1o", + "1&(E1", + "1&(Ef", + "1&(Ek", + "1&(En", + "1&(Eo", + "1&(Es", + "1&(Ev", "1&(f(", - "1&(k(", - "1&(k1", - "1&(kf", - "1&(kk", - "1&(kn", - "1&(ko", - "1&(ks", - "1&(kv", "1&(s)", "1&(s,", "1&(so", @@ -1055,142 +1119,261 @@ static const char* sql_fingerprints[] = { "1&(v,", "1&(vo", "1&1", + "1&1&(", + "1&1&1", + "1&1&f", + "1&1&n", + "1&1&s", + "1&1&v", + "1&1B1", "1&1Bf", - "1&1Uk", + "1&1Bs", + "1&1Bv", + "1&1En", + "1&1U", + "1&1U(", + "1&1UE", + "1&1Uc", "1&1c", "1&1f(", + "1&1k1", + "1&1kf", + "1&1ks", + "1&1kv", "1&1o(", - "1&1o1", + "1&1oE", "1&1of", - "1&1ok", - "1&1on", "1&1oo", "1&1os", "1&1ov", + "1&1so", + "1&1vo", + "1&E((", + "1&E(1", + "1&E(f", + "1&E(o", + "1&E(s", + "1&E(v", + "1&E1k", + "1&E1o", + "1&Ef(", + "1&Ek1", + "1&Ekf", + "1&Eks", + "1&Ekv", + "1&Esk", + "1&Eso", + "1&Evk", + "1&Evo", "1&f((", "1&f()", "1&f(1", "1&f(f", - "1&f(k", "1&f(n", "1&f(s", "1&f(v", - "1&k(1", - "1&k(f", - "1&k(s", - "1&k(v", - "1&k1k", - "1&kUk", - "1&kk1", - "1&kks", - "1&kkv", - "1&ksk", - "1&kvk", - "1&n()", - "1&no1", + "1&k&1", + "1&k&f", + "1&k&s", + "1&k&v", + "1&k1o", + "1&kf(", + "1&knk", + "1&ko(", + "1&ko1", + "1&kof", + "1&kok", + "1&kon", + "1&kos", + "1&kov", + "1&kso", + "1&kvo", + "1&n&1", + "1&n&f", + "1&n&n", + "1&n&s", + "1&n&v", + "1&nc", + "1&nk1", + "1&nkf", + "1&nks", + "1&nkv", + "1&nof", "1&nos", "1&nov", + "1&o((", "1&o(1", + "1&o(f", "1&o(s", "1&o(v", + "1&o1", + "1&o1c", "1&o1o", + "1&of(", + "1&oko", + "1&os", + "1&osc", "1&oso", + "1&ov", + "1&ovc", "1&ovo", + "1&s", + "1&s&(", + "1&s&1", + "1&s&f", + "1&s&n", + "1&s&s", + "1&s&v", + "1&s1o", + "1&sB1", "1&sBf", + "1&sBs", + "1&sBv", + "1&sEn", + "1&sU", "1&sU(", - "1&sUk", + "1&sUE", + "1&sUc", + "1&sc", "1&sf(", + "1&sk1", + "1&skf", + "1&sks", + "1&skv", "1&so(", "1&so1", + "1&soE", "1&sof", - "1&sok", "1&son", "1&soo", "1&sos", "1&sov", + "1&svo", "1&v", + "1&v&(", + "1&v&1", + "1&v&f", + "1&v&n", + "1&v&s", + "1&v&v", + "1&vB1", "1&vBf", + "1&vBs", + "1&vBv", + "1&vEn", + "1&vU", "1&vU(", - "1&vUk", + "1&vUE", + "1&vUc", "1&vc", "1&vf(", + "1&vk1", + "1&vkf", + "1&vks", + "1&vkv", "1&vo(", "1&vo1", + "1&voE", "1&vof", - "1&vok", "1&von", "1&voo", "1&vos", "1&vov", + "1&vso", + "1((((", + "1(((E", + "1(((U", + "1((En", + "1((U(", + "1(Enk", + "1(U((", + "1(U(E", + "1)&((", "1)&(1", + "1)&(E", "1)&(f", - "1)&(k", - "1)&(n", "1)&(s", "1)&(v", + "1)&1", + "1)&1&", "1)&1B", "1)&1U", + "1)&1c", "1)&1f", "1)&1o", "1)&f(", "1)&o(", + "1)&s", + "1)&s&", "1)&sB", "1)&sU", + "1)&sc", "1)&sf", "1)&so", + "1)&v", + "1)&v&", "1)&vB", "1)&vU", + "1)&vc", "1)&vf", "1)&vo", - "1)()s", - "1)()v", "1))&(", "1))&1", "1))&f", + "1))&n", "1))&o", "1))&s", "1))&v", "1)))&", "1))))", + "1))),", "1)));", "1)))B", + "1)))E", "1)))U", - "1)))c", "1)))k", "1)))o", - "1));c", - "1));k", + "1)),(", + "1));E", "1))B1", + "1))Bf", "1))Bs", "1))Bv", - "1))Uk", - "1))Un", - "1))c", + "1))E1", + "1))Ef", + "1))Es", + "1))Ev", + "1))U(", + "1))UE", "1))k1", - "1))kk", + "1))kf", + "1))kn", "1))ks", "1))kv", "1))o(", "1))o1", + "1))oE", "1))of", - "1))ok", "1))on", "1))os", "1))ov", + "1),((", "1),(1", + "1),(f", "1),(s", "1),(v", - "1);c", - "1);k&", - "1);k(", - "1);kf", - "1);kk", - "1);kn", - "1);ko", + "1);E&", + "1);E(", + "1);E1", + "1);Ef", + "1);Eo", + "1);Es", + "1);Ev", "1)B1", "1)B1&", "1)B1c", "1)B1o", + "1)Bf(", "1)Bs", "1)Bs&", "1)Bsc", @@ -1199,598 +1382,1544 @@ static const char* sql_fingerprints[] = { "1)Bv&", "1)Bvc", "1)Bvo", - "1)U(k", - "1)Uk(", - "1)Uk1", - "1)Ukf", - "1)Ukk", - "1)Ukn", - "1)Uko", - "1)Uks", - "1)Ukv", - "1)Unk", - "1)c", - "1)k1", - "1)k1c", + "1)E1c", + "1)E1o", + "1)Ef(", + "1)Esc", + "1)Eso", + "1)Evc", + "1)Evo", + "1)U((", + "1)U(E", + "1)UE(", + "1)UE1", + "1)UEf", + "1)UEk", + "1)UEn", + "1)UEs", + "1)UEv", + "1)k1&", + "1)k1;", + "1)k1B", + "1)k1E", + "1)k1U", "1)k1o", - "1)kks", - "1)kkv", + "1)kf(", "1)knk", - "1)ks", - "1)ksc", + "1)ks&", + "1)ks;", + "1)ksB", + "1)ksE", + "1)ksU", "1)kso", - "1)kv", - "1)kvc", + "1)kv&", + "1)kv;", + "1)kvB", + "1)kvE", + "1)kvU", "1)kvo", - "1)o(1", - "1)o(k", + "1)o((", "1)o(n", - "1)o(s", - "1)o(v", + "1)o1", "1)o1)", - "1)o1B", "1)o1U", - "1)o1f", - "1)o1k", + "1)o1c", "1)o1o", + "1)oE(", "1)of(", - "1)ok(", - "1)ok1", - "1)oks", - "1)okv", + "1)on", "1)on&", + "1)onc", + "1)os", "1)os)", - "1)osB", "1)osU", - "1)osf", - "1)osk", + "1)osc", "1)oso", + "1)ov", "1)ov)", - "1)ovB", "1)ovU", - "1)ovf", - "1)ovk", + "1)ovc", "1)ovo", + "1,(((", + "1,((E", + "1,((f", + "1,(E(", + "1,(E1", + "1,(Ef", + "1,(Es", + "1,(Ev", "1,(f(", - "1,(k(", - "1,(k1", - "1,(kf", - "1,(ks", - "1,(kv", + "1,1))", "1,1),", "1,1)o", "1,1B1", + "1,1Bf", "1,1Bs", "1,1Bv", - "1,1Uk", + "1,1UE", + "1,1of", + "1,1os", + "1,1ov", + "1,f((", "1,f(1", + "1,f(f", "1,f(s", "1,f(v", + "1,s))", "1,s),", "1,s)o", "1,sB1", + "1,sBf", "1,sBs", "1,sBv", - "1,sUk", + "1,sUE", + "1,so1", + "1,sof", + "1,son", + "1,sos", + "1,sov", + "1,v))", "1,v),", "1,v)o", "1,vB1", + "1,vBf", "1,vBs", "1,vBv", - "1,vUk", - "1;c", - "1;k&k", - "1;k((", - "1;k(1", - "1;k(o", - "1;k(s", - "1;k(v", - "1;k1,", - "1;kf(", - "1;kks", - "1;kkv", - "1;kn(", - "1;kn,", - "1;knc", - "1;ko(", - "1;kok", - "1;ks,", - "1;kv,", + "1,vUE", + "1,vo1", + "1,vof", + "1,von", + "1,vos", + "1,vov", + "1:n:1", + "1:n:f", + "1:n:s", + "1:n:v", + "1;E&k", + "1;E((", + "1;E(1", + "1;E(E", + "1;E(f", + "1;E(s", + "1;E(v", + "1;E1,", + "1;E1;", + "1;E1E", + "1;E1c", + "1;E1o", + "1;E;", + "1;E;c", + "1;EEn", + "1;Ef(", + "1;En,", + "1;EnE", + "1;Enc", + "1;Enk", + "1;Eo(", + "1;Es,", + "1;Es;", + "1;EsE", + "1;Esc", + "1;Eso", + "1;Ev,", + "1;Ev;", + "1;EvE", + "1;Evc", + "1;Evo", + "1;n:k", "1B1", + "1B1&1", + "1B1&f", + "1B1&s", + "1B1&v", "1B1,1", + "1B1,f", "1B1,n", "1B1,s", "1B1,v", - "1B1Uk", + "1B1UE", "1B1c", "1B1k1", + "1B1kf", "1B1ks", "1B1kv", + "1B1of", + "1B1os", + "1B1ov", + "1BE((", + "1BE(1", + "1BE(f", + "1BE(s", + "1BE(v", + "1Bf((", "1Bf(1", "1Bf(f", "1Bf(s", "1Bf(v", - "1Bk(1", - "1Bk(s", - "1Bk(v", "1Bn,n", "1Bnk1", + "1Bnkf", "1Bnks", "1Bnkv", "1Bs", + "1Bs&1", + "1Bs&f", + "1Bs&s", + "1Bs&v", "1Bs,1", + "1Bs,f", "1Bs,n", "1Bs,s", "1Bs,v", - "1BsUk", + "1BsUE", "1Bsc", "1Bsk1", + "1Bskf", "1Bsks", "1Bskv", + "1Bso1", + "1Bsof", + "1Bson", + "1Bsos", + "1Bsov", "1Bv", + "1Bv&1", + "1Bv&f", + "1Bv&s", + "1Bv&v", "1Bv,1", + "1Bv,f", "1Bv,n", "1Bv,s", "1Bv,v", - "1BvUk", + "1BvUE", "1Bvc", "1Bvk1", + "1Bvkf", "1Bvks", "1Bvkv", + "1Bvo1", + "1Bvof", + "1Bvon", + "1Bvos", + "1Bvov", + "1E1c", + "1E1of", + "1E1os", + "1E1ov", + "1EU1,", + "1EU1o", + "1EUEf", + "1EUf(", + "1EUs,", + "1EUso", + "1EUv,", + "1EUvo", + "1Ef((", + "1Ef(1", + "1Ef(f", + "1Ef(s", + "1Ef(v", + "1EnEn", + "1Eokn", + "1Esc", + "1Eso1", + "1Esof", + "1Eson", + "1Esos", + "1Esov", + "1Evc", + "1Evo1", + "1Evof", + "1Evon", + "1Evos", + "1Evov", "1U", - "1U((k", - "1U(k1", - "1U(kf", - "1U(kn", - "1U(ks", - "1U(kv", + "1U(((", + "1U((E", + "1U(E(", + "1U(E1", + "1U(Ef", + "1U(En", + "1U(Es", + "1U(Ev", "1U1,1", + "1U1,f", "1U1,s", "1U1,v", + "1U1of", + "1U1os", + "1U1ov", + "1UE", + "1UE((", + "1UE(1", + "1UE(E", + "1UE(f", + "1UE(s", + "1UE(v", + "1UE1", + "1UE1&", + "1UE1,", + "1UE1c", + "1UE1f", + "1UE1k", + "1UE1n", + "1UE1o", + "1UEc", + "1UEf", + "1UEf(", + "1UEf,", + "1UEfc", + "1UEk1", + "1UEkf", + "1UEkn", + "1UEks", + "1UEkv", + "1UEn&", + "1UEn,", + "1UEn1", + "1UEnc", + "1UEnf", + "1UEnk", + "1UEno", + "1UEns", + "1UEok", + "1UEs", + "1UEs&", + "1UEs,", + "1UEsc", + "1UEsf", + "1UEsk", + "1UEsn", + "1UEso", + "1UEv", + "1UEv&", + "1UEv,", + "1UEvc", + "1UEvf", + "1UEvk", + "1UEvn", + "1UEvo", "1Uc", - "1Uk", - "1Uk(1", - "1Uk(k", - "1Uk(n", - "1Uk(s", - "1Uk(v", - "1Uk1", - "1Uk1,", - "1Uk1c", - "1Uk1f", - "1Uk1k", - "1Uk1n", - "1Uk1o", - "1Ukf", - "1Ukf(", - "1Ukf,", - "1Ukk(", - "1Ukk,", - "1Ukk1", - "1Ukkk", - "1Ukkn", - "1Ukks", - "1Ukkv", - "1Ukn&", - "1Ukn(", - "1Ukn,", - "1Ukn1", - "1Uknc", - "1Uknk", - "1Ukno", - "1Ukns", - "1Uknv", - "1Uko1", - "1Ukok", - "1Ukos", - "1Ukov", - "1Uks", - "1Uks,", - "1Uksc", - "1Uksf", - "1Uksk", - "1Uksn", - "1Ukso", - "1Ukv", - "1Ukv,", - "1Ukvc", - "1Ukvf", - "1Ukvk", - "1Ukvn", - "1Ukvo", + "1Uf((", + "1Uf(1", + "1Uf(f", + "1Uf(s", + "1Uf(v", + "1Uk((", + "1Uk(E", "1Un,1", + "1Un,f", "1Un,s", "1Un,v", "1Un1,", - "1Unk(", - "1Unk1", - "1Unkf", - "1Unks", - "1Unkv", - "1Uns,", - "1Unv,", + "1Un1o", + "1UnE1", + "1UnEf", + "1UnEs", + "1UnEv", + "1Unc", + "1Unf(", + "1Uo((", + "1Uo(E", "1Uon1", - "1Uons", - "1Uonv", + "1Uonf", "1Us,1", + "1Us,f", "1Us,s", "1Us,v", + "1Uso1", + "1Usof", + "1Uson", + "1Usos", + "1Usov", "1Uv,1", + "1Uv,f", "1Uv,s", "1Uv,v", + "1Uvo1", + "1Uvof", + "1Uvon", + "1Uvos", + "1Uvov", "1c", + "1f(((", + "1f(()", + "1f((1", + "1f((f", + "1f((n", + "1f((s", + "1f((v", + "1f())", "1f()k", + "1f(1)", + "1f(1o", + "1f(f(", + "1f(n,", + "1f(s)", + "1f(so", + "1f(v)", + "1f(vo", + "1k(((", + "1k((1", + "1k((f", + "1k((s", + "1k((v", + "1k(1)", + "1k(1o", + "1k(f(", + "1k(s)", + "1k(so", + "1k(v)", + "1k(vo", + "1k)&(", + "1k)&1", + "1k)&f", + "1k)&s", + "1k)&v", + "1k))&", + "1k)))", + "1k));", + "1k))B", + "1k))E", + "1k))U", + "1k))k", + "1k))o", + "1k);E", + "1k)B1", + "1k)Bf", + "1k)Bs", + "1k)Bv", + "1k)E1", + "1k)Ef", + "1k)Es", + "1k)Ev", + "1k)UE", + "1k)oE", + "1k1", + "1k1&(", + "1k1&1", + "1k1&f", + "1k1&o", + "1k1&s", + "1k1&v", + "1k1;E", + "1k1B1", + "1k1Bf", + "1k1Bs", + "1k1Bv", + "1k1E1", + "1k1Ef", + "1k1Es", + "1k1Ev", "1k1U(", - "1k1Uk", + "1k1UE", "1k1c", - "1k1o1", + "1k1oE", + "1k1of", + "1k1os", "1k1ov", - "1kU1,", - "1kUs,", - "1kUv,", + "1kf((", "1kf(1", + "1kf(f", "1kf(s", "1kf(v", - "1kk(1", - "1kk(s", - "1kk(v", - "1kksc", - "1kkvc", - "1knkn", - "1kno1", - "1knov", - "1kokn", + "1knc", + "1ks", + "1ks&(", + "1ks&1", + "1ks&f", + "1ks&o", + "1ks&s", + "1ks&v", + "1ks;E", + "1ksB1", + "1ksBf", + "1ksBs", + "1ksBv", + "1ksE1", + "1ksEf", + "1ksEs", + "1ksEv", "1ksU(", - "1ksUk", + "1ksUE", "1ksc", + "1kso1", + "1ksoE", + "1ksof", + "1kson", + "1ksos", + "1ksov", + "1kv", + "1kv&(", + "1kv&1", + "1kv&f", + "1kv&o", + "1kv&s", + "1kv&v", + "1kv;E", + "1kvB1", + "1kvBf", + "1kvBs", + "1kvBv", + "1kvE1", + "1kvEf", + "1kvEs", + "1kvEv", "1kvU(", - "1kvUk", + "1kvUE", "1kvc", "1kvo1", + "1kvoE", + "1kvof", + "1kvon", + "1kvos", "1kvov", "1n&f(", - "1n)Uk", - "1nUk1", - "1nUkn", - "1nUks", - "1nUkv", - "1nk1c", - "1nkf(", - "1nksc", - "1nkvc", + "1n)))", + "1n))U", + "1n))n", + "1n)UE", + "1n,f(", + "1n1c", + "1n1of", + "1n1os", + "1n1ov", + "1nE1c", + "1nE1o", + "1nEf(", + "1nEsc", + "1nEso", + "1nEvc", + "1nEvo", + "1nU((", + "1nU(E", + "1nUE1", + "1nUEf", + "1nUEs", + "1nUEv", + "1nf((", + "1nf(1", + "1nf(f", + "1nf(s", + "1nf(v", + "1no((", + "1no(1", + "1no(f", + "1no(s", + "1no(v", + "1nof(", + "1nosU", + "1noso", + "1novU", + "1novo", "1o(((", "1o((1", + "1o((E", "1o((f", + "1o((n", + "1o((o", "1o((s", "1o((v", "1o(1)", "1o(1o", + "1o(E(", + "1o(E1", + "1o(EE", + "1o(Ef", + "1o(En", + "1o(Es", + "1o(Ev", "1o(f(", - "1o(k(", - "1o(k1", - "1o(kf", - "1o(kn", - "1o(ks", - "1o(kv", "1o(n)", "1o(o1", + "1o(of", "1o(os", "1o(ov", "1o(s)", "1o(so", "1o(v)", "1o(vo", - "1o1)&", - "1o1)o", - "1o1Bf", - "1o1Uk", - "1o1f(", - "1o1kf", - "1o1o(", - "1o1o1", - "1o1of", - "1o1oo", - "1o1os", - "1o1ov", + "1oE((", + "1oE(1", + "1oE(f", + "1oE(s", + "1oE(v", + "1oEUE", + "1oU((", + "1oU(E", + "1of((", "1of()", "1of(1", "1of(f", - "1of(n", "1of(s", "1of(v", + "1ok&1", + "1ok&f", + "1ok&s", + "1ok&v", + "1ok((", "1ok(1", - "1ok(k", + "1ok(f", "1ok(s", "1ok(v", - "1ok)U", - "1ok)o", - "1ok1", - "1ok1,", "1ok1c", - "1ok1k", - "1okUk", + "1ok1o", "1okf(", - "1oks", - "1oks,", + "1oko1", + "1okof", + "1okos", + "1okov", "1oksc", - "1oksk", - "1okv", - "1okv,", + "1okso", "1okvc", - "1okvk", - "1onos", - "1onov", + "1okvo", + "1os&(", + "1os&1", + "1os&E", + "1os&U", + "1os&f", + "1os&k", + "1os&n", + "1os&o", + "1os&s", + "1os&v", + "1os((", + "1os(E", + "1os(U", "1os)&", + "1os))", + "1os),", + "1os);", + "1os)B", + "1os)E", "1os)U", + "1os)k", "1os)o", + "1os,(", + "1os,1", + "1os,f", + "1os,s", + "1os,v", + "1os1:", + "1os1f", + "1os1o", + "1os1s", + "1os1v", + "1os:n", + "1os;E", + "1os;n", + "1osB1", + "1osBE", "1osBf", + "1osBn", + "1osBs", + "1osBv", + "1osE1", + "1osEU", + "1osEf", + "1osEn", + "1osEo", + "1osEs", + "1osEv", + "1osU", + "1osU(", + "1osU1", + "1osUE", + "1osUc", + "1osUf", "1osUk", + "1osUn", + "1osUo", + "1osUs", + "1osUv", + "1osc", "1osf(", + "1osk(", + "1osk)", + "1osk1", "1oskf", + "1oskn", + "1osks", + "1oskv", + "1osn&", + "1osn)", + "1osn,", + "1osn1", + "1osnE", + "1osnU", + "1osnf", + "1osno", "1oso(", "1oso1", + "1osoE", + "1osoU", "1osof", - "1osoo", + "1osok", + "1oson", "1osos", "1osov", + "1osv:", + "1osvf", + "1osvo", + "1osvs", + "1ov", + "1ov&(", + "1ov&1", + "1ov&E", + "1ov&U", + "1ov&f", + "1ov&k", + "1ov&n", + "1ov&o", + "1ov&s", + "1ov&v", + "1ov((", + "1ov(E", + "1ov(U", "1ov)&", + "1ov))", + "1ov),", + "1ov);", + "1ov)B", + "1ov)E", "1ov)U", + "1ov)k", "1ov)o", + "1ov,(", + "1ov,1", + "1ov,f", + "1ov,s", + "1ov,v", + "1ov:n", + "1ov;E", + "1ov;n", + "1ovB1", + "1ovBE", "1ovBf", + "1ovBn", + "1ovBs", + "1ovBv", + "1ovE1", + "1ovEU", + "1ovEf", + "1ovEn", + "1ovEo", + "1ovEs", + "1ovEv", + "1ovU", + "1ovU(", + "1ovU1", + "1ovUE", + "1ovUc", + "1ovUf", "1ovUk", + "1ovUn", + "1ovUo", + "1ovUs", + "1ovUv", + "1ovc", "1ovf(", + "1ovk(", + "1ovk)", + "1ovk1", "1ovkf", + "1ovkn", + "1ovks", + "1ovkv", + "1ovn&", + "1ovn)", + "1ovn,", + "1ovn1", + "1ovnE", + "1ovnU", + "1ovnf", + "1ovno", "1ovo(", "1ovo1", + "1ovoE", + "1ovoU", "1ovof", - "1ovoo", + "1ovok", + "1ovon", "1ovos", "1ovov", - ";kknc", - "Uk1,1", - "Uk1,f", - "Uk1,n", - "Uk1,s", - "Uk1,v", - "Ukkkn", - "Uks,1", - "Uks,f", - "Uks,n", - "Uks,s", - "Uks,v", - "Ukv,1", - "Ukv,f", - "Ukv,n", - "Ukv,s", - "Ukv,v", + "1ovs1", + "1ovs:", + "1ovsf", + "1ovso", + "1ovsv", + "1s1", + "1s1c", + "1s1of", + "1s1os", + "1s1ov", + "1s:1:", + "1s:1o", + "1s:f(", + "1s:s:", + "1s:so", + "1s:v:", + "1s:vo", + "1sf((", + "1sf(1", + "1sf(f", + "1sf(s", + "1sf(v", + "1so1f", + "1so1o", + "1so1s", + "1so1v", + "1sof(", + "1son1", + "1sonf", + "1sos1", + "1sosf", + "1soso", + "1sosv", + "1sovf", + "1sovo", + "1sovs", + "1sv", + "1svc", + "1svo1", + "1svof", + "1svon", + "1svos", + "1svov", + "1v:1:", + "1v:1o", + "1v:f(", + "1v:s:", + "1v:so", + "1v:v:", + "1v:vo", + "1vf((", + "1vf(1", + "1vf(f", + "1vf(s", + "1vf(v", + "1vo1f", + "1vo1o", + "1vo1s", + "1vo1v", + "1vof(", + "1von1", + "1vonf", + "1vos1", + "1vosf", + "1voso", + "1vosv", + "1vovf", + "1vovo", + "1vovs", + "1vs", + "1vsc", + "1vso1", + "1vsof", + "1vson", + "1vsos", + "1vsov", + ";Eknc", + "E((((", + "E(((1", + "E(((E", + "E(((f", + "E(((n", + "E(((s", + "E(((v", + "E((1)", + "E((1f", + "E((1o", + "E((1s", + "E((1v", + "E((Ek", + "E((f(", + "E((n)", + "E((s)", + "E((s1", + "E((sf", + "E((so", + "E((sv", + "E((v)", + "E((vf", + "E((vo", + "E((vs", + "E(1))", + "E(1),", + "E(1f(", + "E(1of", + "E(1os", + "E(1ov", + "E(1s)", + "E(1so", + "E(1v)", + "E(1vo", + "E(Ek(", + "E(f((", + "E(f(1", + "E(f(f", + "E(f(s", + "E(f(v", + "E(n))", + "E(n),", + "E(s))", + "E(s),", + "E(s1)", + "E(s1o", + "E(sf(", + "E(so1", + "E(sof", + "E(son", + "E(sos", + "E(sov", + "E(sv)", + "E(svo", + "E(v))", + "E(v),", + "E(vf(", + "E(vo1", + "E(vof", + "E(von", + "E(vos", + "E(vov", + "E(vs)", + "E(vso", + "E(vv)", + "E1&((", + "E1&(E", + "E1)", + "E1))", + "E1)))", + "E1))1", + "E1))c", + "E1))f", + "E1))s", + "E1))v", + "E1)c", + "E1,((", + "E1,(1", + "E1,(f", + "E1,(s", + "E1,(v", + "E1,1,", + "E1,1k", + "E1,1o", + "E1,f(", + "E1,n,", + "E1,s,", + "E1,sk", + "E1,so", + "E1,v,", + "E1,vk", + "E1,vo", + "E1f((", + "E1f(1", + "E1f(f", + "E1f(s", + "E1f(v", + "E1k((", + "E1k(E", + "E1k1k", + "E1k1o", + "E1kf(", + "E1knk", + "E1ksk", + "E1kso", + "E1kvk", + "E1kvo", + "E1o((", + "E1o(1", + "E1o(f", + "E1o(s", + "E1o(v", + "E1of(", + "E1os1", + "E1osf", + "E1oso", + "E1osv", + "E1ovf", + "E1ovo", + "E1ovs", + "EE(((", + "EE((f", + "EE(f(", + "Ef(((", + "Ef((1", + "Ef((f", + "Ef((n", + "Ef((o", + "Ef((s", + "Ef((v", + "Ef(1)", + "Ef(1,", + "Ef(1o", + "Ef(f(", + "Ef(n)", + "Ef(n,", + "Ef(o)", + "Ef(s)", + "Ef(s,", + "Ef(so", + "Ef(v)", + "Ef(v,", + "Ef(vo", + "Ek1f(", + "Ek1k1", + "Ek1kf", + "Ek1kn", + "Ek1ks", + "Ek1kv", + "Ek1nk", + "Ek1of", + "Ek1os", + "Ek1ov", + "Ek1sf", + "Ek1sk", + "Ek1so", + "Ek1vf", + "Ek1vk", + "Ek1vo", + "Ekf((", + "Ekf(1", + "Ekf(f", + "Ekf(s", + "Ekf(v", + "Eks1f", + "Eks1k", + "Eks1o", + "Eksf(", + "Eksk1", + "Ekskf", + "Ekskn", + "Eksks", + "Ekskv", + "Eksnk", + "Ekso1", + "Eksof", + "Ekson", + "Eksos", + "Eksov", + "Eksvf", + "Eksvk", + "Eksvo", + "Ekvf(", + "Ekvk1", + "Ekvkf", + "Ekvkn", + "Ekvks", + "Ekvkv", + "Ekvnk", + "Ekvo1", + "Ekvof", + "Ekvon", + "Ekvos", + "Ekvov", + "Ekvsf", + "Ekvsk", + "Ekvso", + "En,f(", + "En,n,", + "Enk((", + "Enk(E", + "Enknk", + "Eo(((", + "Eo((1", + "Eo((f", + "Eo((s", + "Eo((v", + "Eo(1,", + "Eo(1o", + "Eo(f(", + "Eo(s,", + "Eo(so", + "Eo(v,", + "Eo(vo", + "Eok((", + "Eok(E", + "Es&((", + "Es&(E", + "Es)", + "Es))", + "Es)))", + "Es))1", + "Es))c", + "Es))f", + "Es))s", + "Es))v", + "Es)c", + "Es,((", + "Es,(1", + "Es,(f", + "Es,(s", + "Es,(v", + "Es,1,", + "Es,1k", + "Es,1o", + "Es,f(", + "Es,n,", + "Es,s,", + "Es,sk", + "Es,so", + "Es,v,", + "Es,vk", + "Es,vo", + "Esf((", + "Esf(1", + "Esf(f", + "Esf(s", + "Esf(v", + "Esk((", + "Esk(E", + "Esk1k", + "Esk1o", + "Eskf(", + "Esknk", + "Esksk", + "Eskso", + "Eskvk", + "Eskvo", + "Eso((", + "Eso(1", + "Eso(f", + "Eso(s", + "Eso(v", + "Eso1f", + "Eso1o", + "Eso1s", + "Eso1v", + "Esof(", + "Eson1", + "Esonf", + "Esos1", + "Esosf", + "Esoso", + "Esosv", + "Esovf", + "Esovo", + "Esovs", + "Ev&((", + "Ev&(E", + "Ev)", + "Ev))", + "Ev)))", + "Ev))1", + "Ev))c", + "Ev))f", + "Ev))s", + "Ev))v", + "Ev)c", + "Ev,((", + "Ev,(1", + "Ev,(f", + "Ev,(s", + "Ev,(v", + "Ev,1,", + "Ev,1k", + "Ev,1o", + "Ev,f(", + "Ev,n,", + "Ev,s,", + "Ev,sk", + "Ev,so", + "Ev,v,", + "Ev,vk", + "Ev,vo", + "Evf((", + "Evf(1", + "Evf(f", + "Evf(s", + "Evf(v", + "Evk((", + "Evk(E", + "Evk1k", + "Evk1o", + "Evkf(", + "Evknk", + "Evksk", + "Evkso", + "Evkvk", + "Evkvo", + "Evo((", + "Evo(1", + "Evo(f", + "Evo(s", + "Evo(v", + "Evo1f", + "Evo1o", + "Evo1s", + "Evo1v", + "Evof(", + "Evon1", + "Evonf", + "Evos1", + "Evosf", + "Evoso", + "Evosv", + "Evovf", + "Evovo", + "Evovs", + "U((((", + "U(((E", + "U((En", + "U(Enk", + "UE(((", + "UE((1", + "UE((f", + "UE((s", + "UE((v", + "UE(1,", + "UE(1o", + "UE(f(", + "UE(s,", + "UE(so", + "UE(v,", + "UE(vo", + "UE1,1", + "UE1,f", + "UE1,n", + "UE1,s", + "UE1,v", + "UE1of", + "UE1os", + "UE1ov", + "UEf((", + "UEf(1", + "UEf(f", + "UEf(s", + "UEf(v", + "UEnkn", + "UEs,1", + "UEs,f", + "UEs,n", + "UEs,s", + "UEs,v", + "UEso1", + "UEsof", + "UEson", + "UEsos", + "UEsov", + "UEv,1", + "UEv,f", + "UEv,n", + "UEv,s", + "UEv,v", + "UEvo1", + "UEvof", + "UEvon", + "UEvos", + "UEvov", + "Uf(((", + "Uf((1", + "Uf((f", + "Uf((s", + "Uf((v", + "Uf(1)", + "Uf(1o", + "Uf(f(", + "Uf(s)", + "Uf(so", + "Uf(v)", + "Uf(vo", + "f((((", + "f((()", + "f(((1", + "f(((E", + "f(((f", + "f(((k", + "f(((s", + "f(((v", + "f(()&", + "f(())", + "f(()o", + "f((1)", + "f((1,", + "f((1o", + "f((E(", + "f((Ef", "f((f(", "f((k(", - "f((kf", + "f((k,", + "f((s)", + "f((s,", + "f((so", + "f((v)", + "f((v,", + "f((vo", "f()&f", - "f()of", + "f())&", + "f()))", + "f())o", + "f()ok", "f(1)&", + "f(1))", + "f(1),", + "f(1)1", + "f(1):", + "f(1);", + "f(1)B", + "f(1)E", "f(1)U", + "f(1)c", + "f(1)f", + "f(1)k", + "f(1)n", "f(1)o", + "f(1)s", + "f(1)v", "f(1,1", "f(1,f", + "f(1,n", "f(1,s", "f(1,v", - "f(1o1", + "f(1of", "f(1os", "f(1ov", + "f(f((", "f(f()", "f(f(1", "f(f(f", "f(f(s", "f(f(v", + "f(k((", "f(k()", "f(k,(", "f(k,f", - "f(k,n", - "f(n()", "f(s)&", + "f(s))", + "f(s),", + "f(s)1", + "f(s):", + "f(s);", + "f(s)B", + "f(s)E", "f(s)U", + "f(s)c", + "f(s)f", + "f(s)k", + "f(s)n", "f(s)o", + "f(s)s", + "f(s)v", "f(s,1", "f(s,f", + "f(s,n", "f(s,s", "f(s,v", "f(so1", + "f(sof", + "f(son", "f(sos", "f(sov", "f(v)&", + "f(v))", + "f(v),", + "f(v)1", + "f(v):", + "f(v);", + "f(v)B", + "f(v)E", "f(v)U", + "f(v)c", + "f(v)f", + "f(v)k", + "f(v)n", "f(v)o", + "f(v)s", + "f(v)v", "f(v,1", "f(v,f", + "f(v,n", "f(v,s", "f(v,v", "f(vo1", + "f(vof", + "f(von", "f(vos", "f(vov", - "k()ok", - "k(1)U", - "k(f(1", - "k(f(v", - "k(ok(", - "k(s)U", - "k(sv)", - "k(v)U", - "k(vs)", - "k(vv)", - "k1,1,", + "ff(((", + "ff((1", + "ff((f", + "ff((s", + "ff((v", + "ff(1)", + "ff(1o", + "ff(f(", + "ff(s)", + "ff(so", + "ff(v)", + "ff(vo", "k1,1c", - "k1,1k", + "k1,1o", "k1,f(", - "k1,n,", - "k1,s,", "k1,sc", - "k1,sk", - "k1,v,", + "k1,so", "k1,vc", - "k1,vk", - "k1k(k", - "k1kf(", - "k1o(s", - "k1o(v", - "k;non", - "kc", + "k1,vo", + "k1of(", + "k1os1", + "k1osf", + "k1oso", + "k1osv", + "k1ovf", + "k1ovo", + "k1ovs", + "kf(((", + "kf((1", "kf((f", + "kf((s", + "kf((v", "kf(1)", - "kf(1,", + "kf(1o", "kf(f(", - "kf(n,", - "kf(o)", "kf(s)", - "kf(s,", - "kf(s:", + "kf(so", "kf(v)", - "kf(v,", - "kf(v:", - "kk(f(", - "kk1f(", - "kk1fn", - "kk1kk", - "kk1nk", - "kk1sf", - "kk1sk", - "kk1sn", - "kk1vf", - "kk1vk", - "kk1vn", - "kksf(", - "kksfn", - "kkskk", - "kksnk", - "kksvk", - "kksvn", - "kkvf(", - "kkvfn", - "kkvkk", - "kkvnk", - "kkvsf", - "kkvsk", - "kkvsn", - "kkvvf", - "kkvvk", - "kkvvn", - "kn1kk", - "kn1sk", - "kn1sn", - "kn1vk", - "kn1vn", - "knk(k", - "knskk", - "knsvk", - "knsvn", - "knvkk", - "knvsk", - "knvsn", - "knvvk", - "knvvn", - "ko(k(", - "ko(kf", - "ko(n,", - "ko(s,", - "ko(v,", - "kok(k", - "ks&(k", - "ks&(o", - "ks)", - "ks,1,", + "kf(vo", "ks,1c", - "ks,1k", + "ks,1o", "ks,f(", - "ks,s,", "ks,sc", - "ks,sk", - "ks,v,", + "ks,so", "ks,vc", - "ks,vk", - "ksf(1", - "ksf(s", - "ksf(v", - "ksk(1", - "ksk(k", - "ksk(s", - "ksk(v", - "kso(s", - "kso(v", - "kv&(k", - "kv&(o", - "kv)", - "kv,1,", + "ks,vo", + "kso1f", + "kso1o", + "kso1s", + "kso1v", + "ksof(", + "kson1", + "ksonf", + "ksos1", + "ksosf", + "ksoso", + "ksosv", + "ksovf", + "ksovo", + "ksovs", "kv,1c", - "kv,1k", + "kv,1o", "kv,f(", - "kv,n,", - "kv,s,", "kv,sc", - "kv,sk", - "kv,v,", + "kv,so", "kv,vc", - "kv,vk", - "kvf(1", - "kvf(s", - "kvf(v", - "kvk(1", - "kvk(k", - "kvk(s", - "kvk(v", - "kvkf(", - "kvo(s", - "kvo(v", + "kv,vo", + "kvo1f", + "kvo1o", + "kvo1s", + "kvo1v", + "kvof(", + "kvon1", + "kvonf", + "kvos1", + "kvosf", + "kvoso", + "kvosv", + "kvovf", + "kvovo", + "kvovs", + "n&(((", + "n&((1", + "n&((E", + "n&((f", + "n&((o", + "n&((s", + "n&((v", "n&(1)", "n&(1,", - "n&(k1", - "n&(ks", - "n&(kv", + "n&(1o", + "n&(E1", + "n&(Ef", + "n&(Es", + "n&(Ev", + "n&(f(", "n&(o1", + "n&(of", "n&(os", "n&(ov", "n&(s)", "n&(s,", + "n&(so", "n&(v)", "n&(v,", + "n&(vo", + "n&1", + "n&1&n", "n&1Bf", + "n&1UE", + "n&1c", "n&1f(", "n&1o(", - "n&1o1", "n&1of", "n&1oo", "n&1os", "n&1ov", + "n&E((", + "n&E(1", + "n&E(f", + "n&E(s", + "n&E(v", + "n&f((", "n&f(1", "n&f(f", "n&f(s", "n&f(v", - "n&k(1", - "n&k(s", - "n&k(v", + "n&nUE", + "n&nof", + "n&nos", + "n&nov", + "n&o1", + "n&o1c", "n&o1o", + "n&of(", + "n&os", + "n&osc", "n&oso", + "n&ov", + "n&ovc", "n&ovo", + "n&s", + "n&s&n", + "n&sBf", + "n&sUE", + "n&sc", "n&sf(", "n&so(", "n&so1", "n&sof", + "n&son", "n&soo", "n&sos", "n&sov", + "n&v", + "n&v&n", "n&vBf", + "n&vUE", + "n&vc", "n&vf(", "n&vo(", "n&vo1", "n&vof", + "n&von", "n&voo", "n&vos", "n&vov", - "n)&(k", + "n)&((", + "n)&(E", + "n)&1", + "n)&1&", + "n)&1c", "n)&1f", "n)&1o", "n)&f(", + "n)&s", + "n)&s&", + "n)&sc", "n)&sf", "n)&so", + "n)&v", + "n)&v&", + "n)&vc", "n)&vf", "n)&vo", "n))&(", @@ -1799,194 +2928,344 @@ static const char* sql_fingerprints[] = { "n))&s", "n))&v", "n)))&", + "n))))", "n)));", "n)))B", + "n)))E", "n)))U", - "n)))c", "n)))k", "n)))o", - "n));c", - "n));k", + "n));E", "n))B1", + "n))Bf", + "n))Bs", "n))Bv", - "n))Uk", - "n))c", - "n))kk", - "n))o(", + "n))E1", + "n))Ef", + "n))Es", + "n))Ev", + "n))UE", + "n))k1", + "n))kf", + "n))ks", + "n))kv", "n))o1", + "n))oE", "n))of", - "n))ok", "n))os", "n))ov", - "n);c", - "n);k&", - "n);k(", - "n);kf", - "n);kk", - "n);kn", - "n);ko", + "n);E&", + "n);E(", + "n);E1", + "n);Ef", + "n);Eo", + "n);Es", + "n);Ev", "n)B1c", + "n)B1o", + "n)Bf(", + "n)Bsc", + "n)Bso", "n)Bvc", - "n)Uk1", - "n)Ukv", - "n)c", + "n)Bvo", + "n)E1c", + "n)E1o", + "n)Ef(", + "n)Esc", + "n)Eso", + "n)Evc", + "n)Evo", + "n)UE1", + "n)UEf", + "n)UEs", + "n)UEv", + "n)k1&", + "n)k1;", + "n)k1B", + "n)k1U", "n)k1o", - "n)kks", - "n)kkv", + "n)kf(", + "n)ks&", + "n)ks;", + "n)ksB", + "n)ksU", "n)kso", + "n)kv&", + "n)kv;", + "n)kvB", + "n)kvU", "n)kvo", - "n)o(k", "n)o1&", - "n)o1f", "n)o1o", + "n)oE(", "n)of(", - "n)ok(", "n)os&", - "n)osf", "n)oso", "n)ov&", - "n)ovf", "n)ovo", + "n,(((", + "n,((E", + "n,((f", + "n,(E(", + "n,(E1", + "n,(Ef", + "n,(Es", + "n,(Ev", "n,(f(", - "n,(k(", - "n,(k1", - "n,(kf", - "n,(ks", - "n,(kv", + "n,1,1", + "n,1,f", + "n,1,s", + "n,1,v", + "n,1of", + "n,1os", + "n,1ov", + "n,f((", "n,f(1", + "n,f(f", "n,f(s", "n,f(v", + "n,s,1", + "n,s,f", + "n,s,s", + "n,s,v", + "n,so1", + "n,sof", + "n,son", + "n,sos", + "n,sov", + "n,v,1", + "n,v,f", + "n,v,s", + "n,v,v", + "n,vo1", + "n,vof", + "n,von", + "n,vos", + "n,vov", "n:o1U", + "n:o1o", + "n:of(", "n:osU", + "n:oso", "n:ovU", - "n;c", - "n;k&k", - "n;k((", - "n;k(1", - "n;k(s", - "n;k(v", - "n;kf(", - "n;kks", - "n;kkv", - "n;kn(", - "n;ko(", - "n;kok", + "n:ovo", + "n;E&k", + "n;E((", + "n;E(1", + "n;E(f", + "n;E(s", + "n;E(v", + "n;E1;", + "n;E1c", + "n;E1o", + "n;Ef(", + "n;Eo(", + "n;Es;", + "n;Esc", + "n;Eso", + "n;Ev;", + "n;Evc", + "n;Evo", "nB1c", + "nB1of", + "nB1os", + "nB1ov", + "nBf((", + "nBf(1", + "nBf(f", + "nBf(s", + "nBf(v", + "nBsc", + "nBso1", + "nBsof", + "nBson", + "nBsos", + "nBsov", "nBvc", - "nUk(k", - "nUk1,", - "nUk1c", - "nUkf(", - "nUkn,", - "nUks,", - "nUkv,", - "nUkvc", - "nUnk(", + "nBvo1", + "nBvof", + "nBvon", + "nBvos", + "nBvov", + "nE1c", + "nE1of", + "nE1os", + "nE1ov", + "nEf((", + "nEf(1", + "nEf(f", + "nEf(s", + "nEf(v", + "nEsc", + "nEso1", + "nEsof", + "nEson", + "nEsos", + "nEsov", + "nEvc", + "nEvo1", + "nEvof", + "nEvon", + "nEvos", + "nEvov", + "nU(((", + "nU((E", + "nU(E1", + "nU(Ef", + "nU(En", + "nU(Es", + "nU(Ev", + "nUE((", + "nUE(E", + "nUE1,", + "nUE1c", + "nUE1o", + "nUEf(", + "nUEn,", + "nUEs,", + "nUEsc", + "nUEso", + "nUEv,", + "nUEvc", + "nUEvo", "nc", - "nk1Uk", - "nk1o1", + "nf(((", + "nf((1", + "nf((f", + "nf((s", + "nf((v", + "nf(1)", + "nf(1o", + "nf(f(", + "nf(s)", + "nf(so", + "nf(v)", + "nf(vo", + "nk1&(", + "nk1&1", + "nk1&f", + "nk1&s", + "nk1&v", + "nk1;E", + "nk1B1", + "nk1Bf", + "nk1Bs", + "nk1Bv", + "nk1UE", + "nk1oE", + "nk1of", + "nk1os", "nk1ov", + "nkf((", "nkf(1", + "nkf(f", "nkf(s", "nkf(v", - "nkksc", - "nkkvc", - "nksUk", - "nkvUk", + "nks&(", + "nks&1", + "nks&f", + "nks&s", + "nks&v", + "nks;E", + "nksB1", + "nksBf", + "nksBs", + "nksBv", + "nksUE", + "nkso1", + "nksoE", + "nksof", + "nkson", + "nksos", + "nksov", + "nkv&(", + "nkv&1", + "nkv&f", + "nkv&s", + "nkv&v", + "nkv;E", + "nkvB1", + "nkvBf", + "nkvBs", + "nkvBv", + "nkvUE", "nkvo1", + "nkvoE", + "nkvof", + "nkvon", + "nkvos", "nkvov", - "nnn)U", - "nno1U", - "nnosU", - "nnovU", - "no(k1", - "no(ks", - "no(kv", - "no(o1", - "no(os", - "no(ov", - "no1&1", - "no1&s", - "no1&v", - "no1Uk", - "no1f(", - "no1o(", - "no1of", - "no1oo", - "no1os", - "no1ov", + "no(((", + "no((E", + "no(E1", + "no(Ef", + "no(Es", + "no(Ev", + "noE((", + "noE(1", + "noE(f", + "noE(s", + "noE(v", + "nof((", "nof(1", + "nof(f", "nof(s", "nof(v", - "nok(1", - "nok(f", - "nok(k", - "nok(s", - "nok(v", - "nono1", - "nonov", - "nos&1", - "nos&s", - "nos&v", - "nosUk", - "nosf(", - "noso(", + "nosUE", "noso1", "nosof", - "nosoo", + "noson", "nosos", "nosov", - "nov&1", - "nov&s", - "nov&v", - "novUk", - "novf(", - "novo(", + "novUE", "novo1", "novof", - "novoo", + "novon", "novos", "novov", - "o1kf(", - "oUk1,", - "oUks,", - "oUkv,", - "oc", - "of()o", + "oUE1,", + "oUE1o", + "oUEf(", + "oUEs,", + "oUEso", + "oUEv,", + "oUEvo", + "of(((", + "of((1", + "of((f", + "of((s", + "of((v", "of(1)", + "of(1o", + "of(f(", "of(s)", + "of(so", "of(v)", - "ok1o1", - "ok1os", - "ok1ov", - "okkkn", - "okso1", - "oksos", - "oksov", - "okvo1", - "okvos", - "okvov", - "ook1,", - "ooks,", - "ookv,", - "oskf(", - "ovkf(", + "of(vo", + "ooE1,", + "ooE1o", + "ooEf(", + "ooEs,", + "ooEso", + "ooEv,", + "ooEvo", + "s&(((", + "s&((1", + "s&((E", "s&((f", - "s&((k", + "s&((s", + "s&((v", "s&(1)", "s&(1,", "s&(1o", + "s&(E1", + "s&(Ef", + "s&(Ek", + "s&(En", + "s&(Eo", + "s&(Es", + "s&(Ev", "s&(f(", - "s&(k(", - "s&(k)", - "s&(k1", - "s&(kc", - "s&(kf", - "s&(kk", - "s&(kn", - "s&(ko", - "s&(ks", - "s&(kv", "s&(s)", "s&(s,", "s&(so", @@ -1994,123 +3273,205 @@ static const char* sql_fingerprints[] = { "s&(v,", "s&(vo", "s&1", + "s&1&(", + "s&1&1", + "s&1&f", + "s&1&n", + "s&1&s", + "s&1&v", + "s&1B1", "s&1Bf", - "s&1Uk", + "s&1Bs", + "s&1Bv", + "s&1En", + "s&1U", + "s&1U(", + "s&1UE", + "s&1Uc", "s&1c", "s&1f(", + "s&1k1", + "s&1kf", + "s&1ks", + "s&1kv", "s&1o(", - "s&1o1", + "s&1oE", "s&1of", - "s&1ok", - "s&1on", "s&1oo", "s&1os", "s&1ov", + "s&1so", + "s&1vo", + "s&E((", + "s&E(1", + "s&E(f", + "s&E(o", + "s&E(s", + "s&E(v", + "s&E1k", + "s&E1o", + "s&Ef(", + "s&Ek1", + "s&Ekf", + "s&Eks", + "s&Ekv", + "s&Esk", + "s&Eso", + "s&Evk", + "s&Evo", "s&f((", "s&f()", "s&f(1", "s&f(f", - "s&f(k", "s&f(n", "s&f(s", "s&f(v", + "s&k&1", + "s&k&f", "s&k&s", "s&k&v", - "s&k(1", - "s&k(f", - "s&k(o", - "s&k(s", - "s&k(v", - "s&k1k", "s&k1o", - "s&kUk", - "s&kc", - "s&kk1", - "s&kks", - "s&kkv", + "s&kf(", "s&knk", "s&ko(", "s&ko1", + "s&kof", "s&kok", + "s&kon", "s&kos", "s&kov", - "s&ksk", "s&kso", - "s&kvk", "s&kvo", + "s&n", + "s&n&1", + "s&n&f", + "s&n&n", "s&n&s", "s&n&v", - "s&n()", - "s&no1", + "s&nc", + "s&nk1", + "s&nkf", + "s&nks", + "s&nkv", + "s&nof", "s&nos", "s&nov", + "s&o((", "s&o(1", - "s&o(k", + "s&o(f", "s&o(s", "s&o(v", + "s&o1", + "s&o1c", "s&o1o", - "s&okc", + "s&of(", "s&oko", "s&os", + "s&osc", "s&oso", "s&ov", + "s&ovc", "s&ovo", "s&s", - "s&s:o", + "s&s&(", + "s&s&1", + "s&s&f", + "s&s&n", + "s&s&s", + "s&s&v", + "s&s1o", + "s&sB1", "s&sBf", + "s&sBs", + "s&sBv", + "s&sEn", + "s&sU", "s&sU(", - "s&sUk", + "s&sUE", + "s&sUc", "s&sc", "s&sf(", + "s&sk1", + "s&skf", + "s&sks", + "s&skv", "s&so(", "s&so1", + "s&soE", "s&sof", - "s&sok", "s&son", "s&soo", "s&sos", "s&sov", "s&svo", "s&v", - "s&v:o", + "s&v&(", + "s&v&1", + "s&v&f", + "s&v&n", + "s&v&s", + "s&v&v", + "s&vB1", "s&vBf", + "s&vBs", + "s&vBv", + "s&vEn", + "s&vU", "s&vU(", - "s&vUk", + "s&vUE", + "s&vUc", "s&vc", "s&vf(", + "s&vk1", + "s&vkf", + "s&vks", + "s&vkv", "s&vo(", "s&vo1", + "s&voE", "s&vof", - "s&vok", "s&von", "s&voo", "s&vos", "s&vov", "s&vso", - "s&vvo", - "s(c", + "s((((", + "s(((E", + "s(((U", + "s((En", + "s((U(", + "s(Enk", + "s(U((", + "s(U(E", + "s)&((", "s)&(1", + "s)&(E", "s)&(f", - "s)&(k", - "s)&(n", "s)&(s", "s)&(v", + "s)&1", + "s)&1&", "s)&1B", "s)&1U", + "s)&1c", "s)&1f", "s)&1o", "s)&f(", "s)&o(", + "s)&s", + "s)&s&", "s)&sB", "s)&sU", + "s)&sc", "s)&sf", "s)&so", + "s)&v", + "s)&v&", "s)&vB", "s)&vU", + "s)&vc", "s)&vf", "s)&vo", - "s)()s", - "s)()v", "s))&(", "s))&1", "s))&f", @@ -2120,45 +3481,54 @@ static const char* sql_fingerprints[] = { "s))&v", "s)))&", "s))))", + "s))),", "s)));", "s)))B", + "s)))E", "s)))U", - "s)))c", "s)))k", "s)))o", - "s));c", - "s));k", + "s)),(", + "s));E", "s))B1", + "s))Bf", "s))Bs", "s))Bv", - "s))Uk", - "s))Un", - "s))c", + "s))E1", + "s))Ef", + "s))Es", + "s))Ev", + "s))U(", + "s))UE", "s))k1", - "s))kk", + "s))kf", + "s))kn", "s))ks", "s))kv", "s))o(", "s))o1", + "s))oE", "s))of", - "s))ok", "s))on", "s))os", "s))ov", + "s),((", "s),(1", + "s),(f", "s),(s", "s),(v", - "s);c", - "s);k&", - "s);k(", - "s);kf", - "s);kk", - "s);kn", - "s);ko", + "s);E&", + "s);E(", + "s);E1", + "s);Ef", + "s);Eo", + "s);Es", + "s);Ev", "s)B1", "s)B1&", "s)B1c", "s)B1o", + "s)Bf(", "s)Bs", "s)Bs&", "s)Bsc", @@ -2167,493 +3537,1018 @@ static const char* sql_fingerprints[] = { "s)Bv&", "s)Bvc", "s)Bvo", - "s)U(k", - "s)Uk(", - "s)Uk1", - "s)Ukf", - "s)Ukk", - "s)Ukn", - "s)Uko", - "s)Uks", - "s)Ukv", - "s)Unk", - "s)c", - "s)k1", - "s)k1c", + "s)E1c", + "s)E1o", + "s)Ef(", + "s)Esc", + "s)Eso", + "s)Evc", + "s)Evo", + "s)U((", + "s)U(E", + "s)UE(", + "s)UE1", + "s)UEf", + "s)UEk", + "s)UEn", + "s)UEs", + "s)UEv", + "s)k1&", + "s)k1;", + "s)k1B", + "s)k1E", + "s)k1U", "s)k1o", - "s)kks", - "s)kkv", - "s)ks", - "s)ksc", + "s)kf(", + "s)knk", + "s)ks&", + "s)ks;", + "s)ksB", + "s)ksE", + "s)ksU", "s)kso", - "s)kv", - "s)kvc", + "s)kv&", + "s)kv;", + "s)kvB", + "s)kvE", + "s)kvU", "s)kvo", - "s)o(1", - "s)o(k", + "s)o((", "s)o(n", - "s)o(s", - "s)o(v", - "s)o1B", + "s)o1", + "s)o1)", "s)o1U", - "s)o1f", - "s)o1k", + "s)o1c", "s)o1o", + "s)oE(", "s)of(", - "s)ok(", - "s)ok1", - "s)oks", - "s)okv", + "s)on", "s)on&", + "s)onc", + "s)os", "s)os)", - "s)osB", "s)osU", - "s)osf", - "s)osk", + "s)osc", "s)oso", + "s)ov", "s)ov)", - "s)ovB", "s)ovU", - "s)ovf", - "s)ovk", + "s)ovc", "s)ovo", + "s,(((", + "s,((E", + "s,((f", + "s,(E(", + "s,(E1", + "s,(Ef", + "s,(Es", + "s,(Ev", "s,(f(", - "s,(k(", - "s,(k1", - "s,(kf", - "s,(ks", - "s,(kv", + "s,1))", "s,1),", "s,1)o", "s,1B1", + "s,1Bf", "s,1Bs", "s,1Bv", - "s,1Uk", + "s,1UE", + "s,1of", + "s,1os", + "s,1ov", + "s,f((", "s,f(1", + "s,f(f", "s,f(s", "s,f(v", + "s,s))", "s,s),", "s,s)o", "s,sB1", + "s,sBf", "s,sBs", "s,sBv", - "s,sUk", + "s,sUE", + "s,so1", + "s,sof", + "s,son", + "s,sos", + "s,sov", + "s,v))", "s,v),", "s,v)o", "s,vB1", + "s,vBf", "s,vBs", "s,vBv", - "s,vUk", - "s:o1)", - "s:os)", - "s:ov)", - "s;c", - "s;k&k", - "s;k((", - "s;k(1", - "s;k(o", - "s;k(s", - "s;k(v", - "s;k1,", - "s;k1o", - "s;k;", - "s;k[k", - "s;k[n", - "s;kf(", - "s;kkn", - "s;kks", - "s;kkv", - "s;kn(", - "s;kn,", - "s;knc", - "s;knk", - "s;knn", - "s;ko(", - "s;kok", - "s;ks,", - "s;ksc", - "s;ksk", - "s;kso", - "s;kv,", - "s;kvc", - "s;kvk", - "s;kvo", + "s,vUE", + "s,vo1", + "s,vof", + "s,von", + "s,vos", + "s,vov", + "s1:1:", + "s1:1o", + "s1:f(", + "s1:s:", + "s1:so", + "s1:v:", + "s1:vo", + "s1f((", + "s1f(1", + "s1f(f", + "s1f(s", + "s1f(v", + "s1of(", + "s1os1", + "s1osf", + "s1oso", + "s1osv", + "s1ovf", + "s1ovo", + "s1ovs", + "s1sc", + "s1so1", + "s1sof", + "s1son", + "s1sos", + "s1sov", + "s1v", + "s1vc", + "s1vo1", + "s1vof", + "s1von", + "s1vos", + "s1vov", + "s:n:1", + "s:n:f", + "s:n:s", + "s:n:v", + "s;E&k", + "s;E((", + "s;E(1", + "s;E(E", + "s;E(f", + "s;E(s", + "s;E(v", + "s;E1,", + "s;E1;", + "s;E1E", + "s;E1c", + "s;E1o", + "s;E;", + "s;E;c", + "s;EEn", + "s;Ef(", + "s;En,", + "s;EnE", + "s;Enc", + "s;Enk", + "s;Eo(", + "s;Es,", + "s;Es;", + "s;EsE", + "s;Esc", + "s;Eso", + "s;Ev,", + "s;Ev;", + "s;EvE", + "s;Evc", + "s;Evo", "s;n:k", "sB1", + "sB1&1", + "sB1&f", "sB1&s", "sB1&v", "sB1,1", + "sB1,f", "sB1,n", "sB1,s", "sB1,v", - "sB1Uk", + "sB1UE", "sB1c", "sB1k1", + "sB1kf", "sB1ks", "sB1kv", + "sB1of", "sB1os", "sB1ov", + "sBE((", + "sBE(1", + "sBE(f", + "sBE(s", + "sBE(v", + "sBf((", "sBf(1", "sBf(f", "sBf(s", "sBf(v", - "sBk(1", - "sBk(s", - "sBk(v", "sBn,n", "sBnk1", + "sBnkf", "sBnks", "sBnkv", "sBs", + "sBs&1", + "sBs&f", "sBs&s", "sBs&v", "sBs,1", + "sBs,f", "sBs,n", "sBs,s", "sBs,v", - "sBsUk", + "sBsUE", "sBsc", "sBsk1", + "sBskf", "sBsks", "sBskv", + "sBso1", + "sBsof", + "sBson", "sBsos", "sBsov", "sBv", + "sBv&1", + "sBv&f", "sBv&s", "sBv&v", "sBv,1", + "sBv,f", "sBv,n", "sBv,s", "sBv,v", - "sBvUk", + "sBvUE", "sBvc", "sBvk1", + "sBvkf", "sBvks", "sBvkv", + "sBvo1", + "sBvof", + "sBvon", "sBvos", "sBvov", - "sU((k", - "sU(k(", - "sU(k1", - "sU(kf", - "sU(kk", - "sU(kn", - "sU(ks", - "sU(kv", + "sE1c", + "sE1of", + "sE1os", + "sE1ov", + "sEU1,", + "sEU1o", + "sEUEf", + "sEUf(", + "sEUs,", + "sEUso", + "sEUv,", + "sEUvo", + "sEf((", + "sEf(1", + "sEf(f", + "sEf(s", + "sEf(v", + "sEnEn", + "sEokn", + "sEsc", + "sEso1", + "sEsof", + "sEson", + "sEsos", + "sEsov", + "sEvc", + "sEvo1", + "sEvof", + "sEvon", + "sEvos", + "sEvov", + "sU", + "sU(((", + "sU((E", + "sU(E(", + "sU(E1", + "sU(Ef", + "sU(En", + "sU(Es", + "sU(Ev", "sU1,1", + "sU1,f", "sU1,s", "sU1,v", + "sU1of", + "sU1os", + "sU1ov", + "sUE", + "sUE((", + "sUE(1", + "sUE(E", + "sUE(f", + "sUE(s", + "sUE(v", + "sUE1", + "sUE1&", + "sUE1,", + "sUE1c", + "sUE1f", + "sUE1k", + "sUE1n", + "sUE1o", + "sUEc", + "sUEf", + "sUEf(", + "sUEf,", + "sUEfc", + "sUEk1", + "sUEkf", + "sUEkn", + "sUEks", + "sUEkv", + "sUEn&", + "sUEn,", + "sUEn1", + "sUEnc", + "sUEnf", + "sUEnk", + "sUEno", + "sUEok", + "sUEs", + "sUEs&", + "sUEs,", + "sUEsc", + "sUEsf", + "sUEsk", + "sUEsn", + "sUEso", + "sUEv", + "sUEv&", + "sUEv,", + "sUEvc", + "sUEvf", + "sUEvk", + "sUEvn", + "sUEvo", "sUc", - "sUk", - "sUk(1", - "sUk(k", - "sUk(n", - "sUk(s", - "sUk(v", - "sUk1", - "sUk1&", - "sUk1,", - "sUk1c", - "sUk1f", - "sUk1k", - "sUk1n", - "sUk1o", - "sUkf", - "sUkf(", - "sUkf,", - "sUkk(", - "sUkk,", - "sUkk1", - "sUkkk", - "sUkkn", - "sUkks", - "sUkkv", - "sUkn&", - "sUkn(", - "sUkn,", - "sUkn1", - "sUknc", - "sUknk", - "sUkno", - "sUkns", - "sUknv", - "sUko1", - "sUkok", - "sUkos", - "sUkov", - "sUks", - "sUks&", - "sUks,", - "sUksc", - "sUksf", - "sUksk", - "sUksn", - "sUkso", - "sUkv", - "sUkv&", - "sUkv,", - "sUkvc", - "sUkvf", - "sUkvk", - "sUkvn", - "sUkvo", - "sUn(k", + "sUf((", + "sUf(1", + "sUf(f", + "sUf(s", + "sUf(v", + "sUk((", + "sUk(E", "sUn,1", + "sUn,f", "sUn,s", "sUn,v", "sUn1,", - "sUnk(", - "sUnk1", - "sUnkf", - "sUnks", - "sUnkv", - "sUno1", - "sUnos", - "sUnov", - "sUns,", - "sUnv,", + "sUn1o", + "sUnE1", + "sUnEf", + "sUnEs", + "sUnEv", + "sUnc", + "sUnf(", + "sUo((", + "sUo(E", "sUon1", - "sUons", - "sUonv", + "sUonf", "sUs,1", + "sUs,f", "sUs,s", "sUs,v", + "sUso1", + "sUsof", + "sUson", + "sUsos", + "sUsov", "sUv,1", + "sUv,f", "sUv,s", "sUv,v", + "sUvo1", + "sUvof", + "sUvon", + "sUvos", + "sUvov", "sc", + "sf(((", + "sf(()", + "sf((1", + "sf((f", + "sf((n", + "sf((s", + "sf((v", + "sf())", "sf()k", "sf(1)", + "sf(1o", + "sf(f(", "sf(n,", "sf(s)", + "sf(so", "sf(v)", + "sf(vo", + "sk(((", + "sk((1", + "sk((f", + "sk((s", + "sk((v", + "sk(1)", + "sk(1o", + "sk(f(", + "sk(s)", + "sk(so", + "sk(v)", + "sk(vo", "sk)&(", "sk)&1", "sk)&f", "sk)&s", "sk)&v", - "sk);k", + "sk))&", + "sk)))", + "sk));", + "sk))B", + "sk))E", + "sk))U", + "sk))k", + "sk))o", + "sk);E", "sk)B1", + "sk)Bf", "sk)Bs", "sk)Bv", - "sk)Uk", - "sk)Un", - "sk)k1", - "sk)kk", - "sk)ks", - "sk)kv", - "sk)o(", - "sk)o1", - "sk)of", - "sk)ok", - "sk)os", - "sk)ov", + "sk)E1", + "sk)Ef", + "sk)Es", + "sk)Ev", + "sk)UE", + "sk)oE", + "sk1", + "sk1&(", "sk1&1", + "sk1&f", + "sk1&o", "sk1&s", "sk1&v", + "sk1;E", + "sk1B1", + "sk1Bf", + "sk1Bs", + "sk1Bv", + "sk1E1", + "sk1Ef", + "sk1Es", + "sk1Ev", "sk1U(", - "sk1Uk", + "sk1UE", "sk1c", - "sk1o1", + "sk1oE", + "sk1of", "sk1os", "sk1ov", - "skU1,", - "skUs,", - "skUv,", + "skf((", "skf(1", + "skf(f", "skf(s", "skf(v", - "skk(1", - "skk(s", - "skk(v", - "skks", - "skksc", - "skkv", - "skkvc", - "sknkn", + "sknc", + "sks", + "sks&(", "sks&1", + "sks&f", + "sks&o", "sks&s", "sks&v", + "sks;E", + "sksB1", + "sksBf", + "sksBs", + "sksBv", + "sksE1", + "sksEf", + "sksEs", + "sksEv", "sksU(", - "sksUk", + "sksUE", "sksc", "skso1", + "sksoE", + "sksof", + "skson", "sksos", "sksov", + "skv", + "skv&(", "skv&1", + "skv&f", + "skv&o", "skv&s", "skv&v", + "skv;E", + "skvB1", + "skvBf", + "skvBs", + "skvBv", + "skvE1", + "skvEf", + "skvEs", + "skvEv", "skvU(", - "skvUk", + "skvUE", "skvc", "skvo1", + "skvoE", + "skvof", + "skvon", "skvos", "skvov", "sn&f(", + "sn)))", + "sn))U", + "sn))n", + "sn)UE", "sn,f(", - "snUk1", - "snUkn", - "snUks", - "snUkv", - "snk1c", - "snkf(", - "snksc", - "snkvc", + "sn1", + "sn1c", + "sn1of", + "sn1os", + "sn1ov", + "snE1c", + "snE1o", + "snEf(", + "snEsc", + "snEso", + "snEvc", + "snEvo", + "snU((", + "snU(E", + "snUE1", + "snUEf", + "snUEs", + "snUEv", + "snf((", + "snf(1", + "snf(f", + "snf(s", + "snf(v", + "sno((", + "sno(1", + "sno(f", "sno(s", "sno(v", - "sno1U", + "snof(", "snosU", + "snoso", "snovU", + "snovo", "so(((", "so((1", + "so((E", "so((f", - "so((k", + "so((n", + "so((o", "so((s", "so((v", "so(1)", "so(1o", + "so(E(", + "so(E1", + "so(EE", + "so(Ef", + "so(En", + "so(Es", + "so(Ev", "so(f(", - "so(k(", - "so(k)", - "so(k1", - "so(kc", - "so(kf", - "so(kk", - "so(kn", - "so(ko", - "so(ks", - "so(kv", "so(n)", "so(o1", + "so(of", "so(os", "so(ov", "so(s)", "so(so", "so(v)", "so(vo", + "so1", + "so1&(", "so1&1", + "so1&E", + "so1&U", + "so1&f", + "so1&k", + "so1&n", "so1&o", "so1&s", "so1&v", + "so1((", + "so1(E", + "so1(U", "so1)&", + "so1))", + "so1),", + "so1);", + "so1)B", + "so1)E", + "so1)U", + "so1)k", "so1)o", + "so1,(", + "so1,1", + "so1,f", + "so1,s", + "so1,v", + "so1:n", + "so1;E", + "so1;n", + "so1B1", + "so1BE", "so1Bf", + "so1Bn", + "so1Bs", + "so1Bv", + "so1E1", + "so1EU", + "so1Ef", + "so1En", + "so1Eo", + "so1Es", + "so1Ev", + "so1U", + "so1U(", + "so1U1", + "so1UE", + "so1Uc", + "so1Uf", "so1Uk", + "so1Un", + "so1Uo", + "so1Us", + "so1Uv", "so1c", "so1f(", + "so1k(", + "so1k)", + "so1k1", "so1kf", + "so1kn", + "so1ks", + "so1kv", + "so1n&", + "so1n,", + "so1n1", + "so1nE", + "so1nU", + "so1nf", + "so1no", "so1o(", - "so1o1", + "so1oE", + "so1oU", "so1of", "so1ok", - "so1oo", "so1os", "so1ov", + "so1s1", + "so1s:", + "so1sf", + "so1so", + "so1sv", + "so1v:", + "so1vf", + "so1vo", + "so1vs", + "soE((", + "soE(1", + "soE(f", + "soE(s", + "soE(v", + "soEUE", + "soU((", + "soU(E", + "sof((", "sof()", "sof(1", "sof(f", - "sof(k", - "sof(n", "sof(s", "sof(v", + "sok&1", + "sok&f", "sok&s", "sok&v", + "sok((", "sok(1", - "sok(k", - "sok(o", + "sok(f", "sok(s", "sok(v", - "sok1", - "sok1,", "sok1c", - "sok1k", "sok1o", - "sokUk", - "sokc", "sokf(", - "sokn,", - "soknk", - "soko(", "soko1", - "sokok", + "sokof", "sokos", "sokov", - "soks", - "soks,", "soksc", - "soksk", "sokso", - "sokv", - "sokv,", "sokvc", - "sokvk", "sokvo", + "son&(", + "son&1", + "son&E", + "son&U", + "son&f", + "son&k", + "son&n", + "son&o", + "son&s", + "son&v", + "son((", + "son(E", + "son(U", + "son)&", + "son))", + "son),", + "son);", + "son)B", + "son)E", + "son)U", + "son)k", + "son)o", + "son,(", + "son,1", + "son,f", + "son,s", + "son,v", + "son1:", + "son1f", + "son1o", + "son1s", + "son1v", + "son:n", + "son;E", + "son;n", + "sonB1", + "sonBE", + "sonBf", + "sonBn", + "sonBs", + "sonBv", + "sonE1", + "sonEU", + "sonEf", + "sonEn", + "sonEo", + "sonEs", + "sonEv", + "sonU", + "sonU(", + "sonU1", + "sonUE", + "sonUc", + "sonUf", + "sonUk", + "sonUn", + "sonUo", + "sonUs", + "sonUv", + "sonc", + "sonf(", + "sonk(", + "sonk)", "sonk1", + "sonkf", + "sonkn", "sonks", "sonkv", + "sono(", + "sonoU", + "sonof", + "sonok", "sonos", "sonov", "sos", "sos&(", "sos&1", + "sos&E", + "sos&U", + "sos&f", + "sos&k", + "sos&n", "sos&o", "sos&s", "sos&v", + "sos((", + "sos(E", + "sos(U", "sos)&", + "sos))", + "sos),", + "sos);", + "sos)B", + "sos)E", + "sos)U", + "sos)k", "sos)o", - "sos:o", + "sos,(", + "sos,1", + "sos,f", + "sos,s", + "sos,v", + "sos1:", + "sos1f", + "sos1o", + "sos1s", + "sos1v", + "sos:n", + "sos;E", + "sos;n", + "sosB1", + "sosBE", "sosBf", + "sosBn", + "sosBs", + "sosBv", + "sosE1", + "sosEU", + "sosEf", + "sosEn", + "sosEo", + "sosEs", + "sosEv", + "sosU", + "sosU(", + "sosU1", + "sosUE", + "sosUc", + "sosUf", "sosUk", + "sosUn", + "sosUo", + "sosUs", + "sosUv", "sosc", "sosf(", + "sosk(", + "sosk)", + "sosk1", "soskf", + "soskn", + "sosks", + "soskv", + "sosn&", + "sosn)", + "sosn,", + "sosn1", + "sosnE", + "sosnU", + "sosnf", + "sosno", "soso(", "soso1", + "sosoE", + "sosoU", "sosof", "sosok", - "sosoo", + "soson", "sosos", "sosov", + "sosv:", + "sosvf", "sosvo", + "sosvs", "sov", "sov&(", "sov&1", + "sov&E", + "sov&U", + "sov&f", + "sov&k", + "sov&n", "sov&o", "sov&s", "sov&v", + "sov((", + "sov(E", + "sov(U", "sov)&", + "sov))", + "sov),", + "sov);", + "sov)B", + "sov)E", + "sov)U", + "sov)k", "sov)o", - "sov:o", + "sov,(", + "sov,1", + "sov,f", + "sov,s", + "sov,v", + "sov:n", + "sov;E", + "sov;n", + "sovB1", + "sovBE", "sovBf", + "sovBn", + "sovBs", + "sovBv", + "sovE1", + "sovEU", + "sovEf", + "sovEn", + "sovEo", + "sovEs", + "sovEv", + "sovU", + "sovU(", + "sovU1", + "sovUE", + "sovUc", + "sovUf", "sovUk", + "sovUn", + "sovUo", + "sovUs", + "sovUv", "sovc", "sovf(", + "sovk(", + "sovk)", + "sovk1", "sovkf", + "sovkn", + "sovks", + "sovkv", + "sovn&", + "sovn)", + "sovn,", + "sovn1", + "sovnE", + "sovnU", + "sovnf", + "sovno", "sovo(", "sovo1", + "sovoE", + "sovoU", "sovof", "sovok", - "sovoo", + "sovon", "sovos", "sovov", + "sovs1", + "sovs:", + "sovsf", "sovso", - "sovvo", + "sovsv", + "sv:1:", + "sv:1o", + "sv:f(", + "sv:s:", + "sv:so", + "sv:v:", + "sv:vo", + "svf((", + "svf(1", + "svf(f", + "svf(s", + "svf(v", + "svo1f", + "svo1o", + "svo1s", + "svo1v", + "svof(", + "svon1", + "svonf", + "svos1", + "svosf", + "svoso", + "svosv", + "svovf", + "svovo", + "svovs", + "svs", + "svsc", + "svso1", + "svsof", + "svson", + "svsos", + "svsov", + "v&(((", + "v&((1", + "v&((E", "v&((f", - "v&((k", + "v&((s", + "v&((v", "v&(1)", "v&(1,", "v&(1o", + "v&(E1", + "v&(Ef", + "v&(Ek", + "v&(En", + "v&(Eo", + "v&(Es", + "v&(Ev", "v&(f(", - "v&(k(", - "v&(k)", - "v&(k1", - "v&(kc", - "v&(kf", - "v&(kk", - "v&(kn", - "v&(ko", - "v&(ks", - "v&(kv", "v&(s)", "v&(s,", "v&(so", @@ -2661,123 +4556,205 @@ static const char* sql_fingerprints[] = { "v&(v,", "v&(vo", "v&1", + "v&1&(", + "v&1&1", + "v&1&f", + "v&1&n", + "v&1&s", + "v&1&v", + "v&1B1", "v&1Bf", - "v&1Uk", + "v&1Bs", + "v&1Bv", + "v&1En", + "v&1U", + "v&1U(", + "v&1UE", + "v&1Uc", "v&1c", "v&1f(", + "v&1k1", + "v&1kf", + "v&1ks", + "v&1kv", "v&1o(", - "v&1o1", + "v&1oE", "v&1of", - "v&1ok", - "v&1on", "v&1oo", "v&1os", "v&1ov", + "v&1so", + "v&1vo", + "v&E((", + "v&E(1", + "v&E(f", + "v&E(o", + "v&E(s", + "v&E(v", + "v&E1k", + "v&E1o", + "v&Ef(", + "v&Ek1", + "v&Ekf", + "v&Eks", + "v&Ekv", + "v&Esk", + "v&Eso", + "v&Evk", + "v&Evo", "v&f((", "v&f()", "v&f(1", "v&f(f", - "v&f(k", "v&f(n", "v&f(s", "v&f(v", + "v&k&1", + "v&k&f", "v&k&s", "v&k&v", - "v&k(1", - "v&k(f", - "v&k(o", - "v&k(s", - "v&k(v", - "v&k1k", "v&k1o", - "v&kUk", - "v&kc", - "v&kk1", - "v&kks", - "v&kkv", + "v&kf(", "v&knk", "v&ko(", "v&ko1", + "v&kof", "v&kok", + "v&kon", "v&kos", "v&kov", - "v&ksk", "v&kso", - "v&kvk", "v&kvo", + "v&n", + "v&n&1", + "v&n&f", + "v&n&n", "v&n&s", "v&n&v", - "v&n()", - "v&no1", + "v&nc", + "v&nk1", + "v&nkf", + "v&nks", + "v&nkv", + "v&nof", "v&nos", "v&nov", + "v&o((", "v&o(1", - "v&o(k", + "v&o(f", "v&o(s", "v&o(v", + "v&o1", + "v&o1c", "v&o1o", - "v&okc", + "v&of(", "v&oko", "v&os", + "v&osc", "v&oso", "v&ov", + "v&ovc", "v&ovo", "v&s", - "v&s:o", + "v&s&(", + "v&s&1", + "v&s&f", + "v&s&n", + "v&s&s", + "v&s&v", + "v&s1o", + "v&sB1", "v&sBf", + "v&sBs", + "v&sBv", + "v&sEn", + "v&sU", "v&sU(", - "v&sUk", + "v&sUE", + "v&sUc", "v&sc", "v&sf(", + "v&sk1", + "v&skf", + "v&sks", + "v&skv", "v&so(", "v&so1", + "v&soE", "v&sof", - "v&sok", "v&son", "v&soo", "v&sos", "v&sov", "v&svo", "v&v", - "v&v:o", + "v&v&(", + "v&v&1", + "v&v&f", + "v&v&n", + "v&v&s", + "v&v&v", + "v&vB1", "v&vBf", + "v&vBs", + "v&vBv", + "v&vEn", + "v&vU", "v&vU(", - "v&vUk", + "v&vUE", + "v&vUc", "v&vc", "v&vf(", + "v&vk1", + "v&vkf", + "v&vks", + "v&vkv", "v&vo(", "v&vo1", + "v&voE", "v&vof", - "v&vok", "v&von", "v&voo", "v&vos", "v&vov", "v&vso", - "v&vvo", - "v(c", + "v((((", + "v(((E", + "v(((U", + "v((En", + "v((U(", + "v(Enk", + "v(U((", + "v(U(E", + "v)&((", "v)&(1", + "v)&(E", "v)&(f", - "v)&(k", - "v)&(n", "v)&(s", "v)&(v", + "v)&1", + "v)&1&", "v)&1B", "v)&1U", + "v)&1c", "v)&1f", "v)&1o", "v)&f(", "v)&o(", + "v)&s", + "v)&s&", "v)&sB", "v)&sU", + "v)&sc", "v)&sf", "v)&so", + "v)&v", + "v)&v&", "v)&vB", "v)&vU", + "v)&vc", "v)&vf", "v)&vo", - "v)()s", - "v)()v", "v))&(", "v))&1", "v))&f", @@ -2787,45 +4764,54 @@ static const char* sql_fingerprints[] = { "v))&v", "v)))&", "v))))", + "v))),", "v)));", "v)))B", + "v)))E", "v)))U", - "v)))c", "v)))k", "v)))o", - "v));c", - "v));k", + "v)),(", + "v));E", "v))B1", + "v))Bf", "v))Bs", "v))Bv", - "v))Uk", - "v))Un", - "v))c", + "v))E1", + "v))Ef", + "v))Es", + "v))Ev", + "v))U(", + "v))UE", "v))k1", - "v))kk", + "v))kf", + "v))kn", "v))ks", "v))kv", "v))o(", "v))o1", + "v))oE", "v))of", - "v))ok", "v))on", "v))os", "v))ov", + "v),((", "v),(1", + "v),(f", "v),(s", "v),(v", - "v);c", - "v);k&", - "v);k(", - "v);kf", - "v);kk", - "v);kn", - "v);ko", + "v);E&", + "v);E(", + "v);E1", + "v);Ef", + "v);Eo", + "v);Es", + "v);Ev", "v)B1", "v)B1&", "v)B1c", "v)B1o", + "v)Bf(", "v)Bs", "v)Bs&", "v)Bsc", @@ -2834,490 +4820,938 @@ static const char* sql_fingerprints[] = { "v)Bv&", "v)Bvc", "v)Bvo", - "v)U(k", - "v)Uk(", - "v)Uk1", - "v)Ukf", - "v)Ukk", - "v)Ukn", - "v)Uko", - "v)Uks", - "v)Ukv", - "v)Unk", - "v)c", - "v)k1", - "v)k1c", + "v)E1c", + "v)E1o", + "v)Ef(", + "v)Esc", + "v)Eso", + "v)Evc", + "v)Evo", + "v)U((", + "v)U(E", + "v)UE(", + "v)UE1", + "v)UEf", + "v)UEk", + "v)UEn", + "v)UEs", + "v)UEv", + "v)k1&", + "v)k1;", + "v)k1B", + "v)k1E", + "v)k1U", "v)k1o", - "v)kks", - "v)kkv", + "v)kf(", "v)knk", - "v)ks", - "v)ksc", + "v)ks&", + "v)ks;", + "v)ksB", + "v)ksE", + "v)ksU", "v)kso", - "v)kv", - "v)kvc", + "v)kv&", + "v)kv;", + "v)kvB", + "v)kvE", + "v)kvU", "v)kvo", - "v)o(1", - "v)o(k", + "v)o((", "v)o(n", - "v)o(s", - "v)o(v", + "v)o1", "v)o1)", - "v)o1B", "v)o1U", - "v)o1f", - "v)o1k", + "v)o1c", "v)o1o", + "v)oE(", "v)of(", - "v)ok(", - "v)ok1", - "v)oks", - "v)okv", + "v)on", "v)on&", + "v)onc", + "v)os", "v)os)", - "v)osB", "v)osU", - "v)osf", - "v)osk", + "v)osc", "v)oso", + "v)ov", "v)ov)", - "v)ovB", "v)ovU", - "v)ovf", - "v)ovk", + "v)ovc", "v)ovo", + "v,(((", + "v,((E", + "v,((f", + "v,(E(", + "v,(E1", + "v,(Ef", + "v,(Es", + "v,(Ev", "v,(f(", - "v,(k(", - "v,(k1", - "v,(kf", - "v,(ks", - "v,(kv", + "v,1))", "v,1),", "v,1)o", "v,1B1", + "v,1Bf", "v,1Bs", "v,1Bv", - "v,1Uk", + "v,1UE", + "v,1of", + "v,1os", + "v,1ov", + "v,f((", "v,f(1", + "v,f(f", "v,f(s", "v,f(v", + "v,s))", "v,s),", "v,s)o", "v,sB1", + "v,sBf", "v,sBs", "v,sBv", - "v,sUk", + "v,sUE", + "v,so1", + "v,sof", + "v,son", + "v,sos", + "v,sov", + "v,v))", "v,v),", "v,v)o", "v,vB1", + "v,vBf", "v,vBs", "v,vBv", - "v,vUk", - "v:o1)", - "v:os)", - "v:ov)", - "v;c", - "v;k&k", - "v;k((", - "v;k(1", - "v;k(o", - "v;k(s", - "v;k(v", - "v;k1,", - "v;k1o", - "v;k;", - "v;k[k", - "v;k[n", - "v;kf(", - "v;kkn", - "v;kks", - "v;kkv", - "v;kn(", - "v;kn,", - "v;knc", - "v;knk", - "v;knn", - "v;ko(", - "v;kok", - "v;ks,", - "v;ksc", - "v;ksk", - "v;kso", - "v;kv,", - "v;kvc", - "v;kvk", - "v;kvo", + "v,vUE", + "v,vo1", + "v,vof", + "v,von", + "v,vos", + "v,vov", + "v:n:1", + "v:n:f", + "v:n:s", + "v:n:v", + "v;E&k", + "v;E((", + "v;E(1", + "v;E(E", + "v;E(f", + "v;E(s", + "v;E(v", + "v;E1,", + "v;E1;", + "v;E1E", + "v;E1c", + "v;E1o", + "v;E;", + "v;E;c", + "v;EEn", + "v;Ef(", + "v;En,", + "v;EnE", + "v;Enc", + "v;Enk", + "v;Eo(", + "v;Es,", + "v;Es;", + "v;EsE", + "v;Esc", + "v;Eso", + "v;Ev,", + "v;Ev;", + "v;EvE", + "v;Evc", + "v;Evo", "v;n:k", "vB1", + "vB1&1", + "vB1&f", "vB1&s", "vB1&v", "vB1,1", + "vB1,f", "vB1,n", "vB1,s", "vB1,v", - "vB1Uk", + "vB1UE", "vB1c", "vB1k1", + "vB1kf", "vB1ks", "vB1kv", + "vB1of", "vB1os", "vB1ov", + "vBE((", + "vBE(1", + "vBE(f", + "vBE(s", + "vBE(v", + "vBf((", "vBf(1", "vBf(f", "vBf(s", "vBf(v", - "vBk(1", - "vBk(s", - "vBk(v", "vBn,n", "vBnk1", + "vBnkf", "vBnks", "vBnkv", "vBs", + "vBs&1", + "vBs&f", "vBs&s", "vBs&v", "vBs,1", + "vBs,f", "vBs,n", "vBs,s", "vBs,v", - "vBsUk", + "vBsUE", "vBsc", "vBsk1", + "vBskf", "vBsks", "vBskv", + "vBso1", + "vBsof", + "vBson", "vBsos", "vBsov", "vBv", + "vBv&1", + "vBv&f", "vBv&s", "vBv&v", "vBv,1", + "vBv,f", "vBv,n", "vBv,s", "vBv,v", - "vBvUk", + "vBvUE", "vBvc", "vBvk1", + "vBvkf", "vBvks", "vBvkv", + "vBvo1", + "vBvof", + "vBvon", "vBvos", "vBvov", + "vE1c", + "vE1of", + "vE1os", + "vE1ov", + "vEU1,", + "vEU1o", + "vEUEf", + "vEUf(", + "vEUs,", + "vEUso", + "vEUv,", + "vEUvo", + "vEf((", + "vEf(1", + "vEf(f", + "vEf(s", + "vEf(v", + "vEnEn", + "vEokn", + "vEsc", + "vEso1", + "vEsof", + "vEson", + "vEsos", + "vEsov", + "vEvc", + "vEvo1", + "vEvof", + "vEvon", + "vEvos", + "vEvov", "vU", - "vU((k", - "vU(k(", - "vU(k1", - "vU(kf", - "vU(kk", - "vU(kn", - "vU(ks", - "vU(kv", + "vU(((", + "vU((E", + "vU(E(", + "vU(E1", + "vU(Ef", + "vU(En", + "vU(Es", + "vU(Ev", "vU1,1", + "vU1,f", "vU1,s", "vU1,v", + "vU1of", + "vU1os", + "vU1ov", + "vUE", + "vUE((", + "vUE(1", + "vUE(E", + "vUE(f", + "vUE(s", + "vUE(v", + "vUE1", + "vUE1&", + "vUE1,", + "vUE1c", + "vUE1f", + "vUE1k", + "vUE1n", + "vUE1o", + "vUEc", + "vUEf", + "vUEf(", + "vUEf,", + "vUEfc", + "vUEk1", + "vUEkf", + "vUEkn", + "vUEks", + "vUEkv", + "vUEn&", + "vUEn,", + "vUEn1", + "vUEnc", + "vUEnf", + "vUEnk", + "vUEno", + "vUEok", + "vUEs", + "vUEs&", + "vUEs,", + "vUEsc", + "vUEsf", + "vUEsk", + "vUEsn", + "vUEso", + "vUEv", + "vUEv&", + "vUEv,", + "vUEvc", + "vUEvf", + "vUEvk", + "vUEvn", + "vUEvo", "vUc", - "vUk", - "vUk(1", - "vUk(k", - "vUk(n", - "vUk(s", - "vUk(v", - "vUk1", - "vUk1&", - "vUk1,", - "vUk1c", - "vUk1f", - "vUk1k", - "vUk1n", - "vUk1o", - "vUkf", - "vUkf(", - "vUkf,", - "vUkk(", - "vUkk,", - "vUkk1", - "vUkkk", - "vUkkn", - "vUkks", - "vUkkv", - "vUkn&", - "vUkn(", - "vUkn,", - "vUkn1", - "vUknc", - "vUknk", - "vUkno", - "vUkns", - "vUknv", - "vUko1", - "vUkok", - "vUkos", - "vUkov", - "vUks", - "vUks&", - "vUks,", - "vUksc", - "vUksf", - "vUksk", - "vUksn", - "vUkso", - "vUkv", - "vUkv&", - "vUkv,", - "vUkvc", - "vUkvf", - "vUkvk", - "vUkvn", - "vUkvo", - "vUn(k", + "vUf((", + "vUf(1", + "vUf(f", + "vUf(s", + "vUf(v", + "vUk((", + "vUk(E", "vUn,1", + "vUn,f", "vUn,s", "vUn,v", "vUn1,", - "vUnk(", - "vUnk1", - "vUnkf", - "vUnks", - "vUnkv", - "vUno1", - "vUnos", - "vUnov", - "vUns,", - "vUnv,", + "vUn1o", + "vUnE1", + "vUnEf", + "vUnEs", + "vUnEv", + "vUnc", + "vUnf(", + "vUo((", + "vUo(E", "vUon1", - "vUons", - "vUonv", + "vUonf", "vUs,1", + "vUs,f", "vUs,s", "vUs,v", + "vUso1", + "vUsof", + "vUson", + "vUsos", + "vUsov", "vUv,1", + "vUv,f", "vUv,s", "vUv,v", + "vUvo1", + "vUvof", + "vUvon", + "vUvos", + "vUvov", "vc", + "vf(((", + "vf(()", + "vf((1", + "vf((f", + "vf((n", + "vf((s", + "vf((v", + "vf())", "vf()k", "vf(1)", + "vf(1o", + "vf(f(", "vf(n,", "vf(s)", + "vf(so", "vf(v)", + "vf(vo", + "vk(((", + "vk((1", + "vk((f", + "vk((s", + "vk((v", + "vk(1)", + "vk(1o", + "vk(f(", + "vk(s)", + "vk(so", + "vk(v)", + "vk(vo", "vk)&(", "vk)&1", "vk)&f", "vk)&s", "vk)&v", - "vk);k", + "vk))&", + "vk)))", + "vk));", + "vk))B", + "vk))E", + "vk))U", + "vk))k", + "vk))o", + "vk);E", "vk)B1", + "vk)Bf", "vk)Bs", "vk)Bv", - "vk)Uk", - "vk)Un", - "vk)k1", - "vk)kk", - "vk)ks", - "vk)kv", - "vk)o(", - "vk)o1", - "vk)of", - "vk)ok", - "vk)os", - "vk)ov", + "vk)E1", + "vk)Ef", + "vk)Es", + "vk)Ev", + "vk)UE", + "vk)oE", + "vk1", + "vk1&(", "vk1&1", + "vk1&f", + "vk1&o", "vk1&s", "vk1&v", + "vk1;E", + "vk1B1", + "vk1Bf", + "vk1Bs", + "vk1Bv", + "vk1E1", + "vk1Ef", + "vk1Es", + "vk1Ev", "vk1U(", - "vk1Uk", + "vk1UE", "vk1c", - "vk1o1", + "vk1oE", + "vk1of", "vk1os", "vk1ov", - "vkU1,", - "vkUs,", - "vkUv,", + "vkf((", "vkf(1", + "vkf(f", "vkf(s", "vkf(v", - "vkk(1", - "vkk(s", - "vkk(v", - "vkks", - "vkksc", - "vkkv", - "vkkvc", - "vknkn", - "vkno1", - "vknov", - "vkokn", + "vknc", + "vks", + "vks&(", "vks&1", + "vks&f", + "vks&o", "vks&s", "vks&v", + "vks;E", + "vksB1", + "vksBf", + "vksBs", + "vksBv", + "vksE1", + "vksEf", + "vksEs", + "vksEv", "vksU(", - "vksUk", + "vksUE", "vksc", "vkso1", + "vksoE", + "vksof", + "vkson", "vksos", "vksov", + "vkv", + "vkv&(", "vkv&1", + "vkv&f", + "vkv&o", "vkv&s", "vkv&v", + "vkv;E", + "vkvB1", + "vkvBf", + "vkvBs", + "vkvBv", + "vkvE1", + "vkvEf", + "vkvEs", + "vkvEv", "vkvU(", - "vkvUk", + "vkvUE", "vkvc", "vkvo1", + "vkvoE", + "vkvof", + "vkvon", "vkvos", "vkvov", "vn&f(", - "vn)Uk", + "vn)))", + "vn))U", + "vn))n", + "vn)UE", "vn,f(", - "vnUk1", - "vnUkn", - "vnUks", - "vnUkv", - "vnk1c", - "vnkf(", - "vnksc", - "vnkvc", + "vn1", + "vn1c", + "vn1of", + "vn1os", + "vn1ov", + "vnE1c", + "vnE1o", + "vnEf(", + "vnEsc", + "vnEso", + "vnEvc", + "vnEvo", + "vnU((", + "vnU(E", + "vnUE1", + "vnUEf", + "vnUEs", + "vnUEv", + "vnf((", + "vnf(1", + "vnf(f", + "vnf(s", + "vnf(v", + "vno((", + "vno(1", + "vno(f", "vno(s", "vno(v", - "vno1U", + "vnof(", "vnosU", + "vnoso", "vnovU", + "vnovo", "vo(((", "vo((1", + "vo((E", "vo((f", - "vo((k", + "vo((n", + "vo((o", "vo((s", "vo((v", "vo(1)", "vo(1o", + "vo(E(", + "vo(E1", + "vo(EE", + "vo(Ef", + "vo(En", + "vo(Es", + "vo(Ev", "vo(f(", - "vo(k(", - "vo(k)", - "vo(k1", - "vo(kc", - "vo(kf", - "vo(kk", - "vo(kn", - "vo(ko", - "vo(ks", - "vo(kv", "vo(n)", "vo(o1", + "vo(of", "vo(os", "vo(ov", "vo(s)", "vo(so", "vo(v)", "vo(vo", + "vo1", + "vo1&(", "vo1&1", + "vo1&E", + "vo1&U", + "vo1&f", + "vo1&k", + "vo1&n", "vo1&o", "vo1&s", "vo1&v", + "vo1((", + "vo1(E", + "vo1(U", "vo1)&", + "vo1))", + "vo1),", + "vo1);", + "vo1)B", + "vo1)E", + "vo1)U", + "vo1)k", "vo1)o", + "vo1,(", + "vo1,1", + "vo1,f", + "vo1,s", + "vo1,v", + "vo1:n", + "vo1;E", + "vo1;n", + "vo1B1", + "vo1BE", "vo1Bf", + "vo1Bn", + "vo1Bs", + "vo1Bv", + "vo1E1", + "vo1EU", + "vo1Ef", + "vo1En", + "vo1Eo", + "vo1Es", + "vo1Ev", + "vo1U", + "vo1U(", + "vo1U1", + "vo1UE", + "vo1Uc", + "vo1Uf", "vo1Uk", + "vo1Un", + "vo1Uo", + "vo1Us", + "vo1Uv", "vo1c", "vo1f(", + "vo1k(", + "vo1k)", + "vo1k1", "vo1kf", + "vo1kn", + "vo1ks", + "vo1kv", + "vo1n&", + "vo1n)", + "vo1n,", + "vo1n1", + "vo1nE", + "vo1nU", + "vo1nf", + "vo1no", "vo1o(", - "vo1o1", + "vo1oE", + "vo1oU", "vo1of", "vo1ok", - "vo1oo", "vo1os", "vo1ov", + "vo1s1", + "vo1s:", + "vo1sf", + "vo1so", + "vo1sv", + "vo1v:", + "vo1vf", + "vo1vo", + "vo1vs", + "voE((", + "voE(1", + "voE(f", + "voE(s", + "voE(v", + "voEUE", + "voU((", + "voU(E", + "vof((", "vof()", "vof(1", "vof(f", - "vof(k", - "vof(n", "vof(s", "vof(v", + "vok&1", + "vok&f", "vok&s", "vok&v", + "vok((", "vok(1", - "vok(k", - "vok(o", + "vok(f", "vok(s", "vok(v", - "vok)U", - "vok)o", - "vok1", - "vok1,", "vok1c", - "vok1k", "vok1o", - "vokUk", - "vokc", "vokf(", - "vokn,", - "voknk", - "voko(", "voko1", - "vokok", + "vokof", "vokos", "vokov", - "voks", - "voks,", "voksc", - "voksk", "vokso", - "vokv", - "vokv,", "vokvc", - "vokvk", "vokvo", + "von&(", + "von&1", + "von&E", + "von&U", + "von&f", + "von&k", + "von&n", + "von&o", + "von&s", + "von&v", + "von((", + "von(E", + "von(U", + "von)&", + "von))", + "von),", + "von);", + "von)B", + "von)E", + "von)U", + "von)k", + "von)o", + "von,(", + "von,1", + "von,f", + "von,s", + "von,v", + "von1:", + "von1f", + "von1o", + "von1s", + "von1v", + "von:n", + "von;E", + "von;n", + "vonB1", + "vonBE", + "vonBf", + "vonBn", + "vonBs", + "vonBv", + "vonE1", + "vonEU", + "vonEf", + "vonEn", + "vonEo", + "vonEs", + "vonEv", + "vonU", + "vonU(", + "vonU1", + "vonUE", + "vonUc", + "vonUf", + "vonUk", + "vonUn", + "vonUo", + "vonUs", + "vonUv", + "vonc", + "vonf(", + "vonk(", + "vonk)", "vonk1", + "vonkf", + "vonkn", "vonks", "vonkv", - "vono1", + "vono(", + "vonoE", + "vonoU", + "vonof", + "vonok", "vonos", "vonov", "vos", "vos&(", "vos&1", + "vos&E", + "vos&U", + "vos&f", + "vos&k", + "vos&n", "vos&o", "vos&s", "vos&v", + "vos((", + "vos(E", + "vos(U", "vos)&", + "vos))", + "vos),", + "vos);", + "vos)B", + "vos)E", "vos)U", + "vos)k", "vos)o", - "vos:o", + "vos,(", + "vos,1", + "vos,f", + "vos,s", + "vos,v", + "vos1:", + "vos1f", + "vos1o", + "vos1s", + "vos1v", + "vos:n", + "vos;E", + "vos;n", + "vosB1", + "vosBE", "vosBf", + "vosBn", + "vosBs", + "vosBv", + "vosE1", + "vosEU", + "vosEf", + "vosEn", + "vosEo", + "vosEs", + "vosEv", + "vosU", + "vosU(", + "vosU1", + "vosUE", + "vosUc", + "vosUf", "vosUk", + "vosUn", + "vosUo", + "vosUs", + "vosUv", "vosc", "vosf(", + "vosk(", + "vosk)", + "vosk1", "voskf", + "voskn", + "vosks", + "voskv", + "vosn&", + "vosn)", + "vosn,", + "vosn1", + "vosnE", + "vosnU", + "vosnf", + "vosno", "voso(", "voso1", + "vosoE", + "vosoU", "vosof", "vosok", - "vosoo", + "voson", "vosos", "vosov", + "vosv:", + "vosvf", "vosvo", + "vosvs", "vov", "vov&(", "vov&1", + "vov&E", + "vov&U", + "vov&f", + "vov&k", + "vov&n", "vov&o", "vov&s", "vov&v", + "vov((", + "vov(E", + "vov(U", "vov)&", + "vov))", + "vov),", + "vov);", + "vov)B", + "vov)E", "vov)U", + "vov)k", "vov)o", - "vov:o", + "vov,(", + "vov,1", + "vov,f", + "vov,s", + "vov,v", + "vov:n", + "vov;E", + "vov;n", + "vovB1", + "vovBE", "vovBf", + "vovBn", + "vovBs", + "vovBv", + "vovE1", + "vovEU", + "vovEf", + "vovEn", + "vovEo", + "vovEs", + "vovEv", + "vovU", + "vovU(", + "vovU1", + "vovUE", + "vovUc", + "vovUf", "vovUk", + "vovUn", + "vovUo", + "vovUs", + "vovUv", "vovc", "vovf(", + "vovk(", + "vovk)", + "vovk1", "vovkf", + "vovkn", + "vovks", + "vovkv", + "vovn&", + "vovn)", + "vovn,", + "vovn1", + "vovnE", + "vovnU", + "vovnf", + "vovno", "vovo(", "vovo1", + "vovoE", + "vovoU", "vovof", "vovok", - "vovoo", + "vovon", "vovos", "vovov", + "vovs1", + "vovs:", + "vovsf", "vovso", - "vovvo", + "vovsv", }; -static const size_t sqli_fingerprints_sz = 2298; +static const size_t sqli_fingerprints_sz = 4719; #endif From 4af03f208ee5ee5ca652b80fbb4f96031ed21c1c Mon Sep 17 00:00:00 2001 From: Nick Galbreath Date: Tue, 4 Jun 2013 10:14:52 +0900 Subject: [PATCH 2/3] Update to libinjection 3.0.0-pre8 --- apache2/libinjection/libinjection.h | 86 +- apache2/libinjection/libinjection_sqli.c | 426 ++++-- apache2/libinjection/libinjection_sqli_data.h | 867 ++++++++--- apache2/libinjection/sqlparse.c | 1340 ----------------- 4 files changed, 1106 insertions(+), 1613 deletions(-) delete mode 100644 apache2/libinjection/sqlparse.c diff --git a/apache2/libinjection/libinjection.h b/apache2/libinjection/libinjection.h index 497fb2fe..9bc96e23 100644 --- a/apache2/libinjection/libinjection.h +++ b/apache2/libinjection/libinjection.h @@ -37,7 +37,7 @@ extern "C" { * See python's normalized version * http://www.python.org/dev/peps/pep-0386/#normalizedversion */ -#define LIBINJECTION_VERSION "3.0.0-pre2" +#define LIBINJECTION_VERSION "3.0.0-pre8" #define ST_MAX_SIZE 32 #define MAX_TOKENS 5 @@ -46,7 +46,13 @@ extern "C" { #define CHAR_SINGLE '\'' #define CHAR_DOUBLE '"' +#define COMMENTS_ANSI 0 +#define COMMENTS_MYSQL 1 + typedef struct { +#ifdef SWIG +%immutable; +#endif char type; char str_open; char str_close; @@ -55,6 +61,10 @@ typedef struct { } stoken_t; typedef struct { +#ifdef SWIG +%immutable; +#endif + /* input */ const char *s; size_t slen; @@ -73,13 +83,40 @@ typedef struct { /* +1 for ending null */ char pat[MAX_TOKENS + 1]; char delim; + char comment_style; + int reason; + + /* Number of ddw (dash-dash-white) comments + * These comments are in the form of + * '--[whitespace]' or '--[EOF]' + * + * All databases treat this as a comment. + */ + int stats_comment_ddw; + + /* Number of ddx (dash-dash-[notwhite]) comments + * + * ANSI SQL treats these are comments, MySQL treats this as + * two unary operators '-' '-' + * + * If you are parsing result returns FALSE and + * stats_comment_dd > 0, you should reparse with + * COMMENT_MYSQL + * + */ + int stats_comment_ddx; + + int stats_comment_c; + + int stats_folds; + } sfilter; /** * Pointer to function, takes cstr input, returns 1 for true, 0 for false */ -typedef int (*ptr_fingerprints_fn)(const char*, void* callbackarg); +typedef int (*ptr_fingerprints_fn)(sfilter*, void* callbackarg); /** * Main API: tests for SQLi in three possible contexts, no quotes, @@ -112,28 +149,51 @@ int libinjection_is_sqli(sfilter * sql_state, * CHAR_SINGLE ('), single quote context * CHAR_DOUBLE ("), double quote context * Other values will likely be ignored. - * \param ptr_fingerprints_fn is a pointer to a function - * that determines if a fingerprint is a match or not. - * \param callbackarg passed to function above * - * - * \return 1 (true) if SQLi or 0 (false) if not SQLi **in this context** + * \return pointer to sfilter.pat as convience. + * do not free! * */ -int libinjection_is_string_sqli(sfilter * sql_state, - const char *s, size_t slen, - const char delim, - ptr_fingerprints_fn fn, void* callbackarg); +const char* libinjection_sqli_fingerprint(sfilter * sql_state, + const char *s, size_t slen, + char delim, + char comment_style); /* FOR H@CKERS ONLY * */ -void libinjection_sqli_init(sfilter* sql_state, const char* str, - size_t slen, char delim); +void libinjection_sqli_init(sfilter* sql_state, + const char* s, size_t slen, + char delim, char comment_style); int libinjection_sqli_tokenize(sfilter * sql_state, stoken_t *ouput); +/** The built-in default function to match fingerprints + * and do false negative/positive analysis. This calls the following + * two functions. With this, you other-ride one part or the other. + * + * return libinjection_sqli_blacklist(sql_state, callbackarg) && + * libinject_sqli_not_whitelist(sql_state, callbackarg); + * + * \param sql_state should be filled out after libinjection_sqli_fingerprint is called + * \param callbackarg is unused but here to be used with API. + */ +int libinjection_sqli_check_fingerprint(sfilter *sql_state, void* callbackarg); + +/* Given a pattern determine if it's a SQLi pattern. + * + * \return TRUE if sqli, false otherwise + */ +int libinjection_sqli_blacklist(sfilter* sql_state); + +/* Given a positive match for a pattern (i.e. pattern is SQLi), this function + * does additional analysis to reduce false positives. + * + * \return TRUE if sqli, false otherwise + */ +int libinjection_sqli_not_whitelist(sfilter* sql_state); + #ifdef __cplusplus } #endif diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index 4067c223..022e8dc5 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -47,16 +47,13 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) if (haystack_len < 2) { return NULL; } - if (c0 == c1) { - return NULL; - } while (cur < last) { if (cur[0] == c0) { if (cur[1] == c1) { return cur; } else { - cur += 2; + cur += 2; //(c0 == c1) ? 1 : 2; } } else { cur += 1; @@ -66,6 +63,24 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) return NULL; } +/** + */ +static const char * +my_memmem(const char* haystack, size_t hlen, const char* needle, size_t nlen) +{ + assert(haystack); + assert(needle); + assert(nlen > 1); + const char* cur; + const char* last = haystack + hlen - nlen; + for (cur = haystack; cur <= last; ++cur) { + if (cur[0] == needle[0] && memcmp(cur, needle, nlen) == 0) { + return cur; + } + } + return NULL; +} + /** Find largest string containing certain characters. * * C Standard library 'strspn' only works for 'c-strings' (null terminated) @@ -107,6 +122,17 @@ strlencspn(const char *s, size_t len, const char *accept) } return len; } +static int char_is_white(char ch) { + /* ' ' space is 0x32 + '\t 0x09 \011 horizontal tab + '\n' 0x0a \012 new line + '\v' 0x0b \013 verical tab + '\f' 0x0c \014 new page + '\r' 0x0d \015 carriage return + 0xa0 \240 is latin1 + */ + return strchr(" \t\n\v\f\r\240", ch) != NULL; +} /* * ASCII half-case-insenstive compare! @@ -203,17 +229,6 @@ static int bsearch_cstrcase(const char *key, const char *base[], size_t nmemb) } } -/** - * - */ -#define UNUSED(x) (void)(x) - -static int is_sqli_pattern(const char* key, void* callbackarg) -{ - UNUSED(callbackarg); - return bsearch_cstr(key, sql_fingerprints, sqli_fingerprints_sz); -} - /** * * @@ -262,10 +277,7 @@ static char is_keyword(const char* key) static void st_clear(stoken_t * st) { - st->type = CHAR_NULL; - st->str_open = CHAR_NULL; - st->str_close = CHAR_NULL; - st->val[0] = CHAR_NULL; + memset(st, 0, sizeof(stoken_t)); } static void st_assign_char(stoken_t * st, const char stype, const char value) @@ -275,8 +287,8 @@ static void st_assign_char(stoken_t * st, const char stype, const char value) st->val[1] = CHAR_NULL; } -static void st_assign(stoken_t * st, const char stype, const char *value, - size_t len) +static void st_assign(stoken_t * st, const char stype, + const char *value, size_t len) { size_t last = len < ST_MAX_SIZE ? len : (ST_MAX_SIZE - 1); st->type = stype; @@ -367,13 +379,28 @@ static size_t parse_dash(sfilter * sf) const size_t slen = sf->slen; size_t pos = sf->pos; + /* + * five cases + * 1) --[white] this is always a SQL comment + * 2) --[EOF] this is a comment + * 3) --[notwhite] in MySQL this is NOT a comment but two unary operators + * 4) --[notwhite] everyone else thinks this is a comment + * 5) -[not dash] '-' is a unary operator + */ - size_t pos1 = pos + 1; - if (pos1 < slen && cs[pos1] == '-') { + if (pos + 2 < slen && cs[pos + 1] == '-' && char_is_white(cs[pos+2]) ) { + return parse_eol_comment(sf); + } else if (pos +2 == slen && cs[pos + 1] == '-') { + return parse_eol_comment(sf); + } else if (pos + 1 < slen && cs[pos + 1] == '-' && sf->comment_style == COMMENTS_ANSI) { + /* --[not-white] not-white case: + * + */ + sf->stats_comment_ddx += 1; return parse_eol_comment(sf); } else { st_assign_char(sf->current, 'o', '-'); - return pos1; + return pos + 1; } } @@ -582,7 +609,7 @@ static size_t parse_string_core(const char *cs, const size_t len, size_t pos, st_assign(st, 's', cs + pos + offset, len - pos - offset); st->str_close = CHAR_NULL; return len; - } else if (*(qpos - 1) != '\\') { + } else if (qpos == cs || *(qpos - 1) != '\\') { /* * ending quote is not escaped.. copy and end */ @@ -673,42 +700,156 @@ static size_t parse_string_tick(sfilter *sf) } } -static size_t parse_word(sfilter * sf) +/** MySQL ad-hoc character encoding + * + * if something starts with a underscore + * check to see if it's in this form + * _[a-z0-9] and if it's a character encoding + * If not, let the normal 'word parser' + * handle it. + */ +static size_t parse_underscore(sfilter *sf) { const char *cs = sf->s; + size_t slen = sf->slen; size_t pos = sf->pos; - char *dot; char ch; - size_t slen = - strlencspn(cs + pos, sf->slen - pos, - " .`<>:\\?=@!#~+-*/&|^%(),';\r\n\t\"\013\014"); - st_assign(sf->current, 'n', cs + pos, slen); + size_t xlen = strlenspn(cs + pos + 1, slen - pos - 1, + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + if (xlen == 0) { + return parse_word(sf); + } + st_assign(sf->current, 'n', cs + pos, xlen); + ch = is_keyword(sf->current->val); + if (ch == 't') { + sf->current->type = 't'; + return xlen + 1; + } + return parse_word(sf); +} - dot = strchr(sf->current->val, '.'); - if (dot != NULL) { - *dot = '\0'; +static size_t parse_ustring(sfilter * sf) +{ + const char *cs = sf->s; + size_t slen = sf->slen; + size_t pos = sf->pos; - ch = is_keyword(sf->current->val); + if (pos + 2 < slen && cs[pos+1] == '&' && cs[pos+2] == '\'') { + sf->pos += 2; + pos = parse_string(sf); + sf->current->str_open = 'u'; + if (sf->current->str_close == '\'') { + sf->current->str_close = 'u'; + } + return pos; + } else { + return parse_word(sf); + } +} - if (ch == 'k' || ch == 'o' || ch == 'E') { - /* - * we got something like "SELECT.1" - */ - sf->current->type = ch; - return pos + strlen(sf->current->val); - } else { - /* - * something else, put back dot - */ - *dot = '.'; +static size_t parse_qstring_core(sfilter * sf, int offset) +{ + char ch; + const char *strend; + const char *cs = sf->s; + size_t slen = sf->slen; + size_t pos = sf->pos + offset; + + /* if we are already at end of string.. + if current char is not q or Q + if we don't have 2 more chars + if char2 != a single quote + then, just treat as word + */ + if (pos >= slen || + (cs[pos] != 'q' && cs[pos] != 'Q') || + pos + 2 >= slen || + cs[pos + 1] != '\'') { + return parse_word(sf); + } + + ch = cs[pos + 2]; + if (ch < 33 && ch > 127) { + return parse_word(sf); + } + switch (ch) { + case '(' : ch = ')'; break; + case '[' : ch = ']'; break; + case '{' : ch = '}'; break; + case '<' : ch = '>'; break; + } + + strend = memchr2(cs + pos + 3, slen - pos - 3, ch, '\''); + if (strend == NULL) { + st_assign(sf->current, 's', cs + pos + 3, slen - pos - 3); + sf->current->str_open = 'q'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + st_assign(sf->current, 's', cs + pos + 3, strend - cs - pos - 3); + sf->current->str_open = 'q'; + sf->current->str_close = 'q'; + return (strend - cs) + 2; + } +} + +/* + * Oracle's q string + */ +static size_t parse_qstring(sfilter * sf) +{ + return parse_qstring_core(sf, 0); +} + +/* + * Oracle's nq string + */ +static size_t parse_nqstring(sfilter * sf) +{ + return parse_qstring_core(sf, 1); +} + +static size_t parse_word(sfilter * sf) +{ + char ch; + char delim; + size_t i; + const char *cs = sf->s; + size_t pos = sf->pos; + size_t wlen = strlencspn(cs + pos, sf->slen - pos, + " <>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r\""); + + st_assign(sf->current, 'n', cs + pos, wlen); + + /* now we need to look inside what we good for "." and "`" + * and see if what is before is a keyword or not + */ + for (i =0; i < strlen(sf->current->val); ++i) { + delim = sf->current->val[i]; + if (delim == '.' || delim == '`') { + sf->current->val[i] = CHAR_NULL; + ch = is_keyword(sf->current->val); + if (ch == 'k' || ch == 'o' || ch == 'E') { + /* needed for swig */ + st_clear(sf->current); + /* + * we got something like "SELECT.1" + * or SELECT`column` + */ + st_assign(sf->current, ch, cs + pos, i); + return pos + i; + } else { + /* restore character */ + sf->current->val[i] = delim; + } } } /* * do normal lookup with word including '.' */ - if (slen < ST_MAX_SIZE) { + if (wlen < ST_MAX_SIZE) { ch = is_keyword(sf->current->val); @@ -717,7 +858,7 @@ static size_t parse_word(sfilter * sf) } sf->current->type = ch; } - return pos + slen; + return pos + wlen; } /* MySQL backticks are a cross between string and @@ -794,8 +935,7 @@ static size_t parse_var(sfilter * sf) xlen = strlencspn(cs + pos, slen - pos, - " <>:\\?=@!#~+-*/&|^%(),';\r\n\t\"\013\014"); -// "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$"); + " <>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r'`\""); if (xlen == 0) { st_assign(sf->current, 'v', cs + pos, 0); return pos; @@ -807,21 +947,73 @@ static size_t parse_var(sfilter * sf) static size_t parse_money(sfilter *sf) { + const char* strend; const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; size_t xlen; + if (pos + 1 == slen) { + /* end of line */ + st_assign_char(sf->current, 'n', '$'); + return slen; + } + /* * $1,000.00 or $1.000,00 ok! * This also parses $....,,,111 but that's ok */ + xlen = strlenspn(cs + pos + 1, slen - pos - 1, "0123456789.,"); if (xlen == 0) { - /* - * just ignore '$' - */ - return pos + 1; + if (cs[pos + 1] == '$') { + /* we have $$ .. find ending $$ and make string */ + strend = memchr2(cs + pos + 2, slen - pos -2, '$', '$'); + if (strend == NULL) { + /* fell off edge */ + st_assign(sf->current, 's', cs + pos + 2, slen - (pos + 2)); + sf->current->str_open = '$'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + st_assign(sf->current, 's', cs + pos + 2, strend - (cs + pos + 2)); + sf->current->str_open = '$'; + sf->current->str_close = '$'; + return strend - cs + 2; + } + } else { + /* ok it's not a number or '$$', but maybe it's pgsql "$ quoted strings" */ + xlen = strlenspn(cs + pos + 1, slen - pos - 1, "abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + if (xlen == 0) { + /* hmm it's "$" _something_ .. just add $ and keep going*/ + st_assign_char(sf->current, 'n', '$'); + return pos + 1; + } + /* we have $foobar????? */ + /* is it $foobar$ */ + if (pos + xlen + 1 == slen || cs[pos+xlen+1] != '$') { + /* not $foobar$, or fell off edge */ + st_assign_char(sf->current, 'n', '$'); + return pos + 1; + } + + /* we have $foobar$ ... find it again */ + strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); + + if (strend == NULL) { + /* fell off edge */ + st_assign(sf->current, 's', cs+pos+xlen+2, slen - pos - xlen - 2); + sf->current->str_open = '$'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + /* got one */ + st_assign(sf->current, 's', cs+pos+xlen+2, strend - (cs + pos + xlen + 2)); + sf->current->str_open = '$'; + sf->current->str_close = '$'; + return (strend + xlen + 2) - cs; + } + } } else { st_assign(sf->current, '1', cs + pos, 1 + xlen); return pos + 1 + xlen; @@ -950,12 +1142,13 @@ int libinjection_sqli_tokenize(sfilter * sf, stoken_t *current) * Initializes parsing state * */ -void libinjection_sqli_init(sfilter * sf, const char *s, size_t len, char delim) +void libinjection_sqli_init(sfilter * sf, const char *s, size_t len, char delim, char comment_style) { memset(sf, 0, sizeof(sfilter)); sf->s = s; sf->slen = len; sf->delim = delim; + sf->comment_style = comment_style; } /** See if two tokens can be merged since they are compound SQL phrases. @@ -984,7 +1177,7 @@ static int syntax_merge_words(stoken_t * a, stoken_t * b) if (! (a->type == 'k' || a->type == 'n' || a->type == 'o' - || a->type == 'U' || a->type == 'E')) { + || a->type == 'U' || a->type == 'E' || a->type == 't')) { return FALSE; } @@ -1083,15 +1276,18 @@ int filter_fold(sfilter * sf) */ if (sf->tokenvec[left].type == 's' && sf->tokenvec[left+1].type == 's') { pos -= 1; + sf->stats_folds += 1; continue; } else if (sf->tokenvec[left].type =='o' && st_is_unary_op(&sf->tokenvec[left+1])) { pos -= 1; + sf->stats_folds += 1; if (left > 0) { left -= 1; } continue; } else if (sf->tokenvec[left].type =='(' && st_is_unary_op(&sf->tokenvec[left+1])) { pos -= 1; + sf->stats_folds += 1; if (left > 0) { left -= 1; } @@ -1121,8 +1317,16 @@ int filter_fold(sfilter * sf) sf->tokenvec[left].type = 'f'; continue; #endif + } else if (sf->tokenvec[left].type == 't' && + (sf->tokenvec[left+1].type == 'n' || sf->tokenvec[left+1].type == '1' || + sf->tokenvec[left+1].type == 'v' || sf->tokenvec[left+1].type == 's')) { + st_copy(&sf->tokenvec[left], &sf->tokenvec[left+1]); + pos -= 1; + sf->stats_folds += 1; + continue; } + /* all cases of handing 2 tokens is done and nothing matched. Get one more token */ @@ -1171,13 +1375,18 @@ int filter_fold(sfilter * sf) (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n')) { pos -= 2; continue; -#if 0 - } else if ((sf->tokenvec[left].type == 'n' || sf->tokenvec[left].type == '1') && + } else if ((sf->tokenvec[left].type == 'n' || sf->tokenvec[left].type == '1' || + sf->tokenvec[left].type == 'v' || sf->tokenvec[left].type == 's') && + sf->tokenvec[left+1].type == 'o' && + sf->tokenvec[left+2].type == 't') { + pos -= 2; + sf->stats_folds += 2; + continue; + } else if ((sf->tokenvec[left].type == 'n' || sf->tokenvec[left].type == '1' || sf->tokenvec[left].type == 's') && sf->tokenvec[left+1].type == ',' && - (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n')) { + (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n' || sf->tokenvec[left+2].type == 's')) { pos -= 2; continue; -#endif } else if ((sf->tokenvec[left].type == 'k' || sf->tokenvec[left].type == 'E') && st_is_unary_op(&sf->tokenvec[left+1]) && (sf->tokenvec[left+2].type == '1' || sf->tokenvec[left+2].type == 'n' || sf->tokenvec[left+2].type == 'v' || sf->tokenvec[left+2].type == 's' || sf->tokenvec[left+2].type == 'f' )) { @@ -1234,17 +1443,15 @@ int filter_fold(sfilter * sf) * double quote. * */ -int libinjection_is_string_sqli(sfilter * sql_state, - const char *s, size_t slen, - const char delim, - ptr_fingerprints_fn fn, void* callbackarg) +const char* +libinjection_sqli_fingerprint(sfilter * sql_state, + const char *s, size_t slen, + char delim, char comment_style) { int i; int tlen = 0; - char ch; - int patmatch; - libinjection_sqli_init(sql_state, s, slen, delim); + libinjection_sqli_init(sql_state, s, slen, delim, comment_style); tlen = filter_fold(sql_state); for (i = 0; i < tlen; ++i) { @@ -1257,17 +1464,45 @@ int libinjection_is_string_sqli(sfilter * sql_state, sql_state->pat[tlen] = CHAR_NULL; /* - * check for 'X' in pattern + * check for 'X' in pattern, and then + * clear out all tokens + * * this means parsing could not be done * accurately due to pgsql's double comments - * or other syntax that isn't consistent - * should be very rare false positive + * or other syntax that isn't consistent. + * Should be very rare false positive */ if (strchr(sql_state->pat, 'X')) { - return TRUE; + /* needed for SWIG */ + memset((void*)sql_state->pat, 0, MAX_TOKENS + 1); + sql_state->pat[0] = 'X'; + + sql_state->tokenvec[0].type = 'X'; + sql_state->tokenvec[0].val[0] = 'X'; + sql_state->tokenvec[0].val[1] = '\0'; + sql_state->tokenvec[1].type = CHAR_NULL; } - patmatch = fn(sql_state->pat, callbackarg); + return sql_state->pat; +} + + +/** + * + */ +#define UNUSED(x) (void)(x) + +int libinjection_sqli_check_fingerprint(sfilter* sql_state, void* callbackarg) +{ + UNUSED(callbackarg); + + return libinjection_sqli_blacklist(sql_state) && + libinjection_sqli_not_whitelist(sql_state); +} + +int libinjection_sqli_blacklist(sfilter* sql_state) +{ + int patmatch = bsearch_cstr(sql_state->pat, sql_fingerprints, sqli_fingerprints_sz); /* * No match. @@ -1280,11 +1515,22 @@ int libinjection_is_string_sqli(sfilter * sql_state, return FALSE; } + return TRUE; +} + +/* + * return TRUE if sqli, false is benign + */ +int libinjection_sqli_not_whitelist(sfilter* sql_state) +{ /* - * We got a SQLi match + * We assume we got a SQLi match * This next part just helps reduce false positives. * */ + char ch; + size_t tlen = strlen(sql_state->pat); + switch (tlen) { case 2:{ /* @@ -1431,7 +1677,6 @@ int libinjection_is_string_sqli(sfilter * sql_state, int libinjection_is_sqli(sfilter * sql_state, const char *s, size_t slen, ptr_fingerprints_fn fn, void* callbackarg) { - /* * no input? not sqli */ @@ -1440,17 +1685,21 @@ int libinjection_is_sqli(sfilter * sql_state, const char *s, size_t slen, } if (fn == NULL) { - fn = is_sqli_pattern; + fn = libinjection_sqli_check_fingerprint; } /* * test input "as-is" */ - if (libinjection_is_string_sqli(sql_state, s, slen, CHAR_NULL, - fn, callbackarg)) { + libinjection_sqli_fingerprint(sql_state, s, slen, CHAR_NULL, COMMENTS_ANSI); + if (fn(sql_state, callbackarg)) { return TRUE; + } else if (sql_state->stats_comment_ddx) { + libinjection_sqli_fingerprint(sql_state, s, slen, CHAR_NULL, COMMENTS_MYSQL); + if (fn(sql_state, callbackarg)) { + return TRUE; + } } - /* * if input has a single_quote, then * test as if input was actually ' @@ -1460,19 +1709,26 @@ int libinjection_is_sqli(sfilter * sql_state, const char *s, size_t slen, * is_string_sqli(sql_state, "'" + s, slen+1, NULL, fn, arg) * */ - if (memchr(s, CHAR_SINGLE, slen) - && libinjection_is_string_sqli(sql_state, s, slen, CHAR_SINGLE, - fn, callbackarg)) { + if (memchr(s, CHAR_SINGLE, slen)) { + libinjection_sqli_fingerprint(sql_state, s, slen, CHAR_SINGLE, COMMENTS_ANSI); + if (fn(sql_state, callbackarg)) { return TRUE; + } else if (sql_state->stats_comment_ddx) { + libinjection_sqli_fingerprint(sql_state, s, slen, CHAR_SINGLE, COMMENTS_MYSQL); + if (fn(sql_state, callbackarg)) { + return TRUE; + } + } } /* * same as above but with a double-quote " */ - if (memchr(s, CHAR_DOUBLE, slen) - && libinjection_is_string_sqli(sql_state, s, slen, CHAR_DOUBLE, - fn, callbackarg)) { - return TRUE; + if (memchr(s, CHAR_DOUBLE, slen)) { + libinjection_sqli_fingerprint(sql_state, s, slen, CHAR_DOUBLE, COMMENTS_MYSQL); + if (fn(sql_state, callbackarg)) { + return TRUE; + } } /* diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h index 1fcea59b..6708dad0 100644 --- a/apache2/libinjection/libinjection_sqli_data.h +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -24,6 +24,10 @@ static size_t parse_word(sfilter * sf); static size_t parse_var(sfilter * sf); static size_t parse_number(sfilter * sf); static size_t parse_tick(sfilter * sf); +static size_t parse_underscore(sfilter * sf); +static size_t parse_ustring(sfilter * sf); +static size_t parse_qstring(sfilter * sf); +static size_t parse_nqstring(sfilter * sf); static const char* operators2[] = { @@ -31,7 +35,6 @@ static const char* operators2[] = { "!<", "!=", "!>", - "!~", "%=", "&&", "&=", @@ -39,6 +42,7 @@ static const char* operators2[] = { "+=", "-=", "/=", + "::", ":=", "<<", "<=", @@ -71,6 +75,9 @@ static const keyword_t sql_keywords[] = { {"ALTER", 'k'}, {"ANALYZE", 'k'}, {"AND", '&'}, + {"ANYARRAY", 't'}, + {"ANYELEMENT", 't'}, + {"ANYNONARRY", 't'}, {"APPLOCK_MODE", 'f'}, {"APPLOCK_TEST", 'f'}, {"APP_NAME", 'f'}, @@ -100,7 +107,8 @@ static const keyword_t sql_keywords[] = { {"BEGIN", 'E'}, {"BENCHMARK", 'f'}, {"BETWEEN", 'k'}, - {"BIGINT", 'k'}, + {"BIGINT", 't'}, + {"BIGSERIAL", 't'}, {"BIN", 'f'}, {"BINARY", 'k'}, {"BINARY_DOUBLE_INFINITY", '1'}, @@ -114,12 +122,13 @@ static const keyword_t sql_keywords[] = { {"BIT_OR", 'f'}, {"BIT_XOR", 'f'}, {"BLOB", 'k'}, - {"BOOLEAN", 'k'}, + {"BOOLEAN", 't'}, {"BOOL_AND", 'f'}, {"BOOL_OR", 'f'}, {"BOTH", 'k'}, {"BTRIM", 'f'}, {"BY", 'n'}, + {"BYTEA", 't'}, {"CALL", 'k'}, {"CASCADE", 'k'}, {"CASE", 'E'}, @@ -139,7 +148,7 @@ static const keyword_t sql_keywords[] = { {"CHANGE", 'k'}, {"CHANGES", 'f'}, {"CHAR", 'f'}, - {"CHARACTER", 'k'}, + {"CHARACTER", 't'}, {"CHARACTER_LENGTH", 'f'}, {"CHARINDEX", 'f'}, {"CHARSET", 'f'}, @@ -183,6 +192,7 @@ static const keyword_t sql_keywords[] = { {"CREATE", 'E'}, {"CROSS", 'n'}, {"CSNG", 'f'}, + {"CSTRING", 't'}, {"CTXSYS.DRITHSX.SN", 'f'}, {"CUME_DIST", 'f'}, {"CURDATE", 'f'}, @@ -239,7 +249,7 @@ static const keyword_t sql_keywords[] = { {"DB_NAME", 'f'}, {"DCOUNT", 'f'}, {"DEC", 'k'}, - {"DECIMAL", 'k'}, + {"DECIMAL", 't'}, {"DECLARE", 'E'}, {"DECODE", 'f'}, {"DECRYPTBYASMKEY", 'f'}, @@ -267,6 +277,7 @@ static const keyword_t sql_keywords[] = { {"DLOOKUP", 'f'}, {"DMAX", 'f'}, {"DMIN", 'f'}, + {"DOUBLE", 't'}, {"DROP", 'E'}, {"DSUM", 'f'}, {"DUAL", 'k'}, @@ -311,6 +322,9 @@ static const keyword_t sql_keywords[] = { {"FILE_NAME", 'f'}, {"FIND_IN_SET", 'f'}, {"FIRST_VALUE", 'f'}, + {"FLOAT", 't'}, + {"FLOAT4", 't'}, + {"FLOAT8", 't'}, {"FLOOR", 'f'}, {"FN_VIRTUALFILESTATS", 'f'}, {"FOR", 'n'}, @@ -380,7 +394,7 @@ static const keyword_t sql_keywords[] = { {"INT3", 'k'}, {"INT4", 'k'}, {"INT8", 'k'}, - {"INTEGER", 'k'}, + {"INTEGER", 't'}, {"INTERVAL", 'k'}, {"INTO", 'k'}, {"IS", 'o'}, @@ -466,6 +480,7 @@ static const keyword_t sql_keywords[] = { {"MOD", 'o'}, {"MODE", 'n'}, {"MODIFIES", 'k'}, + {"MONEY", 't'}, {"MONTH", 'f'}, {"MONTHNAME", 'f'}, {"NAME_CONST", 'f'}, @@ -480,7 +495,7 @@ static const keyword_t sql_keywords[] = { {"NTILE", 'f'}, {"NULL", 'v'}, {"NULLIF", 'f'}, - {"NUMERIC", 'k'}, + {"NUMERIC", 't'}, {"NZ", 'f'}, {"OBJECTPROPERTY", 'f'}, {"OBJECTPROPERTYEX", 'f'}, @@ -491,6 +506,7 @@ static const keyword_t sql_keywords[] = { {"OCT", 'f'}, {"OCTET_LENGTH", 'f'}, {"OFFSET", 'k'}, + {"OID", 't'}, {"OLD_PASSWORD", 'f'}, {"ONE_SHOT", 'k'}, {"OPEN", 'k'}, @@ -574,13 +590,21 @@ static const keyword_t sql_keywords[] = { {"READ", 'k'}, {"READS", 'k'}, {"READ_WRITE", 'k'}, - {"REAL", 'n'}, + {"REAL", 't'}, {"REFERENCES", 'k'}, + {"REGCLASS", 't'}, + {"REGCONFIG", 't'}, + {"REGDICTIONARY", 't'}, {"REGEXP", 'o'}, {"REGEXP_MATCHES", 'f'}, {"REGEXP_REPLACE", 'f'}, {"REGEXP_SPLIT_TO_ARRAY", 'f'}, {"REGEXP_SPLIT_TO_TABLE", 'f'}, + {"REGOPER", 't'}, + {"REGOPERATOR", 't'}, + {"REGPROC", 't'}, + {"REGPROCEDURE", 't'}, + {"REGTYPE", 't'}, {"RELEASE", 'k'}, {"RELEASE_LOCK", 'f'}, {"RENAME", 'k'}, @@ -612,6 +636,10 @@ static const keyword_t sql_keywords[] = { {"SELECT", 'E'}, {"SENSITIVE", 'k'}, {"SEPARATOR", 'k'}, + {"SERIAL", 't'}, + {"SERIAL2", 't'}, + {"SERIAL4", 't'}, + {"SERIAL8", 't'}, {"SESSION_USER", 'f'}, {"SET", 'E'}, {"SETATTR", 'f'}, @@ -634,7 +662,8 @@ static const keyword_t sql_keywords[] = { {"SIN", 'f'}, {"SLEEP", 'f'}, {"SMALLDATETIMEFROMPARTS", 'f'}, - {"SMALLINT", 'k'}, + {"SMALLINT", 't'}, + {"SMALLSERIAL", 't'}, {"SOUNDEX", 'f'}, {"SOUNDS", 'o'}, {"SPACE", 'f'}, @@ -692,6 +721,7 @@ static const keyword_t sql_keywords[] = { {"TAN", 'f'}, {"TERMINATED", 'k'}, {"TERTIARY_WEIGHTS", 'f'}, + {"TEXT", 't'}, {"TEXTPOS", 'f'}, {"TEXTPTR", 'f'}, {"TEXTVALID", 'f'}, @@ -701,7 +731,7 @@ static const keyword_t sql_keywords[] = { {"TIMEFROMPARTS", 'f'}, {"TIMEOFDAY", 'f'}, {"TIMESERIAL", 'f'}, - {"TIMESTAMP", 'f'}, + {"TIMESTAMP", 't'}, {"TIMESTAMPADD", 'f'}, {"TIMEVALUE", 'f'}, {"TIME_FORMAT", 'f'}, @@ -738,6 +768,7 @@ static const keyword_t sql_keywords[] = { {"TYPE_ID", 'f'}, {"TYPE_NAME", 'f'}, {"UCASE", 'f'}, + {"UESCAPE", 'o'}, {"UNCOMPRESS", 'f'}, {"UNCOMPRESS_LENGTH", 'f'}, {"UNDO", 'k'}, @@ -747,7 +778,7 @@ static const keyword_t sql_keywords[] = { {"UNIQUE", 'n'}, {"UNIX_TIMESTAMP", 'f'}, {"UNI_ON", 'U'}, - {"UNKNOWN", 'k'}, + {"UNKNOWN", 'v'}, {"UNLOCK", 'k'}, {"UNNEST", 'f'}, {"UNSIGNED", 'k'}, @@ -771,7 +802,7 @@ static const keyword_t sql_keywords[] = { {"VALUES", 'k'}, {"VAR", 'f'}, {"VARBINARY", 'k'}, - {"VARCHAR", 'k'}, + {"VARCHAR", 't'}, {"VARCHARACTER", 'k'}, {"VARIANCE", 'f'}, {"VARP", 'f'}, @@ -781,6 +812,7 @@ static const keyword_t sql_keywords[] = { {"VERIFYSIGNEDBYASMKEY", 'f'}, {"VERIFYSIGNEDBYCERT", 'f'}, {"VERSION", 'f'}, + {"VOID", 't'}, {"WAITFOR", 'n'}, {"WEEK", 'f'}, {"WEEKDAY", 'f'}, @@ -811,15 +843,53 @@ static const keyword_t sql_keywords[] = { {"YEAR_MONTH", 'k'}, {"ZEROBLOB", 'f'}, {"ZEROFILL", 'k'}, + {"_ARMSCII8", 't'}, + {"_ASCII", 't'}, + {"_BIG5", 't'}, + {"_BINARY", 't'}, + {"_CP1250", 't'}, + {"_CP1251", 't'}, + {"_CP1257", 't'}, + {"_CP850", 't'}, + {"_CP852", 't'}, + {"_CP866", 't'}, + {"_CP932", 't'}, + {"_DEC8", 't'}, + {"_EUCJPMS", 't'}, + {"_EUCKR", 't'}, + {"_GB2312", 't'}, + {"_GBK", 't'}, + {"_GEOSTD8", 't'}, + {"_GREEK", 't'}, + {"_HEBREW", 't'}, + {"_HP8", 't'}, + {"_KEYBCS2", 't'}, + {"_KOI8R", 't'}, + {"_KOI8U", 't'}, + {"_LATIN1", 't'}, + {"_LATIN2", 't'}, + {"_LATIN5", 't'}, + {"_LATIN7", 't'}, + {"_MACCE", 't'}, + {"_MACROMAN", 't'}, + {"_SJIS", 't'}, + {"_SWE7", 't'}, + {"_TIS620", 't'}, + {"_UJIS", 't'}, + {"_USC2", 't'}, + {"_UTF8", 't'}, }; -static const size_t sql_keywords_sz = 755; +static const size_t sql_keywords_sz = 818; static const char* multikeywords_start[] = { "ALTER", "AT", "AT TIME", + "CHARACTER", "CREATE", "CREATE OR", "CROSS", + "DOUBLE", + "FOR", "FULL", "GROUP", "IN", @@ -829,8 +899,11 @@ static const char* multikeywords_start[] = { "IS", "IS DISTINCT", "IS NOT", + "IS NOT DISTINCT", "LEFT", "LOCK", + "LOCK IN", + "LOCK IN SHARE", "NATURAL", "NEXT", "NEXT VALUE", @@ -846,14 +919,17 @@ static const char* multikeywords_start[] = { "UNION", "WAITFOR", }; -static const size_t multikeywords_start_sz = 31; +static const size_t multikeywords_start_sz = 37; static const keyword_t multikeywords[] = { {"ALTER DOMAIN", 'k'}, {"ALTER TABLE", 'k'}, {"AT TIME", 'n'}, {"AT TIME ZONE", 'k'}, + {"CHARACTER VARYING", 't'}, {"CREATE OR REPLACE", 'E'}, {"CROSS JOIN", 'k'}, + {"DOUBLE PRECISION", 't'}, + {"FOR UPDATE", 'k'}, {"FULL OUTER", 'k'}, {"GROUP BY", 'B'}, {"IN BOOLEAN", 'n'}, @@ -867,6 +943,9 @@ static const keyword_t multikeywords[] = { {"IS NOT DISTINCT FROM", 'k'}, {"LEFT JOIN", 'k'}, {"LEFT OUTER", 'k'}, + {"LOCK IN", 'n'}, + {"LOCK IN SHARE", 'n'}, + {"LOCK IN SHARE MODE", 'k'}, {"LOCK TABLE", 'k'}, {"LOCK TABLES", 'k'}, {"NATURAL FULL", 'k'}, @@ -897,7 +976,7 @@ static const keyword_t multikeywords[] = { {"WAITFOR RECEIVE", 'E'}, {"WAITFOR TIME", 'E'}, }; -static const size_t multikeywords_sz = 48; +static const size_t multikeywords_sz = 54; typedef size_t (*pt2Function)(sfilter *sf); static const pt2Function char_parse_map[] = { @@ -979,14 +1058,14 @@ static const pt2Function char_parse_map[] = { &parse_word, /* 75 */ &parse_word, /* 76 */ &parse_word, /* 77 */ - &parse_word, /* 78 */ + &parse_nqstring, /* 78 */ &parse_word, /* 79 */ &parse_word, /* 80 */ - &parse_word, /* 81 */ + &parse_qstring, /* 81 */ &parse_word, /* 82 */ &parse_word, /* 83 */ &parse_word, /* 84 */ - &parse_word, /* 85 */ + &parse_ustring, /* 85 */ &parse_word, /* 86 */ &parse_word, /* 87 */ &parse_word, /* 88 */ @@ -996,7 +1075,7 @@ static const pt2Function char_parse_map[] = { &parse_backslash, /* 92 */ &parse_other, /* 93 */ &parse_operator1, /* 94 */ - &parse_word, /* 95 */ + &parse_underscore, /* 95 */ &parse_tick, /* 96 */ &parse_word, /* 97 */ &parse_word, /* 98 */ @@ -1011,14 +1090,14 @@ static const pt2Function char_parse_map[] = { &parse_word, /* 107 */ &parse_word, /* 108 */ &parse_word, /* 109 */ - &parse_word, /* 110 */ + &parse_nqstring, /* 110 */ &parse_word, /* 111 */ &parse_word, /* 112 */ - &parse_word, /* 113 */ + &parse_qstring, /* 113 */ &parse_word, /* 114 */ &parse_word, /* 115 */ &parse_word, /* 116 */ - &parse_word, /* 117 */ + &parse_ustring, /* 117 */ &parse_word, /* 118 */ &parse_word, /* 119 */ &parse_word, /* 120 */ @@ -1051,6 +1130,7 @@ static const char* sql_fingerprints[] = { "&f((s", "&f((v", "&f())", + "&f()U", "&f()o", "&f(1)", "&f(1o", @@ -1104,6 +1184,7 @@ static const char* sql_fingerprints[] = { "1&(1)", "1&(1,", "1&(1o", + "1&(E(", "1&(E1", "1&(Ef", "1&(Ek", @@ -1125,6 +1206,8 @@ static const char* sql_fingerprints[] = { "1&1&n", "1&1&s", "1&1&v", + "1&1;", + "1&1;c", "1&1B1", "1&1Bf", "1&1Bs", @@ -1132,6 +1215,7 @@ static const char* sql_fingerprints[] = { "1&1En", "1&1U", "1&1U(", + "1&1U;", "1&1UE", "1&1Uc", "1&1c", @@ -1193,6 +1277,8 @@ static const char* sql_fingerprints[] = { "1&n&n", "1&n&s", "1&n&v", + "1&n;", + "1&n;c", "1&nc", "1&nk1", "1&nkf", @@ -1207,14 +1293,17 @@ static const char* sql_fingerprints[] = { "1&o(s", "1&o(v", "1&o1", + "1&o1;", "1&o1c", "1&o1o", "1&of(", "1&oko", "1&os", + "1&os;", "1&osc", "1&oso", "1&ov", + "1&ov;", "1&ovc", "1&ovo", "1&s", @@ -1225,6 +1314,8 @@ static const char* sql_fingerprints[] = { "1&s&s", "1&s&v", "1&s1o", + "1&s;", + "1&s;c", "1&sB1", "1&sBf", "1&sBs", @@ -1232,6 +1323,7 @@ static const char* sql_fingerprints[] = { "1&sEn", "1&sU", "1&sU(", + "1&sU;", "1&sUE", "1&sUc", "1&sc", @@ -1256,6 +1348,8 @@ static const char* sql_fingerprints[] = { "1&v&n", "1&v&s", "1&v&v", + "1&v;", + "1&v;c", "1&vB1", "1&vBf", "1&vBs", @@ -1263,6 +1357,7 @@ static const char* sql_fingerprints[] = { "1&vEn", "1&vU", "1&vU(", + "1&vU;", "1&vUE", "1&vUc", "1&vc", @@ -1292,10 +1387,12 @@ static const char* sql_fingerprints[] = { "1)&(1", "1)&(E", "1)&(f", + "1)&(n", "1)&(s", "1)&(v", "1)&1", "1)&1&", + "1)&1;", "1)&1B", "1)&1U", "1)&1c", @@ -1305,6 +1402,7 @@ static const char* sql_fingerprints[] = { "1)&o(", "1)&s", "1)&s&", + "1)&s;", "1)&sB", "1)&sU", "1)&sc", @@ -1312,6 +1410,7 @@ static const char* sql_fingerprints[] = { "1)&so", "1)&v", "1)&v&", + "1)&v;", "1)&vB", "1)&vU", "1)&vc", @@ -1371,15 +1470,18 @@ static const char* sql_fingerprints[] = { "1);Ev", "1)B1", "1)B1&", + "1)B1;", "1)B1c", "1)B1o", "1)Bf(", "1)Bs", "1)Bs&", + "1)Bs;", "1)Bsc", "1)Bso", "1)Bv", "1)Bv&", + "1)Bv;", "1)Bvc", "1)Bvo", "1)E1c", @@ -1419,9 +1521,11 @@ static const char* sql_fingerprints[] = { "1)kvU", "1)kvo", "1)o((", + "1)o(E", "1)o(n", "1)o1", "1)o1)", + "1)o1;", "1)o1U", "1)o1c", "1)o1o", @@ -1429,14 +1533,17 @@ static const char* sql_fingerprints[] = { "1)of(", "1)on", "1)on&", + "1)on;", "1)onc", "1)os", "1)os)", + "1)os;", "1)osU", "1)osc", "1)oso", "1)ov", "1)ov)", + "1)ov;", "1)ovU", "1)ovc", "1)ovo", @@ -1449,35 +1556,13 @@ static const char* sql_fingerprints[] = { "1,(Es", "1,(Ev", "1,(f(", - "1,1))", - "1,1),", - "1,1)o", - "1,1B1", - "1,1Bf", - "1,1Bs", - "1,1Bv", - "1,1UE", - "1,1of", - "1,1os", - "1,1ov", "1,f((", + "1,f()", "1,f(1", "1,f(f", "1,f(s", + "1,f(t", "1,f(v", - "1,s))", - "1,s),", - "1,s)o", - "1,sB1", - "1,sBf", - "1,sBs", - "1,sBv", - "1,sUE", - "1,so1", - "1,sof", - "1,son", - "1,sos", - "1,sov", "1,v))", "1,v),", "1,v)o", @@ -1532,11 +1617,10 @@ static const char* sql_fingerprints[] = { "1B1&f", "1B1&s", "1B1&v", - "1B1,1", "1B1,f", - "1B1,n", - "1B1,s", "1B1,v", + "1B1;", + "1B1;c", "1B1UE", "1B1c", "1B1k1", @@ -1552,11 +1636,12 @@ static const char* sql_fingerprints[] = { "1BE(s", "1BE(v", "1Bf((", + "1Bf()", "1Bf(1", "1Bf(f", "1Bf(s", "1Bf(v", - "1Bn,n", + "1BnUE", "1Bnk1", "1Bnkf", "1Bnks", @@ -1566,11 +1651,10 @@ static const char* sql_fingerprints[] = { "1Bs&f", "1Bs&s", "1Bs&v", - "1Bs,1", "1Bs,f", - "1Bs,n", - "1Bs,s", "1Bs,v", + "1Bs;", + "1Bs;c", "1BsUE", "1Bsc", "1Bsk1", @@ -1592,6 +1676,8 @@ static const char* sql_fingerprints[] = { "1Bv,n", "1Bv,s", "1Bv,v", + "1Bv;", + "1Bv;c", "1BvUE", "1Bvc", "1Bvk1", @@ -1608,14 +1694,18 @@ static const char* sql_fingerprints[] = { "1E1os", "1E1ov", "1EU1,", + "1EU1c", "1EU1o", "1EUEf", "1EUf(", "1EUs,", + "1EUsc", "1EUso", "1EUv,", + "1EUvc", "1EUvo", "1Ef((", + "1Ef()", "1Ef(1", "1Ef(f", "1Ef(s", @@ -1643,32 +1733,43 @@ static const char* sql_fingerprints[] = { "1U(En", "1U(Es", "1U(Ev", - "1U1,1", "1U1,f", - "1U1,s", "1U1,v", + "1U1c", "1U1of", "1U1os", "1U1ov", + "1U;", + "1U;c", "1UE", "1UE((", "1UE(1", "1UE(E", "1UE(f", + "1UE(n", "1UE(s", "1UE(v", "1UE1", "1UE1&", + "1UE1(", + "1UE1)", "1UE1,", + "1UE1;", + "1UE1U", "1UE1c", "1UE1f", "1UE1k", "1UE1n", "1UE1o", + "1UE1s", + "1UE1v", + "1UE;", + "1UE;c", "1UEc", "1UEf", "1UEf(", "1UEf,", + "1UEf;", "1UEfc", "1UEk1", "1UEkf", @@ -1676,42 +1777,55 @@ static const char* sql_fingerprints[] = { "1UEks", "1UEkv", "1UEn&", + "1UEn(", "1UEn,", "1UEn1", "1UEnc", "1UEnf", "1UEnk", + "1UEnn", "1UEno", "1UEns", "1UEok", "1UEs", "1UEs&", + "1UEs(", + "1UEs)", "1UEs,", + "1UEs1", + "1UEs;", + "1UEsU", "1UEsc", "1UEsf", "1UEsk", "1UEsn", "1UEso", + "1UEsv", "1UEv", "1UEv&", + "1UEv(", + "1UEv)", "1UEv,", + "1UEv;", + "1UEvU", "1UEvc", "1UEvf", "1UEvk", "1UEvn", "1UEvo", + "1UEvs", "1Uc", "1Uf((", + "1Uf()", "1Uf(1", "1Uf(f", "1Uf(s", "1Uf(v", "1Uk((", "1Uk(E", - "1Un,1", "1Un,f", - "1Un,s", "1Un,v", + "1Un1(", "1Un1,", "1Un1o", "1UnE1", @@ -1720,14 +1834,17 @@ static const char* sql_fingerprints[] = { "1UnEv", "1Unc", "1Unf(", + "1Uns(", + "1Uns,", + "1Unso", "1Uo((", "1Uo(E", "1Uon1", "1Uonf", - "1Us,1", + "1Uons", "1Us,f", - "1Us,s", "1Us,v", + "1Usc", "1Uso1", "1Usof", "1Uson", @@ -1737,6 +1854,7 @@ static const char* sql_fingerprints[] = { "1Uv,f", "1Uv,s", "1Uv,v", + "1Uvc", "1Uvo1", "1Uvof", "1Uvon", @@ -1751,7 +1869,13 @@ static const char* sql_fingerprints[] = { "1f((s", "1f((v", "1f())", + "1f()1", + "1f():", + "1f()f", "1f()k", + "1f()o", + "1f()s", + "1f()v", "1f(1)", "1f(1o", "1f(f(", @@ -1803,7 +1927,9 @@ static const char* sql_fingerprints[] = { "1k1&o", "1k1&s", "1k1&v", + "1k1;", "1k1;E", + "1k1;c", "1k1B1", "1k1Bf", "1k1Bs", @@ -1819,7 +1945,13 @@ static const char* sql_fingerprints[] = { "1k1of", "1k1os", "1k1ov", + "1kUE1", + "1kUEf", + "1kUEn", + "1kUEs", + "1kUEv", "1kf((", + "1kf()", "1kf(1", "1kf(f", "1kf(s", @@ -1832,7 +1964,9 @@ static const char* sql_fingerprints[] = { "1ks&o", "1ks&s", "1ks&v", + "1ks;", "1ks;E", + "1ks;c", "1ksB1", "1ksBf", "1ksBs", @@ -1857,7 +1991,9 @@ static const char* sql_fingerprints[] = { "1kv&o", "1kv&s", "1kv&v", + "1kv;", "1kv;E", + "1kv;c", "1kvB1", "1kvBf", "1kvBs", @@ -1881,6 +2017,8 @@ static const char* sql_fingerprints[] = { "1n))n", "1n)UE", "1n,f(", + "1n1;", + "1n1;c", "1n1c", "1n1of", "1n1os", @@ -1899,6 +2037,7 @@ static const char* sql_fingerprints[] = { "1nUEs", "1nUEv", "1nf((", + "1nf()", "1nf(1", "1nf(f", "1nf(s", @@ -1951,6 +2090,7 @@ static const char* sql_fingerprints[] = { "1of((", "1of()", "1of(1", + "1of(E", "1of(f", "1of(s", "1of(v", @@ -1997,9 +2137,7 @@ static const char* sql_fingerprints[] = { "1os)k", "1os)o", "1os,(", - "1os,1", "1os,f", - "1os,s", "1os,v", "1os1:", "1os1f", @@ -2007,7 +2145,9 @@ static const char* sql_fingerprints[] = { "1os1s", "1os1v", "1os:n", + "1os;", "1os;E", + "1os;c", "1os;n", "1osB1", "1osBE", @@ -2025,6 +2165,7 @@ static const char* sql_fingerprints[] = { "1osU", "1osU(", "1osU1", + "1osU;", "1osUE", "1osUc", "1osUf", @@ -2038,6 +2179,7 @@ static const char* sql_fingerprints[] = { "1osk(", "1osk)", "1osk1", + "1oskU", "1oskf", "1oskn", "1osks", @@ -2092,7 +2234,9 @@ static const char* sql_fingerprints[] = { "1ov,s", "1ov,v", "1ov:n", + "1ov;", "1ov;E", + "1ov;c", "1ov;n", "1ovB1", "1ovBE", @@ -2110,6 +2254,7 @@ static const char* sql_fingerprints[] = { "1ovU", "1ovU(", "1ovU1", + "1ovU;", "1ovUE", "1ovUc", "1ovUf", @@ -2123,6 +2268,7 @@ static const char* sql_fingerprints[] = { "1ovk(", "1ovk)", "1ovk1", + "1ovkU", "1ovkf", "1ovkn", "1ovks", @@ -2150,6 +2296,8 @@ static const char* sql_fingerprints[] = { "1ovso", "1ovsv", "1s1", + "1s1;", + "1s1;c", "1s1c", "1s1of", "1s1os", @@ -2162,6 +2310,7 @@ static const char* sql_fingerprints[] = { "1s:v:", "1s:vo", "1sf((", + "1sf()", "1sf(1", "1sf(f", "1sf(s", @@ -2181,6 +2330,8 @@ static const char* sql_fingerprints[] = { "1sovo", "1sovs", "1sv", + "1sv;", + "1sv;c", "1svc", "1svo1", "1svof", @@ -2195,6 +2346,7 @@ static const char* sql_fingerprints[] = { "1v:v:", "1v:vo", "1vf((", + "1vf()", "1vf(1", "1vf(f", "1vf(s", @@ -2214,6 +2366,8 @@ static const char* sql_fingerprints[] = { "1vovo", "1vovs", "1vs", + "1vs;", + "1vs;c", "1vsc", "1vso1", "1vsof", @@ -2257,6 +2411,7 @@ static const char* sql_fingerprints[] = { "E(1vo", "E(Ek(", "E(f((", + "E(f()", "E(f(1", "E(f(f", "E(f(s", @@ -2292,28 +2447,25 @@ static const char* sql_fingerprints[] = { "E1))", "E1)))", "E1))1", + "E1));", "E1))c", "E1))f", "E1))s", "E1))v", + "E1);", + "E1);c", "E1)c", "E1,((", "E1,(1", "E1,(f", "E1,(s", "E1,(v", - "E1,1,", - "E1,1k", - "E1,1o", "E1,f(", - "E1,n,", - "E1,s,", - "E1,sk", - "E1,so", "E1,v,", "E1,vk", "E1,vo", "E1f((", + "E1f()", "E1f(1", "E1f(f", "E1f(s", @@ -2323,11 +2475,17 @@ static const char* sql_fingerprints[] = { "E1k1k", "E1k1o", "E1kf(", + "E1kn", + "E1kn;", + "E1knc", "E1knk", "E1ksk", "E1kso", "E1kvk", "E1kvo", + "E1n;", + "E1n;c", + "E1nc", "E1o((", "E1o(1", "E1o(f", @@ -2341,16 +2499,45 @@ static const char* sql_fingerprints[] = { "E1ovf", "E1ovo", "E1ovs", + "E1s", + "E1s;", + "E1s;c", + "E1sc", + "E1so1", + "E1sof", + "E1son", + "E1sos", + "E1sov", + "E1v", + "E1v;", + "E1v;c", + "E1vc", + "E1vo1", + "E1vof", + "E1von", + "E1vos", + "E1vov", "EE(((", "EE((f", "EE(f(", "Ef(((", + "Ef(()", "Ef((1", "Ef((f", "Ef((n", "Ef((o", "Ef((s", "Ef((v", + "Ef()&", + "Ef())", + "Ef(),", + "Ef()1", + "Ef()f", + "Ef()k", + "Ef()n", + "Ef()o", + "Ef()s", + "Ef()v", "Ef(1)", "Ef(1,", "Ef(1o", @@ -2381,10 +2568,16 @@ static const char* sql_fingerprints[] = { "Ek1vk", "Ek1vo", "Ekf((", + "Ekf()", "Ekf(1", "Ekf(f", "Ekf(s", "Ekf(v", + "Ekn((", + "Ekn(1", + "Ekn(f", + "Ekn(s", + "Ekn(v", "Eks1f", "Eks1k", "Eks1o", @@ -2419,9 +2612,9 @@ static const char* sql_fingerprints[] = { "Ekvsk", "Ekvso", "En,f(", - "En,n,", "Enk((", "Enk(E", + "Enkn,", "Enknk", "Eo(((", "Eo((1", @@ -2443,28 +2636,32 @@ static const char* sql_fingerprints[] = { "Es))", "Es)))", "Es))1", + "Es));", "Es))c", "Es))f", "Es))s", "Es))v", + "Es);", + "Es);c", "Es)c", "Es,((", "Es,(1", "Es,(f", "Es,(s", "Es,(v", - "Es,1,", - "Es,1k", - "Es,1o", "Es,f(", - "Es,n,", - "Es,s,", - "Es,sk", - "Es,so", "Es,v,", "Es,vk", "Es,vo", + "Es1", + "Es1;", + "Es1;c", + "Es1c", + "Es1of", + "Es1os", + "Es1ov", "Esf((", + "Esf()", "Esf(1", "Esf(f", "Esf(s", @@ -2474,11 +2671,18 @@ static const char* sql_fingerprints[] = { "Esk1k", "Esk1o", "Eskf(", + "Eskn", + "Eskn;", + "Esknc", "Esknk", "Esksk", "Eskso", "Eskvk", "Eskvo", + "Esn", + "Esn;", + "Esn;c", + "Esnc", "Eso((", "Eso(1", "Eso(f", @@ -2498,16 +2702,28 @@ static const char* sql_fingerprints[] = { "Esovf", "Esovo", "Esovs", + "Esv", + "Esv;", + "Esv;c", + "Esvc", + "Esvo1", + "Esvof", + "Esvon", + "Esvos", + "Esvov", "Ev&((", "Ev&(E", "Ev)", "Ev))", "Ev)))", "Ev))1", + "Ev));", "Ev))c", "Ev))f", "Ev))s", "Ev))v", + "Ev);", + "Ev);c", "Ev)c", "Ev,((", "Ev,(1", @@ -2526,6 +2742,7 @@ static const char* sql_fingerprints[] = { "Ev,vk", "Ev,vo", "Evf((", + "Evf()", "Evf(1", "Evf(f", "Evf(s", @@ -2535,11 +2752,18 @@ static const char* sql_fingerprints[] = { "Evk1k", "Evk1o", "Evkf(", + "Evkn", + "Evkn;", + "Evknc", "Evknk", "Evksk", "Evkso", "Evkvk", "Evkvo", + "Evn", + "Evn;", + "Evn;c", + "Evnc", "Evo((", "Evo(1", "Evo(f", @@ -2559,6 +2783,15 @@ static const char* sql_fingerprints[] = { "Evovf", "Evovo", "Evovs", + "Evs", + "Evs;", + "Evs;c", + "Evsc", + "Evso1", + "Evsof", + "Evson", + "Evsos", + "Evsov", "U((((", "U(((E", "U((En", @@ -2568,32 +2801,34 @@ static const char* sql_fingerprints[] = { "UE((f", "UE((s", "UE((v", + "UE(1)", "UE(1,", "UE(1o", "UE(f(", + "UE(s)", "UE(s,", "UE(so", + "UE(v)", "UE(v,", "UE(vo", - "UE1,1", "UE1,f", - "UE1,n", - "UE1,s", "UE1,v", + "UE1c", + "UE1kn", "UE1of", "UE1os", "UE1ov", "UEf((", + "UEf()", "UEf(1", "UEf(f", "UEf(s", "UEf(v", "UEnkn", - "UEs,1", "UEs,f", - "UEs,n", - "UEs,s", "UEs,v", + "UEsc", + "UEskn", "UEso1", "UEsof", "UEson", @@ -2604,6 +2839,8 @@ static const char* sql_fingerprints[] = { "UEv,n", "UEv,s", "UEv,v", + "UEvc", + "UEvkn", "UEvo1", "UEvof", "UEvon", @@ -2621,6 +2858,7 @@ static const char* sql_fingerprints[] = { "Uf(so", "Uf(v)", "Uf(vo", + "X", "f((((", "f((()", "f(((1", @@ -2628,10 +2866,24 @@ static const char* sql_fingerprints[] = { "f(((f", "f(((k", "f(((s", + "f(((t", "f(((v", "f(()&", "f(())", + "f((),", + "f(()1", + "f(():", + "f(();", + "f(()B", + "f(()E", + "f(()U", + "f(()c", + "f(()f", + "f(()k", + "f(()n", "f(()o", + "f(()s", + "f(()v", "f((1)", "f((1,", "f((1o", @@ -2643,14 +2895,104 @@ static const char* sql_fingerprints[] = { "f((s)", "f((s,", "f((so", + "f((t)", + "f((t,", "f((v)", "f((v,", "f((vo", + "f()&(", + "f()&1", + "f()&E", "f()&f", + "f()&k", + "f()&n", + "f()&o", + "f()&s", + "f()&v", "f())&", "f()))", + "f()),", + "f());", + "f())B", + "f())E", + "f())U", + "f())k", "f())o", + "f(),(", + "f(),1", + "f(),f", + "f(),s", + "f(),v", + "f()1:", + "f()1f", + "f()1o", + "f()1s", + "f()1v", + "f():n", + "f();E", + "f();n", + "f()B1", + "f()BE", + "f()Bf", + "f()Bn", + "f()Bs", + "f()Bv", + "f()E1", + "f()EU", + "f()Ef", + "f()En", + "f()Eo", + "f()Es", + "f()Ev", + "f()U", + "f()U(", + "f()U1", + "f()U;", + "f()UE", + "f()Uc", + "f()Uf", + "f()Uk", + "f()Un", + "f()Uo", + "f()Us", + "f()Uv", + "f()c", + "f()f(", + "f()k(", + "f()k)", + "f()k1", + "f()kU", + "f()kf", + "f()kn", + "f()ks", + "f()kv", + "f()n&", + "f()n)", + "f()n,", + "f()n1", + "f()nE", + "f()nU", + "f()nf", + "f()no", + "f()o(", + "f()o1", + "f()oE", + "f()oU", + "f()of", "f()ok", + "f()on", + "f()os", + "f()ov", + "f()s1", + "f()s:", + "f()sf", + "f()so", + "f()sv", + "f()v:", + "f()vf", + "f()vo", + "f()vs", + "f(1)", "f(1)&", "f(1))", "f(1),", @@ -2667,10 +3009,7 @@ static const char* sql_fingerprints[] = { "f(1)o", "f(1)s", "f(1)v", - "f(1,1", "f(1,f", - "f(1,n", - "f(1,s", "f(1,v", "f(1of", "f(1os", @@ -2685,6 +3024,7 @@ static const char* sql_fingerprints[] = { "f(k()", "f(k,(", "f(k,f", + "f(s)", "f(s)&", "f(s))", "f(s),", @@ -2701,16 +3041,21 @@ static const char* sql_fingerprints[] = { "f(s)o", "f(s)s", "f(s)v", - "f(s,1", "f(s,f", - "f(s,n", - "f(s,s", "f(s,v", "f(so1", "f(sof", "f(son", "f(sos", "f(sov", + "f(t))", + "f(t),", + "f(t,(", + "f(t,1", + "f(t,f", + "f(t,s", + "f(t,v", + "f(v)", "f(v)&", "f(v))", "f(v),", @@ -2749,11 +3094,7 @@ static const char* sql_fingerprints[] = { "ff(so", "ff(v)", "ff(vo", - "k1,1c", - "k1,1o", "k1,f(", - "k1,sc", - "k1,so", "k1,vc", "k1,vo", "k1of(", @@ -2765,10 +3106,14 @@ static const char* sql_fingerprints[] = { "k1ovo", "k1ovs", "kf(((", + "kf(()", "kf((1", "kf((f", "kf((s", "kf((v", + "kf())", + "kf(),", + "kf()o", "kf(1)", "kf(1o", "kf(f(", @@ -2776,11 +3121,7 @@ static const char* sql_fingerprints[] = { "kf(so", "kf(v)", "kf(vo", - "ks,1c", - "ks,1o", "ks,f(", - "ks,sc", - "ks,so", "ks,vc", "ks,vo", "kso1f", @@ -2845,6 +3186,8 @@ static const char* sql_fingerprints[] = { "n&(vo", "n&1", "n&1&n", + "n&1;", + "n&1;c", "n&1Bf", "n&1UE", "n&1c", @@ -2860,6 +3203,7 @@ static const char* sql_fingerprints[] = { "n&E(s", "n&E(v", "n&f((", + "n&f()", "n&f(1", "n&f(f", "n&f(s", @@ -2869,17 +3213,22 @@ static const char* sql_fingerprints[] = { "n&nos", "n&nov", "n&o1", + "n&o1;", "n&o1c", "n&o1o", "n&of(", "n&os", + "n&os;", "n&osc", "n&oso", "n&ov", + "n&ov;", "n&ovc", "n&ovo", "n&s", "n&s&n", + "n&s;", + "n&s;c", "n&sBf", "n&sUE", "n&sc", @@ -2893,6 +3242,8 @@ static const char* sql_fingerprints[] = { "n&sov", "n&v", "n&v&n", + "n&v;", + "n&v;c", "n&vBf", "n&vUE", "n&vc", @@ -2908,17 +3259,20 @@ static const char* sql_fingerprints[] = { "n)&(E", "n)&1", "n)&1&", + "n)&1;", "n)&1c", "n)&1f", "n)&1o", "n)&f(", "n)&s", "n)&s&", + "n)&s;", "n)&sc", "n)&sf", "n)&so", "n)&v", "n)&v&", + "n)&v;", "n)&vc", "n)&vf", "n)&vo", @@ -3012,27 +3366,12 @@ static const char* sql_fingerprints[] = { "n,(Es", "n,(Ev", "n,(f(", - "n,1,1", - "n,1,f", - "n,1,s", - "n,1,v", - "n,1of", - "n,1os", - "n,1ov", "n,f((", + "n,f()", "n,f(1", "n,f(f", "n,f(s", "n,f(v", - "n,s,1", - "n,s,f", - "n,s,s", - "n,s,v", - "n,so1", - "n,sof", - "n,son", - "n,sos", - "n,sov", "n,v,1", "n,v,f", "n,v,s", @@ -3071,6 +3410,7 @@ static const char* sql_fingerprints[] = { "nB1os", "nB1ov", "nBf((", + "nBf()", "nBf(1", "nBf(f", "nBf(s", @@ -3092,6 +3432,7 @@ static const char* sql_fingerprints[] = { "nE1os", "nE1ov", "nEf((", + "nEf()", "nEf(1", "nEf(f", "nEf(s", @@ -3119,14 +3460,18 @@ static const char* sql_fingerprints[] = { "nUE(E", "nUE1,", "nUE1c", + "nUE1k", "nUE1o", "nUEf(", "nUEn,", + "nUEnk", "nUEs,", "nUEsc", + "nUEsk", "nUEso", "nUEv,", "nUEvc", + "nUEvk", "nUEvo", "nc", "nf(((", @@ -3157,6 +3502,7 @@ static const char* sql_fingerprints[] = { "nk1os", "nk1ov", "nkf((", + "nkf()", "nkf(1", "nkf(f", "nkf(s", @@ -3207,6 +3553,7 @@ static const char* sql_fingerprints[] = { "noE(s", "noE(v", "nof((", + "nof()", "nof(1", "nof(f", "nof(s", @@ -3258,6 +3605,7 @@ static const char* sql_fingerprints[] = { "s&(1)", "s&(1,", "s&(1o", + "s&(E(", "s&(E1", "s&(Ef", "s&(Ek", @@ -3279,6 +3627,8 @@ static const char* sql_fingerprints[] = { "s&1&n", "s&1&s", "s&1&v", + "s&1;", + "s&1;c", "s&1B1", "s&1Bf", "s&1Bs", @@ -3286,6 +3636,7 @@ static const char* sql_fingerprints[] = { "s&1En", "s&1U", "s&1U(", + "s&1U;", "s&1UE", "s&1Uc", "s&1c", @@ -3348,6 +3699,8 @@ static const char* sql_fingerprints[] = { "s&n&n", "s&n&s", "s&n&v", + "s&n;", + "s&n;c", "s&nc", "s&nk1", "s&nkf", @@ -3362,14 +3715,17 @@ static const char* sql_fingerprints[] = { "s&o(s", "s&o(v", "s&o1", + "s&o1;", "s&o1c", "s&o1o", "s&of(", "s&oko", "s&os", + "s&os;", "s&osc", "s&oso", "s&ov", + "s&ov;", "s&ovc", "s&ovo", "s&s", @@ -3380,6 +3736,8 @@ static const char* sql_fingerprints[] = { "s&s&s", "s&s&v", "s&s1o", + "s&s;", + "s&s;c", "s&sB1", "s&sBf", "s&sBs", @@ -3387,6 +3745,7 @@ static const char* sql_fingerprints[] = { "s&sEn", "s&sU", "s&sU(", + "s&sU;", "s&sUE", "s&sUc", "s&sc", @@ -3411,6 +3770,8 @@ static const char* sql_fingerprints[] = { "s&v&n", "s&v&s", "s&v&v", + "s&v;", + "s&v;c", "s&vB1", "s&vBf", "s&vBs", @@ -3418,6 +3779,7 @@ static const char* sql_fingerprints[] = { "s&vEn", "s&vU", "s&vU(", + "s&vU;", "s&vUE", "s&vUc", "s&vc", @@ -3447,10 +3809,12 @@ static const char* sql_fingerprints[] = { "s)&(1", "s)&(E", "s)&(f", + "s)&(n", "s)&(s", "s)&(v", "s)&1", "s)&1&", + "s)&1;", "s)&1B", "s)&1U", "s)&1c", @@ -3460,6 +3824,7 @@ static const char* sql_fingerprints[] = { "s)&o(", "s)&s", "s)&s&", + "s)&s;", "s)&sB", "s)&sU", "s)&sc", @@ -3467,6 +3832,7 @@ static const char* sql_fingerprints[] = { "s)&so", "s)&v", "s)&v&", + "s)&v;", "s)&vB", "s)&vU", "s)&vc", @@ -3526,15 +3892,18 @@ static const char* sql_fingerprints[] = { "s);Ev", "s)B1", "s)B1&", + "s)B1;", "s)B1c", "s)B1o", "s)Bf(", "s)Bs", "s)Bs&", + "s)Bs;", "s)Bsc", "s)Bso", "s)Bv", "s)Bv&", + "s)Bv;", "s)Bvc", "s)Bvo", "s)E1c", @@ -3574,9 +3943,11 @@ static const char* sql_fingerprints[] = { "s)kvU", "s)kvo", "s)o((", + "s)o(E", "s)o(n", "s)o1", "s)o1)", + "s)o1;", "s)o1U", "s)o1c", "s)o1o", @@ -3584,14 +3955,17 @@ static const char* sql_fingerprints[] = { "s)of(", "s)on", "s)on&", + "s)on;", "s)onc", "s)os", "s)os)", + "s)os;", "s)osU", "s)osc", "s)oso", "s)ov", "s)ov)", + "s)ov;", "s)ovU", "s)ovc", "s)ovo", @@ -3604,35 +3978,13 @@ static const char* sql_fingerprints[] = { "s,(Es", "s,(Ev", "s,(f(", - "s,1))", - "s,1),", - "s,1)o", - "s,1B1", - "s,1Bf", - "s,1Bs", - "s,1Bv", - "s,1UE", - "s,1of", - "s,1os", - "s,1ov", "s,f((", + "s,f()", "s,f(1", "s,f(f", "s,f(s", + "s,f(t", "s,f(v", - "s,s))", - "s,s),", - "s,s)o", - "s,sB1", - "s,sBf", - "s,sBs", - "s,sBv", - "s,sUE", - "s,so1", - "s,sof", - "s,son", - "s,sos", - "s,sov", "s,v))", "s,v),", "s,v)o", @@ -3654,6 +4006,7 @@ static const char* sql_fingerprints[] = { "s1:v:", "s1:vo", "s1f((", + "s1f()", "s1f(1", "s1f(f", "s1f(s", @@ -3666,6 +4019,8 @@ static const char* sql_fingerprints[] = { "s1ovf", "s1ovo", "s1ovs", + "s1s;", + "s1s;c", "s1sc", "s1so1", "s1sof", @@ -3673,6 +4028,8 @@ static const char* sql_fingerprints[] = { "s1sos", "s1sov", "s1v", + "s1v;", + "s1v;c", "s1vc", "s1vo1", "s1vof", @@ -3720,11 +4077,10 @@ static const char* sql_fingerprints[] = { "sB1&f", "sB1&s", "sB1&v", - "sB1,1", "sB1,f", - "sB1,n", - "sB1,s", "sB1,v", + "sB1;", + "sB1;c", "sB1UE", "sB1c", "sB1k1", @@ -3740,11 +4096,12 @@ static const char* sql_fingerprints[] = { "sBE(s", "sBE(v", "sBf((", + "sBf()", "sBf(1", "sBf(f", "sBf(s", "sBf(v", - "sBn,n", + "sBnUE", "sBnk1", "sBnkf", "sBnks", @@ -3754,11 +4111,10 @@ static const char* sql_fingerprints[] = { "sBs&f", "sBs&s", "sBs&v", - "sBs,1", "sBs,f", - "sBs,n", - "sBs,s", "sBs,v", + "sBs;", + "sBs;c", "sBsUE", "sBsc", "sBsk1", @@ -3780,6 +4136,8 @@ static const char* sql_fingerprints[] = { "sBv,n", "sBv,s", "sBv,v", + "sBv;", + "sBv;c", "sBvUE", "sBvc", "sBvk1", @@ -3796,14 +4154,18 @@ static const char* sql_fingerprints[] = { "sE1os", "sE1ov", "sEU1,", + "sEU1c", "sEU1o", "sEUEf", "sEUf(", "sEUs,", + "sEUsc", "sEUso", "sEUv,", + "sEUvc", "sEUvo", "sEf((", + "sEf()", "sEf(1", "sEf(f", "sEf(s", @@ -3831,32 +4193,43 @@ static const char* sql_fingerprints[] = { "sU(En", "sU(Es", "sU(Ev", - "sU1,1", "sU1,f", - "sU1,s", "sU1,v", + "sU1c", "sU1of", "sU1os", "sU1ov", + "sU;", + "sU;c", "sUE", "sUE((", "sUE(1", "sUE(E", "sUE(f", + "sUE(n", "sUE(s", "sUE(v", "sUE1", "sUE1&", + "sUE1(", + "sUE1)", "sUE1,", + "sUE1;", + "sUE1U", "sUE1c", "sUE1f", "sUE1k", "sUE1n", "sUE1o", + "sUE1s", + "sUE1v", + "sUE;", + "sUE;c", "sUEc", "sUEf", "sUEf(", "sUEf,", + "sUEf;", "sUEfc", "sUEk1", "sUEkf", @@ -3864,41 +4237,55 @@ static const char* sql_fingerprints[] = { "sUEks", "sUEkv", "sUEn&", + "sUEn(", "sUEn,", "sUEn1", "sUEnc", "sUEnf", "sUEnk", + "sUEnn", "sUEno", + "sUEns", "sUEok", "sUEs", "sUEs&", + "sUEs(", + "sUEs)", "sUEs,", + "sUEs1", + "sUEs;", + "sUEsU", "sUEsc", "sUEsf", "sUEsk", "sUEsn", "sUEso", + "sUEsv", "sUEv", "sUEv&", + "sUEv(", + "sUEv)", "sUEv,", + "sUEv;", + "sUEvU", "sUEvc", "sUEvf", "sUEvk", "sUEvn", "sUEvo", + "sUEvs", "sUc", "sUf((", + "sUf()", "sUf(1", "sUf(f", "sUf(s", "sUf(v", "sUk((", "sUk(E", - "sUn,1", "sUn,f", - "sUn,s", "sUn,v", + "sUn1(", "sUn1,", "sUn1o", "sUnE1", @@ -3907,14 +4294,17 @@ static const char* sql_fingerprints[] = { "sUnEv", "sUnc", "sUnf(", + "sUns(", + "sUns,", + "sUnso", "sUo((", "sUo(E", "sUon1", "sUonf", - "sUs,1", + "sUons", "sUs,f", - "sUs,s", "sUs,v", + "sUsc", "sUso1", "sUsof", "sUson", @@ -3924,6 +4314,7 @@ static const char* sql_fingerprints[] = { "sUv,f", "sUv,s", "sUv,v", + "sUvc", "sUvo1", "sUvof", "sUvon", @@ -3938,7 +4329,13 @@ static const char* sql_fingerprints[] = { "sf((s", "sf((v", "sf())", + "sf()1", + "sf():", + "sf()f", "sf()k", + "sf()o", + "sf()s", + "sf()v", "sf(1)", "sf(1o", "sf(f(", @@ -3990,7 +4387,9 @@ static const char* sql_fingerprints[] = { "sk1&o", "sk1&s", "sk1&v", + "sk1;", "sk1;E", + "sk1;c", "sk1B1", "sk1Bf", "sk1Bs", @@ -4006,7 +4405,13 @@ static const char* sql_fingerprints[] = { "sk1of", "sk1os", "sk1ov", + "skUE1", + "skUEf", + "skUEn", + "skUEs", + "skUEv", "skf((", + "skf()", "skf(1", "skf(f", "skf(s", @@ -4019,7 +4424,9 @@ static const char* sql_fingerprints[] = { "sks&o", "sks&s", "sks&v", + "sks;", "sks;E", + "sks;c", "sksB1", "sksBf", "sksBs", @@ -4044,7 +4451,9 @@ static const char* sql_fingerprints[] = { "skv&o", "skv&s", "skv&v", + "skv;", "skv;E", + "skv;c", "skvB1", "skvBf", "skvBs", @@ -4069,6 +4478,8 @@ static const char* sql_fingerprints[] = { "sn)UE", "sn,f(", "sn1", + "sn1;", + "sn1;c", "sn1c", "sn1of", "sn1os", @@ -4087,6 +4498,7 @@ static const char* sql_fingerprints[] = { "snUEs", "snUEv", "snf((", + "snf()", "snf(1", "snf(f", "snf(s", @@ -4152,12 +4564,12 @@ static const char* sql_fingerprints[] = { "so1)k", "so1)o", "so1,(", - "so1,1", "so1,f", - "so1,s", "so1,v", "so1:n", + "so1;", "so1;E", + "so1;c", "so1;n", "so1B1", "so1BE", @@ -4175,6 +4587,7 @@ static const char* sql_fingerprints[] = { "so1U", "so1U(", "so1U1", + "so1U;", "so1UE", "so1Uc", "so1Uf", @@ -4188,6 +4601,7 @@ static const char* sql_fingerprints[] = { "so1k(", "so1k)", "so1k1", + "so1kU", "so1kf", "so1kn", "so1ks", @@ -4226,6 +4640,7 @@ static const char* sql_fingerprints[] = { "sof((", "sof()", "sof(1", + "sof(E", "sof(f", "sof(s", "sof(v", @@ -4272,9 +4687,7 @@ static const char* sql_fingerprints[] = { "son)k", "son)o", "son,(", - "son,1", "son,f", - "son,s", "son,v", "son1:", "son1f", @@ -4300,6 +4713,7 @@ static const char* sql_fingerprints[] = { "sonU", "sonU(", "sonU1", + "sonU;", "sonUE", "sonUc", "sonUf", @@ -4313,6 +4727,7 @@ static const char* sql_fingerprints[] = { "sonk(", "sonk)", "sonk1", + "sonkU", "sonkf", "sonkn", "sonks", @@ -4347,9 +4762,7 @@ static const char* sql_fingerprints[] = { "sos)k", "sos)o", "sos,(", - "sos,1", "sos,f", - "sos,s", "sos,v", "sos1:", "sos1f", @@ -4357,7 +4770,9 @@ static const char* sql_fingerprints[] = { "sos1s", "sos1v", "sos:n", + "sos;", "sos;E", + "sos;c", "sos;n", "sosB1", "sosBE", @@ -4375,6 +4790,7 @@ static const char* sql_fingerprints[] = { "sosU", "sosU(", "sosU1", + "sosU;", "sosUE", "sosUc", "sosUf", @@ -4388,6 +4804,7 @@ static const char* sql_fingerprints[] = { "sosk(", "sosk)", "sosk1", + "soskU", "soskf", "soskn", "sosks", @@ -4442,7 +4859,9 @@ static const char* sql_fingerprints[] = { "sov,s", "sov,v", "sov:n", + "sov;", "sov;E", + "sov;c", "sov;n", "sovB1", "sovBE", @@ -4460,6 +4879,7 @@ static const char* sql_fingerprints[] = { "sovU", "sovU(", "sovU1", + "sovU;", "sovUE", "sovUc", "sovUf", @@ -4473,6 +4893,7 @@ static const char* sql_fingerprints[] = { "sovk(", "sovk)", "sovk1", + "sovkU", "sovkf", "sovkn", "sovks", @@ -4507,6 +4928,7 @@ static const char* sql_fingerprints[] = { "sv:v:", "sv:vo", "svf((", + "svf()", "svf(1", "svf(f", "svf(s", @@ -4526,6 +4948,8 @@ static const char* sql_fingerprints[] = { "svovo", "svovs", "svs", + "svs;", + "svs;c", "svsc", "svso1", "svsof", @@ -4541,6 +4965,7 @@ static const char* sql_fingerprints[] = { "v&(1)", "v&(1,", "v&(1o", + "v&(E(", "v&(E1", "v&(Ef", "v&(Ek", @@ -4562,6 +4987,8 @@ static const char* sql_fingerprints[] = { "v&1&n", "v&1&s", "v&1&v", + "v&1;", + "v&1;c", "v&1B1", "v&1Bf", "v&1Bs", @@ -4569,6 +4996,7 @@ static const char* sql_fingerprints[] = { "v&1En", "v&1U", "v&1U(", + "v&1U;", "v&1UE", "v&1Uc", "v&1c", @@ -4631,6 +5059,8 @@ static const char* sql_fingerprints[] = { "v&n&n", "v&n&s", "v&n&v", + "v&n;", + "v&n;c", "v&nc", "v&nk1", "v&nkf", @@ -4645,14 +5075,17 @@ static const char* sql_fingerprints[] = { "v&o(s", "v&o(v", "v&o1", + "v&o1;", "v&o1c", "v&o1o", "v&of(", "v&oko", "v&os", + "v&os;", "v&osc", "v&oso", "v&ov", + "v&ov;", "v&ovc", "v&ovo", "v&s", @@ -4663,6 +5096,8 @@ static const char* sql_fingerprints[] = { "v&s&s", "v&s&v", "v&s1o", + "v&s;", + "v&s;c", "v&sB1", "v&sBf", "v&sBs", @@ -4670,6 +5105,7 @@ static const char* sql_fingerprints[] = { "v&sEn", "v&sU", "v&sU(", + "v&sU;", "v&sUE", "v&sUc", "v&sc", @@ -4694,6 +5130,8 @@ static const char* sql_fingerprints[] = { "v&v&n", "v&v&s", "v&v&v", + "v&v;", + "v&v;c", "v&vB1", "v&vBf", "v&vBs", @@ -4701,6 +5139,7 @@ static const char* sql_fingerprints[] = { "v&vEn", "v&vU", "v&vU(", + "v&vU;", "v&vUE", "v&vUc", "v&vc", @@ -4730,10 +5169,12 @@ static const char* sql_fingerprints[] = { "v)&(1", "v)&(E", "v)&(f", + "v)&(n", "v)&(s", "v)&(v", "v)&1", "v)&1&", + "v)&1;", "v)&1B", "v)&1U", "v)&1c", @@ -4743,6 +5184,7 @@ static const char* sql_fingerprints[] = { "v)&o(", "v)&s", "v)&s&", + "v)&s;", "v)&sB", "v)&sU", "v)&sc", @@ -4750,6 +5192,7 @@ static const char* sql_fingerprints[] = { "v)&so", "v)&v", "v)&v&", + "v)&v;", "v)&vB", "v)&vU", "v)&vc", @@ -4809,15 +5252,18 @@ static const char* sql_fingerprints[] = { "v);Ev", "v)B1", "v)B1&", + "v)B1;", "v)B1c", "v)B1o", "v)Bf(", "v)Bs", "v)Bs&", + "v)Bs;", "v)Bsc", "v)Bso", "v)Bv", "v)Bv&", + "v)Bv;", "v)Bvc", "v)Bvo", "v)E1c", @@ -4857,9 +5303,11 @@ static const char* sql_fingerprints[] = { "v)kvU", "v)kvo", "v)o((", + "v)o(E", "v)o(n", "v)o1", "v)o1)", + "v)o1;", "v)o1U", "v)o1c", "v)o1o", @@ -4867,14 +5315,17 @@ static const char* sql_fingerprints[] = { "v)of(", "v)on", "v)on&", + "v)on;", "v)onc", "v)os", "v)os)", + "v)os;", "v)osU", "v)osc", "v)oso", "v)ov", "v)ov)", + "v)ov;", "v)ovU", "v)ovc", "v)ovo", @@ -4899,9 +5350,11 @@ static const char* sql_fingerprints[] = { "v,1os", "v,1ov", "v,f((", + "v,f()", "v,f(1", "v,f(f", "v,f(s", + "v,f(t", "v,f(v", "v,s))", "v,s),", @@ -4970,11 +5423,10 @@ static const char* sql_fingerprints[] = { "vB1&f", "vB1&s", "vB1&v", - "vB1,1", "vB1,f", - "vB1,n", - "vB1,s", "vB1,v", + "vB1;", + "vB1;c", "vB1UE", "vB1c", "vB1k1", @@ -4990,11 +5442,12 @@ static const char* sql_fingerprints[] = { "vBE(s", "vBE(v", "vBf((", + "vBf()", "vBf(1", "vBf(f", "vBf(s", "vBf(v", - "vBn,n", + "vBnUE", "vBnk1", "vBnkf", "vBnks", @@ -5004,11 +5457,10 @@ static const char* sql_fingerprints[] = { "vBs&f", "vBs&s", "vBs&v", - "vBs,1", "vBs,f", - "vBs,n", - "vBs,s", "vBs,v", + "vBs;", + "vBs;c", "vBsUE", "vBsc", "vBsk1", @@ -5030,6 +5482,8 @@ static const char* sql_fingerprints[] = { "vBv,n", "vBv,s", "vBv,v", + "vBv;", + "vBv;c", "vBvUE", "vBvc", "vBvk1", @@ -5046,14 +5500,18 @@ static const char* sql_fingerprints[] = { "vE1os", "vE1ov", "vEU1,", + "vEU1c", "vEU1o", "vEUEf", "vEUf(", "vEUs,", + "vEUsc", "vEUso", "vEUv,", + "vEUvc", "vEUvo", "vEf((", + "vEf()", "vEf(1", "vEf(f", "vEf(s", @@ -5081,32 +5539,43 @@ static const char* sql_fingerprints[] = { "vU(En", "vU(Es", "vU(Ev", - "vU1,1", "vU1,f", - "vU1,s", "vU1,v", + "vU1c", "vU1of", "vU1os", "vU1ov", + "vU;", + "vU;c", "vUE", "vUE((", "vUE(1", "vUE(E", "vUE(f", + "vUE(n", "vUE(s", "vUE(v", "vUE1", "vUE1&", + "vUE1(", + "vUE1)", "vUE1,", + "vUE1;", + "vUE1U", "vUE1c", "vUE1f", "vUE1k", "vUE1n", "vUE1o", + "vUE1s", + "vUE1v", + "vUE;", + "vUE;c", "vUEc", "vUEf", "vUEf(", "vUEf,", + "vUEf;", "vUEfc", "vUEk1", "vUEkf", @@ -5114,41 +5583,55 @@ static const char* sql_fingerprints[] = { "vUEks", "vUEkv", "vUEn&", + "vUEn(", "vUEn,", "vUEn1", "vUEnc", "vUEnf", "vUEnk", + "vUEnn", "vUEno", + "vUEns", "vUEok", "vUEs", "vUEs&", + "vUEs(", + "vUEs)", "vUEs,", + "vUEs1", + "vUEs;", + "vUEsU", "vUEsc", "vUEsf", "vUEsk", "vUEsn", "vUEso", + "vUEsv", "vUEv", "vUEv&", + "vUEv(", + "vUEv)", "vUEv,", + "vUEv;", + "vUEvU", "vUEvc", "vUEvf", "vUEvk", "vUEvn", "vUEvo", + "vUEvs", "vUc", "vUf((", + "vUf()", "vUf(1", "vUf(f", "vUf(s", "vUf(v", "vUk((", "vUk(E", - "vUn,1", "vUn,f", - "vUn,s", "vUn,v", + "vUn1(", "vUn1,", "vUn1o", "vUnE1", @@ -5157,14 +5640,17 @@ static const char* sql_fingerprints[] = { "vUnEv", "vUnc", "vUnf(", + "vUns(", + "vUns,", + "vUnso", "vUo((", "vUo(E", "vUon1", "vUonf", - "vUs,1", + "vUons", "vUs,f", - "vUs,s", "vUs,v", + "vUsc", "vUso1", "vUsof", "vUson", @@ -5174,6 +5660,7 @@ static const char* sql_fingerprints[] = { "vUv,f", "vUv,s", "vUv,v", + "vUvc", "vUvo1", "vUvof", "vUvon", @@ -5188,7 +5675,13 @@ static const char* sql_fingerprints[] = { "vf((s", "vf((v", "vf())", + "vf()1", + "vf():", + "vf()f", "vf()k", + "vf()o", + "vf()s", + "vf()v", "vf(1)", "vf(1o", "vf(f(", @@ -5240,7 +5733,9 @@ static const char* sql_fingerprints[] = { "vk1&o", "vk1&s", "vk1&v", + "vk1;", "vk1;E", + "vk1;c", "vk1B1", "vk1Bf", "vk1Bs", @@ -5256,7 +5751,13 @@ static const char* sql_fingerprints[] = { "vk1of", "vk1os", "vk1ov", + "vkUE1", + "vkUEf", + "vkUEn", + "vkUEs", + "vkUEv", "vkf((", + "vkf()", "vkf(1", "vkf(f", "vkf(s", @@ -5269,7 +5770,9 @@ static const char* sql_fingerprints[] = { "vks&o", "vks&s", "vks&v", + "vks;", "vks;E", + "vks;c", "vksB1", "vksBf", "vksBs", @@ -5294,7 +5797,9 @@ static const char* sql_fingerprints[] = { "vkv&o", "vkv&s", "vkv&v", + "vkv;", "vkv;E", + "vkv;c", "vkvB1", "vkvBf", "vkvBs", @@ -5319,6 +5824,8 @@ static const char* sql_fingerprints[] = { "vn)UE", "vn,f(", "vn1", + "vn1;", + "vn1;c", "vn1c", "vn1of", "vn1os", @@ -5337,6 +5844,7 @@ static const char* sql_fingerprints[] = { "vnUEs", "vnUEv", "vnf((", + "vnf()", "vnf(1", "vnf(f", "vnf(s", @@ -5402,12 +5910,12 @@ static const char* sql_fingerprints[] = { "vo1)k", "vo1)o", "vo1,(", - "vo1,1", "vo1,f", - "vo1,s", "vo1,v", "vo1:n", + "vo1;", "vo1;E", + "vo1;c", "vo1;n", "vo1B1", "vo1BE", @@ -5425,6 +5933,7 @@ static const char* sql_fingerprints[] = { "vo1U", "vo1U(", "vo1U1", + "vo1U;", "vo1UE", "vo1Uc", "vo1Uf", @@ -5438,6 +5947,7 @@ static const char* sql_fingerprints[] = { "vo1k(", "vo1k)", "vo1k1", + "vo1kU", "vo1kf", "vo1kn", "vo1ks", @@ -5477,6 +5987,7 @@ static const char* sql_fingerprints[] = { "vof((", "vof()", "vof(1", + "vof(E", "vof(f", "vof(s", "vof(v", @@ -5523,9 +6034,7 @@ static const char* sql_fingerprints[] = { "von)k", "von)o", "von,(", - "von,1", "von,f", - "von,s", "von,v", "von1:", "von1f", @@ -5551,6 +6060,7 @@ static const char* sql_fingerprints[] = { "vonU", "vonU(", "vonU1", + "vonU;", "vonUE", "vonUc", "vonUf", @@ -5564,6 +6074,7 @@ static const char* sql_fingerprints[] = { "vonk(", "vonk)", "vonk1", + "vonkU", "vonkf", "vonkn", "vonks", @@ -5599,9 +6110,7 @@ static const char* sql_fingerprints[] = { "vos)k", "vos)o", "vos,(", - "vos,1", "vos,f", - "vos,s", "vos,v", "vos1:", "vos1f", @@ -5609,7 +6118,9 @@ static const char* sql_fingerprints[] = { "vos1s", "vos1v", "vos:n", + "vos;", "vos;E", + "vos;c", "vos;n", "vosB1", "vosBE", @@ -5627,6 +6138,7 @@ static const char* sql_fingerprints[] = { "vosU", "vosU(", "vosU1", + "vosU;", "vosUE", "vosUc", "vosUf", @@ -5640,6 +6152,7 @@ static const char* sql_fingerprints[] = { "vosk(", "vosk)", "vosk1", + "voskU", "voskf", "voskn", "vosks", @@ -5694,7 +6207,9 @@ static const char* sql_fingerprints[] = { "vov,s", "vov,v", "vov:n", + "vov;", "vov;E", + "vov;c", "vov;n", "vovB1", "vovBE", @@ -5712,6 +6227,7 @@ static const char* sql_fingerprints[] = { "vovU", "vovU(", "vovU1", + "vovU;", "vovUE", "vovUc", "vovUf", @@ -5725,6 +6241,7 @@ static const char* sql_fingerprints[] = { "vovk(", "vovk)", "vovk1", + "vovkU", "vovkf", "vovkn", "vovks", @@ -5752,6 +6269,6 @@ static const char* sql_fingerprints[] = { "vovso", "vovsv", }; -static const size_t sqli_fingerprints_sz = 4719; +static const size_t sqli_fingerprints_sz = 5157; #endif diff --git a/apache2/libinjection/sqlparse.c b/apache2/libinjection/sqlparse.c deleted file mode 100644 index 43c51343..00000000 --- a/apache2/libinjection/sqlparse.c +++ /dev/null @@ -1,1340 +0,0 @@ -/** - * Copyright 2012,2013 Nick Galbreath - * nickg@client9.com - * BSD License -- see COPYING.txt for details - * - * (setq-default indent-tabs-mode nil) - * (setq c-default-style "k&r" - * c-basic-offset 4) - * indent -kr -nut - */ - -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#if 0 -#define FOLD_DEBUG printf("%d: Fold state = %d, current=%c, last=%c\n", __LINE__, sf->fold_state, current->type, last->type == CHAR_NULL ? '~': last->type) -#else -#define FOLD_DEBUG -#endif - -/* order is important here */ -#include "sqlparse_private.h" -#include "sqlparse_data.h" - -/* memchr2 finds a string of 2 characters inside another string - * This a specialized version of "memmem" or "memchr". - * 'memmem' doesn't exist on all platforms - * - * Porting notes: this is just a special version of - * astring.find("AB") - * - */ -const char * -memchr2(const char *haystack, size_t haystack_len, char c0, char c1) -{ - const char *cur = haystack; - const char *last = haystack + haystack_len - 1; - - if (haystack_len < 2) { - return NULL; - } - if (c0 == c1) { - return NULL; - } - - while (cur < last) { - if (cur[0] == c0) { - if (cur[1] == c1) { - return cur; - } else { - cur += 2; - } - } else { - cur += 1; - } - } - - return NULL; -} - -/** Find largest string containing certain characters. - * - * C Standard library 'strspn' only works for 'c-strings' (null terminated) - * This works on arbitrary length. - * - * Porting notes: - * if accept is 'ABC', then this function would be similar to - * a_regexp.match(a_str, '[ABC]*'), - */ -size_t strlenspn(const char *s, size_t len, const char *accept) -{ - size_t i; - for (i = 0; i < len; ++i) { - /* likely we can do better by inlining this function - * but this works for now - */ - if (strchr(accept, s[i]) == NULL) { - return i; - } - } - return len; -} - -/* - * ASCII case insenstive compare only! - */ -int cstrcasecmp(const char *a, const char *b) -{ - int ca, cb; - - do { - ca = *a++ & 0xff; - cb = *b++ & 0xff; - if (ca >= 'a' && ca <= 'z') - ca -= 0x20; - if (cb >= 'a' && cb <= 'z') - cb -= 0x20; - } while (ca == cb && ca != '\0'); - - return ca - cb; -} - -/** - * Case insentive string compare. - * Here only to make code more readable - */ -int streq(const char *a, const char *b) -{ - return cstrcasecmp(a, b) == 0; -} - -/* - * Case-sensitive binary search. - * - */ -int bsearch_cstr(const char *key, const char *base[], size_t nmemb) -{ - int left = 0; - int right = (int) nmemb - 1; - - while (left <= right) { - int pos = (left + right) / 2; - int cmp = strcmp(base[pos], key); - if (cmp == 0) { - return TRUE; - } else if (cmp < 0) { - left = pos + 1; - } else { - right = pos - 1; - } - } - return FALSE; -} - -/* - * Case-insensitive binary search - */ -int bsearch_cstrcase(const char *key, const char *base[], size_t nmemb) -{ - int left = 0; - int right = (int) nmemb - 1; - - while (left <= right) { - int pos = (left + right) / 2; - int cmp = cstrcasecmp(base[pos], key); - if (cmp == 0) { - return TRUE; - } else if (cmp < 0) { - left = pos + 1; - } else { - right = pos - 1; - } - } - return FALSE; -} - -/** - * - * - * - * Porting Notes: - * given a mapping/hash of string to char - * this is just - * mapping[key.upper()] - */ -char bsearch_keyword_type(const char *key, const keyword_t * keywords, - size_t numb) -{ - int left = 0; - int right = (int) numb - 1; - - while (left <= right) { - int pos = (left + right) / 2; - int cmp = cstrcasecmp(keywords[pos].word, key); - if (cmp == 0) { - return keywords[pos].type; - } else if (cmp < 0) { - left = pos + 1; - } else { - right = pos - 1; - } - } - return CHAR_NULL; -} - -/* st_token methods - * - * The folow just manipulates the stoken_t type - * - * - */ - -void st_clear(stoken_t * st) -{ - st->type = CHAR_NULL; - st->str_open = CHAR_NULL; - st->str_close = CHAR_NULL; - st->val[0] = CHAR_NULL; -} - -int st_is_empty(const stoken_t * st) -{ - return st->type == CHAR_NULL; -} - -void st_assign_char(stoken_t * st, const char stype, const char value) -{ - st->type = stype; - st->val[0] = value; - st->val[1] = CHAR_NULL; -} - -void st_assign(stoken_t * st, const char stype, const char *value, - size_t len) -{ - size_t last = len < ST_MAX_SIZE ? len : (ST_MAX_SIZE - 1); - st->type = stype; - memcpy(st->val, value, last); - st->val[last] = CHAR_NULL; -} - -void st_copy(stoken_t * dest, const stoken_t * src) -{ - memcpy(dest, src, sizeof(stoken_t)); -} - -int st_is_multiword_start(const stoken_t * st) -{ - return bsearch_cstrcase(st->val, - multikeywords_start, - multikeywords_start_sz); -} - -int st_is_unary_op(const stoken_t * st) -{ - return (st->type == 'o' && !(strcmp(st->val, "+") && - strcmp(st->val, "-") && - strcmp(st->val, "!") && - strcmp(st->val, "!!") && - cstrcasecmp(st->val, "NOT") && - strcmp(st->val, "~"))); -} - -int st_is_arith_op(const stoken_t * st) -{ - return (st->type == 'o' && !(strcmp(st->val, "-") && - strcmp(st->val, "+") && - strcmp(st->val, "~") && - strcmp(st->val, "!") && - strcmp(st->val, "/") && - strcmp(st->val, "%") && - strcmp(st->val, "*") && - strcmp(st->val, "|") && - strcmp(st->val, "&") && - cstrcasecmp(st->val, "MOD") && - cstrcasecmp(st->val, "DIV"))); -} - -/* Parsers - * - * - */ - - -size_t parse_white(sfilter * sf) -{ - return sf->pos + 1; -} - -size_t parse_operator1(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - size_t pos = sf->pos; - - st_assign_char(current, 'o', cs[pos]); - return pos + 1; -} - -size_t parse_other(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - size_t pos = sf->pos; - - st_assign_char(current, '?', cs[pos]); - return pos + 1; -} - -size_t parse_char(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - size_t pos = sf->pos; - - st_assign_char(current, cs[pos], cs[pos]); - return pos + 1; -} - -size_t parse_eol_comment(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - - const char *endpos = - (const char *) memchr((const void *) (cs + pos), '\n', slen - pos); - if (endpos == NULL) { - st_assign(current, 'c', cs + pos, slen - pos); - return slen; - } else { - st_assign(current, 'c', cs + pos, endpos - cs - pos); - return (endpos - cs) + 1; - } -} - -size_t parse_dash(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - - - size_t pos1 = pos + 1; - if (pos1 < slen && cs[pos1] == '-') { - return parse_eol_comment(sf); - } else { - st_assign_char(current, 'o', '-'); - return pos1; - } -} - -size_t is_mysql_comment(const char *cs, const size_t len, size_t pos) -{ - size_t i; - - if (pos + 2 >= len) { - return 0; - } - if (cs[pos + 2] != '!') { - return 0; - } - /* - * this is a mysql comment - * got "/x!" - */ - if (pos + 3 >= len) { - return 3; - } - - if (!isdigit(cs[pos + 3])) { - return 3; - } - /* - * handle odd case of /x!0SELECT - */ - if (!isdigit(cs[pos + 4])) { - return 4; - } - - if (pos + 7 >= len) { - return 4; - } - - for (i = pos + 5; i <= pos + 7; ++i) { - if (!isdigit(cs[i])) { - return 3; - } - } - return 8; -} - -size_t parse_slash(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - const char* cur = cs + pos; - size_t inc; - - size_t pos1 = pos + 1; - if (pos1 == slen || cs[pos1] != '*') { - return parse_operator1(sf); - } - - inc = is_mysql_comment(cs, slen, pos); - if (inc == 0) { - - /* - * skip over initial '/x' - */ - const char *ptr = memchr2(cur + 2, slen - (pos + 2), '*', '/'); - if (ptr == NULL) { - /* - * unterminated comment - */ - st_assign(current, 'c', cs + pos, slen - pos); - return slen; - } else { - /* - * postgresql allows nested comments which makes - * this is incompatible with parsing so - * if we find a '/x' inside the coment, then - * make a new token. - */ - char ctype = 'c'; - const size_t clen = (ptr + 2) - (cur); - if (memchr2(cur + 2, ptr - (cur + 1), '/', '*') != NULL) { - ctype = 'X'; - } - st_assign(current, ctype, cs + pos, clen); - - return pos + clen; - } - } else { - /* - * MySQL Comment - */ - sf->in_comment = TRUE; - st_clear(current); - return pos + inc; - } -} - -size_t parse_backslash(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - - /* - * Weird MySQL alias for NULL, "\N" (capital N only) - */ - if (pos + 1 < slen && cs[pos + 1] == 'N') { - st_assign(current, '1', "NULL", 4); - return pos + 2; - } else { - return parse_other(sf); - } -} - -/** Is input a 2-char operator? - * - */ -int is_operator2(const char *key) -{ - return bsearch_cstr(key, operators2, operators2_sz); -} - -size_t parse_operator2(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - char op2[3]; - - if (pos + 1 >= slen) { - return parse_operator1(sf); - } - - op2[0] = cs[pos]; - op2[1] = cs[pos + 1]; - op2[2] = CHAR_NULL; - - /* - * Special Hack for MYSQL style comments - * instead of turning: - * /x! FOO x/ into FOO by rewriting the string, we - * turn it into FOO x/ and ignore the ending comment - */ - if (sf->in_comment && op2[0] == '*' && op2[1] == '/') { - sf->in_comment = FALSE; - st_clear(current); - return pos + 2; - } else if (pos + 2 < slen && op2[0] == '<' && op2[1] == '=' - && cs[pos + 2] == '>') { - /* - * special 3-char operator - */ - st_assign(current, 'o', "<=>", 3); - return pos + 3; - } else if (is_operator2(op2)) { - if (streq(op2, "&&") || streq(op2, "||")) { - st_assign(current, '&', op2, 2); - } else { - /* - * normal 2 char operator - */ - st_assign(current, 'o', op2, 2); - } - return pos + 2; - } else { - /* - * must be a single char operator - */ - return parse_operator1(sf); - } -} - -size_t parse_string_core(const char *cs, const size_t len, size_t pos, - stoken_t * st, char delim, size_t offset) -{ - /* - * offset is to skip the perhaps first quote char - */ - const char *qpos = - (const char *) memchr((const void *) (cs + pos + offset), delim, - len - pos - offset); - - /* - * then keep string open/close info - */ - if (offset == 1) { - /* - * this is real quote - */ - st->str_open = delim; - } else { - /* - * this was a simulated quote - */ - st->str_open = CHAR_NULL; - } - - while (TRUE) { - if (qpos == NULL) { - /* - * string ended with no trailing quote - * assign what we have - */ - st_assign(st, 's', cs + pos + offset, len - pos - offset); - st->str_close = CHAR_NULL; - return len; - } else if (*(qpos - 1) != '\\') { - /* - * ending quote is not escaped.. copy and end - */ - st_assign(st, 's', cs + pos + offset, - qpos - (cs + pos + offset)); - st->str_close = delim; - return qpos - cs + 1; - } else { - qpos = - (const char *) memchr((const void *) (qpos + 1), delim, - (cs + len) - (qpos + 1)); - } - } -} - -/** - * Used when first char is a ' or " - */ -size_t parse_string(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - - /* - * assert cs[pos] == single or double quote - */ - return parse_string_core(cs, slen, pos, current, cs[pos], 1); -} - -size_t parse_word(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - size_t pos = sf->pos; - char *dot; - char ch; - size_t slen = - strlenspn(cs + pos, sf->slen - pos, - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$."); - - st_assign(current, 'n', cs + pos, slen); - - dot = strchr(current->val, '.'); - if (dot != NULL) { - *dot = '\0'; - - ch = bsearch_keyword_type(current->val, sql_keywords, - sql_keywords_sz); - if (ch == 'k' || ch == 'o') { - /* - * we got something like "SELECT.1" - */ - current->type = ch; - return pos + strlen(current->val); - } else { - /* - * something else, put back dot - */ - *dot = '.'; - } - } - - /* - * do normal lookup with word including '.' - */ - if (slen < ST_MAX_SIZE) { - ch = bsearch_keyword_type(current->val, sql_keywords, - sql_keywords_sz); - if (ch == CHAR_NULL) { - ch = 'n'; - } - current->type = ch; - } - return pos + slen; -} - -size_t parse_var(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - size_t pos1 = pos + 1; - size_t xlen; - - /* - * move past optional other '@' - */ - if (pos1 < slen && cs[pos1] == '@') { - pos1 += 1; - } - - xlen = strlenspn(cs + pos1, slen - pos1, - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$"); - if (xlen == 0) { - st_assign(current, 'v', cs + pos, (pos1 - pos)); - return pos1; - } else { - st_assign(current, 'v', cs + pos, xlen + (pos1 - pos)); - return pos1 + xlen; - } -} - -size_t parse_money(sfilter *sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - size_t xlen; - - /* - * $1,000.00 or $1.000,00 ok! - * This also parses $....,,,111 but that's ok - */ - xlen = strlenspn(cs + pos + 1, slen - pos - 1, "0123456789.,"); - if (xlen == 0) { - /* - * just ignore '$' - */ - return pos + 1; - } else { - st_assign(current, '1', cs + pos, 1 + xlen); - return pos + 1 + xlen; - } -} - -size_t parse_number(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *cs = sf->s; - const size_t slen = sf->slen; - size_t pos = sf->pos; - size_t xlen; - size_t start; - - if (pos + 1 < slen && cs[pos] == '0' && (cs[pos + 1] == 'X' || cs[pos + 1] == 'x')) { - /* - * TBD compare if isxdigit - */ - xlen = - strlenspn(cs + pos + 2, slen - pos - 2, "0123456789ABCDEFabcdef"); - if (xlen == 0) { - st_assign(current, 'n', "0X", 2); - return pos + 2; - } else { - st_assign(current, '1', cs + pos, 2 + xlen); - return pos + 2 + xlen; - } - } - - start = pos; - while (pos < slen && isdigit(cs[pos])) { - pos += 1; - } - if (pos < slen && cs[pos] == '.') { - pos += 1; - while (pos < slen && isdigit(cs[pos])) { - pos += 1; - } - if (pos - start == 1) { - st_assign_char(current, 'n', '.'); - return pos; - } - } - - if (pos < slen) { - if (cs[pos] == 'E' || cs[pos] == 'e') { - pos += 1; - if (pos < slen && (cs[pos] == '+' || cs[pos] == '-')) { - pos += 1; - } - while (pos < slen && isdigit(cs[pos])) { - pos += 1; - } - } else if (isalpha(cs[pos])) { - /* - * oh no, we have something like '6FOO' - * use microsoft style parsing and take just - * the number part and leave the rest to be - * parsed later - */ - st_assign(current, '1', cs + start, pos - start); - return pos; - } - } - - st_assign(current, '1', cs + start, pos - start); - return pos; -} - -int parse_token(sfilter * sf) -{ - stoken_t *current = &sf->syntax_current; - const char *s = sf->s; - const size_t slen = sf->slen; - size_t *pos = &sf->pos; - pt2Function fnptr; - - st_clear(current); - - /* - * if we are at beginning of string - * and in single-quote or double quote mode - * then pretend the input starts with a quote - */ - if (*pos == 0 && sf->delim != CHAR_NULL) { - *pos = parse_string_core(s, slen, 0, current, sf->delim, 0); - return TRUE; - } - - while (*pos < slen) { - /* - * get current character - */ - const int ch = (int) (s[*pos]); - - /* - * if not ascii, then continue... - * actually probably need to just assuming - * it's a string - */ - if (ch < 0 || ch > 127) { - *pos += 1; - continue; - } - - /* - * look up the parser, and call it - * - * Porting Note: this is mapping of char to function - * charparsers[ch]() - */ - fnptr = char_parse_map[ch]; - *pos = (*fnptr) (sf); - - /* - * - */ - if (current->type != CHAR_NULL) { - return TRUE; - } - } - return FALSE; -} - -void sfilter_reset(sfilter * sf, const char *s, size_t len) -{ - memset(sf, 0, sizeof(sfilter)); - sf->s = s; - sf->slen = len; -} - -int syntax_merge_words(stoken_t * a, stoken_t * b) -{ - size_t sz1; - size_t sz2; - size_t sz3; - char tmp[ST_MAX_SIZE]; - char ch; - - if (! - (a->type == 'k' || a->type == 'n' || a->type == 'o' - || a->type == 'U')) { - return FALSE; - } - - sz1 = strlen(a->val); - sz2 = strlen(b->val); - sz3 = sz1 + sz2 + 1; - if (sz3 >= ST_MAX_SIZE) { - return FALSE; - } - /* - * oddly annoying last.val + ' ' + current.val - */ - memcpy(tmp, a->val, sz1); - tmp[sz1] = ' '; - memcpy(tmp + sz1 + 1, b->val, sz2); - tmp[sz3] = CHAR_NULL; - - ch = bsearch_keyword_type(tmp, multikeywords, multikeywords_sz); - if (ch != CHAR_NULL) { - /* - * -1, don't copy the null byte - */ - st_assign(a, ch, tmp, sz3); - return TRUE; - } else { - return FALSE; - } -} - -/* This does some simple syntax cleanup based on the token - * - * - */ -int sqli_tokenize(sfilter * sf, stoken_t * sout) -{ - stoken_t *last = &sf->syntax_last; - stoken_t *current = &sf->syntax_current; - - while (parse_token(sf)) { - char ttype = current->type; - - /* - * TBD: hmm forgot logic here. - */ - if (ttype == 'c') { - st_copy(&sf->syntax_comment, current); - continue; - } - st_clear(&sf->syntax_comment); - - /* - * If we don't have a saved token, and we have - * a string: save it. if the next token is also a string - * then merge them. e.g. "A" "B" in SQL is actually "AB" - * a n/k/U/o type: save since next token my be merged together - * for example: "LEFT" + "JOIN" = "LEFT JOIN" - * a o/& type: TBD need to review. - * - */ - if (last->type == CHAR_NULL) { - switch (ttype) { - - /* - * items that have special needs - */ - case 's': - st_copy(last, current); - continue; - case 'n': - case 'k': - case 'U': - case '&': - case 'o': - if (st_is_multiword_start(current)) { - st_copy(last, current); - continue; - } else if (current->type == 'o' || current->type == '&') { - /* } else if (st_is_unary_op(current)) { */ - st_copy(last, current); - continue; - } else { - /* - * copy to out - */ - st_copy(sout, current); - return TRUE; - } - default: - /* - * copy to out - */ - st_copy(sout, current); - return TRUE; - } - } - /* - * We have a saved token - */ - - switch (ttype) { - case 's': - if (last->type == 's') { - /* - * "FOO" "BAR" == "FOO" (skip second string) - */ - continue; - } else { - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - case 'o': - /* - * first case to handle "IS" + "NOT" - */ - if (syntax_merge_words(last, current)) { - continue; - } else if (st_is_unary_op(current) - && (last->type == 'o' || last->type == '&' - || last->type == 'U')) { - /* - * if an operator is followed by a unary operator, skip it. - * 1, + ==> "+" is not unary, it's arithmetic - * AND, + ==> "+" is unary - */ - continue; - } else { - /* - * no match - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - case 'n': - case 'k': - if (syntax_merge_words(last, current)) { - continue; - } else { - /* - * total no match - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - - default: - /* - * fix up for ambigous "IN" - * handle case where IN is typically a function - * but used in compound "IN BOOLEAN MODE" jive - */ - if (last->type == 'n' && !cstrcasecmp(last->val, "IN")) { - st_copy(last, current); - st_assign(sout, 'f', "IN", 2); - return TRUE; - } else { - /* - * no match at all - */ - st_copy(sout, last); - st_copy(last, current); - return TRUE; - } - break; - } - } - - /* - * final cleanup - */ - if (last->type) { - st_copy(sout, last); - st_clear(last); - return TRUE; - } else if (sf->syntax_comment.type) { - /* - * TBD - */ - st_copy(sout, &sf->syntax_comment); - st_clear(&sf->syntax_comment); - return TRUE; - } else { - return FALSE; - } -} - -/* - * My apologies, this code is a mess - */ -int filter_fold(sfilter * sf, stoken_t * sout) -{ - stoken_t *last = &sf->fold_last; - stoken_t *current = &sf->fold_current; - - if (sf->fold_state == 4 && !st_is_empty(last)) { - st_copy(sout, last); - sf->fold_state = 2; - st_clear(last); - return FALSE; - } - - while (sqli_tokenize(sf, current)) { - /* - * 0 = start of statement - * skip ( and unary ops - */ - if (sf->fold_state == 0) { - if (current->type == '(') { - continue; - } - if (st_is_unary_op(current)) { - continue; - } - sf->fold_state = 1; - } - - if (st_is_empty(last)) { - FOLD_DEBUG; - if (current->type == '1' || current->type == 'n' - || current->type == '(') { - sf->fold_state = 2; - st_copy(last, current); - } - st_copy(sout, current); - return FALSE; - } else if (last->type == '(' && st_is_unary_op(current)) { - /* - * similar to beginning of statement - * an opening '(' resets state, and we should skip all - * unary operators - */ - continue; - } else if (last->type == '(' && current->type == '(') { - /* if we get another '(' after another - * emit 1, but keep state - */ - st_copy(sout, current); - return FALSE; - } else if ((last->type == '1' || last->type == 'n') - && st_is_arith_op(current)) { - FOLD_DEBUG; - st_copy(last, current); - } else if (last->type == 'o' - && (current->type == '1' || current->type == 'n')) { - FOLD_DEBUG; - st_copy(last, current); - } else { - if (sf->fold_state == 2) { - if (last->type != '1' && last->type != '(' - && last->type != 'n') { - FOLD_DEBUG; - st_copy(sout, last); - st_copy(last, current); - sf->fold_state = 4; - } else { - FOLD_DEBUG; - st_copy(sout, current); - st_clear(last); - } - return FALSE; - } else { - if (last->type == 'o') { - st_copy(sout, last); - st_copy(last, current); - sf->fold_state = 4; - } else { - sf->fold_state = 2; - st_copy(sout, current); - st_clear(last); - } - return FALSE; - } - } - } - - if (!st_is_empty(last)) { - if (st_is_arith_op(last)) { - st_copy(sout, last); - st_clear(last); - return FALSE; - } else { - st_clear(last); - } - } - - /* - * all done: nothing more to parse - */ - return TRUE; -} - -/* secondary api: detects SQLi in a string, GIVEN a context. - * - * A context can be: - * * CHAR_NULL (\0), process as is - * * CHAR_SINGLE ('), process pretending input started with a - * single quote. - * * CHAR_DOUBLE ("), process pretending input started with a - * double quote. - * - */ -int is_string_sqli(sfilter * sql_state, const char *s, size_t slen, - const char delim, ptr_fingerprints_fn fn) -{ - int tlen = 0; - char ch; - int patmatch; - int all_done; - - sfilter_reset(sql_state, s, slen); - sql_state->delim = delim; - - while (tlen < MAX_TOKENS) { - all_done = filter_fold(sql_state, &(sql_state->tokenvec[tlen])); - if (all_done) { - break; - } - - sql_state->pat[tlen] = sql_state->tokenvec[tlen].type; - tlen += 1; - } - - /* - * make the fingerprint pattern a c-string (null delimited) - */ - sql_state->pat[tlen] = CHAR_NULL; - - /* - * check for 'X' in pattern - * this means parsing could not be done - * accurately due to pgsql's double comments - * or other syntax that isn't consistent - * should be very rare false positive - */ - if (strchr(sql_state->pat, 'X')) { - return TRUE; - } - - patmatch = fn(sql_state->pat); - - /* - * No match. - * - * Set sql_state->reason to current line number - * only for debugging purposes. - */ - if (!patmatch) { - sql_state->reason = __LINE__; - return FALSE; - } - - /* - * We got a SQLi match - * This next part just helps reduce false positives. - * - */ - switch (tlen) { - case 2:{ - /* - * if 'comment' is '#' ignore.. too many FP - */ - if (sql_state->tokenvec[1].val[0] == '#') { - sql_state->reason = __LINE__; - return FALSE; - } - - /* - * for fingerprint like 'nc', only comments of /x are treated - * as SQL... ending comments of "--" and "#" are not sqli - */ - if (sql_state->tokenvec[0].type == 'n' && - sql_state->tokenvec[1].type == 'c' && - sql_state->tokenvec[1].val[0] != '/') { - sql_state->reason = __LINE__; - return FALSE; - } - - /** - * there are some odd base64-looking query string values - * 1234-ABCDEFEhfhihwuefi-- - * which evaluate to "1c"... these are not SQLi - * but 1234-- probably is. - * Make sure the "1" in "1c" is actually a true decimal number - * - * Need to check -original- string since the folding step - * may have merged tokens, e.g. "1+FOO" is folded into "1" - */ - if (sql_state->tokenvec[0].type == '1'&& sql_state->tokenvec[1].type == 'c') { - /* - * we check that next character after the number is either whitespace, - * or '/' or a '-' ==> sqli. - */ - ch = sql_state->s[strlen(sql_state->tokenvec[0].val)]; - if ( ch <= 32 ) { - /* next char was whitespace,e.g. "1234 --" - * this isn't exactly correct.. ideally we should skip over all whitespace - * but this seems to be ok for now - */ - return TRUE; - } - if (ch == '/' && sql_state->s[strlen(sql_state->tokenvec[0].val) + 1] == '*') { - return TRUE; - } - if (ch == '-' && sql_state->s[strlen(sql_state->tokenvec[0].val) + 1] == '-') { - return TRUE; - } - - sql_state->reason = __LINE__; - return FALSE; - } - - /* - * detect obvious sqli scans.. many people put '--' in plain text - * so only detect if input ends with '--', e.g. 1-- but not 1-- foo - */ - if ((strlen(sql_state->tokenvec[1].val) > 2) - && sql_state->tokenvec[1].val[0] == '-') { - sql_state->reason = __LINE__; - return FALSE; - } - - break; - } /* case 2 */ - case 3:{ - /* - * ...foo' + 'bar... - * no opening quote, no closing quote - * and each string has data - */ - if (streq(sql_state->pat, "sos") - || streq(sql_state->pat, "s&s")) { - if ((sql_state->tokenvec[0].str_open == CHAR_NULL) - && (sql_state->tokenvec[2].str_close == CHAR_NULL)) { - /* - * if ....foo" + "bar.... - */ - return TRUE; - } else { - /* - * not sqli - */ - sql_state->reason = __LINE__; - return FALSE; - } - break; - } - } /* case 3 */ - case 5: { - if (streq(sql_state->pat, "sosos")) { - if (sql_state->tokenvec[0].str_open == CHAR_NULL) { - /* - * if ....foo" + "bar.... - */ - return TRUE; - } else { - /* - * not sqli - */ - sql_state->reason = __LINE__; - return FALSE; - } - break; - } - } /* case 5 */ - } /* end switch */ - - return TRUE; -} - -/** Main API, detects SQLi in an input. - * - * - */ -int is_sqli(sfilter * sql_state, const char *s, size_t slen, - ptr_fingerprints_fn fn) -{ - - /* - * no input? not sqli - */ - if (slen == 0) { - return FALSE; - } - - /* - * test input "as-is" - */ - if (is_string_sqli(sql_state, s, slen, CHAR_NULL, fn)) { - return TRUE; - } - - /* - * if input has a single_quote, then - * test as if input was actually ' - * example: if input if "1' = 1", then pretend it's - * "'1' = 1" - * Porting Notes: example the same as doing - * is_string_sqli(sql_state, "'" + s, slen+1, NULL, fn) - * - */ - if (memchr(s, CHAR_SINGLE, slen) - && is_string_sqli(sql_state, s, slen, CHAR_SINGLE, fn)) { - return TRUE; - } - - /* - * same as above but with a double-quote " - */ - if (memchr(s, CHAR_DOUBLE, slen) - && is_string_sqli(sql_state, s, slen, CHAR_DOUBLE, fn)) { - return TRUE; - } - - /* - * Hurray, input is not SQLi - */ - return FALSE; -} From 69b1095947f5a755c541791f794e1ddcbe12c7b0 Mon Sep 17 00:00:00 2001 From: Nick Galbreath Date: Tue, 4 Jun 2013 11:12:45 +0900 Subject: [PATCH 3/3] fix makefiles --- standalone/Makefile.am | 2 +- tests/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/standalone/Makefile.am b/standalone/Makefile.am index c470376a..b94e3665 100644 --- a/standalone/Makefile.am +++ b/standalone/Makefile.am @@ -13,7 +13,7 @@ standalone_la_SOURCES = ../apache2/mod_security2.c \ ../apache2/msc_util.c ../apache2/msc_pcre.c ../apache2/persist_dbm.c ../apache2/msc_reqbody.c \ ../apache2/msc_geo.c ../apache2/msc_gsb.c ../apache2/msc_unicode.c \ ../apache2/acmp.c ../apache2/msc_lua.c ../apache2/msc_release.c \ - ../apache2/msc_crypt.c ../apache2/msc_tree.c ../apache2/libinjection/sqlparse.c \ + ../apache2/msc_crypt.c ../apache2/msc_tree.c ../apache2/libinjection/libinjection_sql.c \ api.c buckets.c \ config.c filters.c \ hooks.c \ diff --git a/tests/Makefile.am b/tests/Makefile.am index c0209daa..6790dc4b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,7 +22,7 @@ msc_test_SOURCES = msc_test.c \ $(top_srcdir)/apache2/acmp.c \ $(top_srcdir)/apache2/msc_lua.c \ $(top_srcdir)/apache2/msc_release.c \ - $(top_srcdir)/apache2/libinjection/sqlparse.c + $(top_srcdir)/apache2/libinjection/libinjection_sqli.c msc_test_CFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \ @PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @LUA_CFLAGS@ msc_test_CPPFLAGS = -I$(top_srcdir)/apache2 \