Blame apache2/libinjection/libinjection_sqli.c

Packit Service 384592
/**
Packit Service 384592
 * Copyright 2012,2016  Nick Galbreath
Packit Service 384592
 * nickg@client9.com
Packit Service 384592
 * BSD License -- see COPYING.txt for details
Packit Service 384592
 *
Packit Service 384592
 * https://libinjection.client9.com/
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
#include <string.h>
Packit Service 384592
#include <stdlib.h>
Packit Service 384592
#include <stdio.h>
Packit Service 384592
#include <ctype.h>
Packit Service 384592
#include <assert.h>
Packit Service 384592
#include <stddef.h>
Packit Service 384592
Packit Service 384592
#include "libinjection.h"
Packit Service 384592
#include "libinjection_sqli.h"
Packit Service 384592
#include "libinjection_sqli_data.h"
Packit Service 384592
Packit Service 384592
#define LIBINJECTION_VERSION "3.9.2"
Packit Service 384592
Packit Service 384592
#define LIBINJECTION_SQLI_TOKEN_SIZE  sizeof(((stoken_t*)(0))->val)
Packit Service 384592
#define LIBINJECTION_SQLI_MAX_TOKENS  5
Packit Service 384592
Packit Service 384592
#ifndef TRUE
Packit Service 384592
#define TRUE 1
Packit Service 384592
#endif
Packit Service 384592
#ifndef FALSE
Packit Service 384592
#define FALSE 0
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
#define CHAR_NULL    '\0'
Packit Service 384592
#define CHAR_SINGLE  '\''
Packit Service 384592
#define CHAR_DOUBLE  '"'
Packit Service 384592
#define CHAR_TICK    '`'
Packit Service 384592
Packit Service 384592
/* faster than calling out to libc isdigit */
Packit Service 384592
#define ISDIGIT(a) ((unsigned)((a) - '0') <= 9)
Packit Service 384592
Packit Service 384592
#if 0
Packit Service 384592
#define FOLD_DEBUG printf("%d \t more=%d  pos=%d left=%d\n", __LINE__, more, (int)pos, (int)left);
Packit Service 384592
#else
Packit Service 384592
#define FOLD_DEBUG
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * not making public just yet
Packit Service 384592
 */
Packit Service 384592
typedef enum {
Packit Service 384592
    TYPE_NONE        = 0
Packit Service 384592
    , TYPE_KEYWORD     = (int)'k'
Packit Service 384592
    , TYPE_UNION       = (int)'U'
Packit Service 384592
    , TYPE_GROUP       = (int)'B'
Packit Service 384592
    , TYPE_EXPRESSION  = (int)'E'
Packit Service 384592
    , TYPE_SQLTYPE     = (int)'t'
Packit Service 384592
    , TYPE_FUNCTION    = (int)'f'
Packit Service 384592
    , TYPE_BAREWORD    = (int)'n'
Packit Service 384592
    , TYPE_NUMBER      = (int)'1'
Packit Service 384592
    , TYPE_VARIABLE    = (int)'v'
Packit Service 384592
    , TYPE_STRING      = (int)'s'
Packit Service 384592
    , TYPE_OPERATOR    = (int)'o'
Packit Service 384592
    , TYPE_LOGIC_OPERATOR = (int)'&'
Packit Service 384592
    , TYPE_COMMENT     = (int)'c'
Packit Service 384592
    , TYPE_COLLATE     = (int)'A'
Packit Service 384592
    , TYPE_LEFTPARENS  = (int)'('
Packit Service 384592
    , TYPE_RIGHTPARENS = (int)')'  /* not used? */
Packit Service 384592
    , TYPE_LEFTBRACE   = (int)'{'
Packit Service 384592
    , TYPE_RIGHTBRACE  = (int)'}'
Packit Service 384592
    , TYPE_DOT         = (int)'.'
Packit Service 384592
    , TYPE_COMMA       = (int)','
Packit Service 384592
    , TYPE_COLON       = (int)':'
Packit Service 384592
    , TYPE_SEMICOLON   = (int)';'
Packit Service 384592
    , TYPE_TSQL        = (int)'T'  /* TSQL start */
Packit Service 384592
    , TYPE_UNKNOWN     = (int)'?'
Packit Service 384592
    , TYPE_EVIL        = (int)'X'  /* unparsable, abort  */
Packit Service 384592
    , TYPE_FINGERPRINT = (int)'F'  /* not really a token */
Packit Service 384592
    , TYPE_BACKSLASH   = (int)'\\'
Packit Service 384592
} sqli_token_types;
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Initializes parsing state
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static char flag2delim(int flag)
Packit Service 384592
{
Packit Service 384592
    if (flag & FLAG_QUOTE_SINGLE) {
Packit Service 384592
        return CHAR_SINGLE;
Packit Service 384592
    } else if (flag & FLAG_QUOTE_DOUBLE) {
Packit Service 384592
        return CHAR_DOUBLE;
Packit Service 384592
    } else {
Packit Service 384592
        return CHAR_NULL;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* memchr2 finds a string of 2 characters inside another string
Packit Service 384592
 * This a specialized version of "memmem" or "memchr".
Packit Service 384592
 * 'memmem' doesn't exist on all platforms
Packit Service 384592
 *
Packit Service 384592
 * Porting notes: this is just a special version of
Packit Service 384592
 *    astring.find("AB")
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static const char *
Packit Service 384592
memchr2(const char *haystack, size_t haystack_len, char c0, char c1)
Packit Service 384592
{
Packit Service 384592
    const char *cur = haystack;
Packit Service 384592
    const char *last = haystack + haystack_len - 1;
Packit Service 384592
Packit Service 384592
    if (haystack_len < 2) {
Packit Service 384592
        return NULL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    while (cur < last) {
Packit Service 384592
        /* safe since cur < len - 1 always */
Packit Service 384592
        if (cur[0] == c0 && cur[1] == c1) {
Packit Service 384592
            return cur;
Packit Service 384592
        }
Packit Service 384592
        cur += 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * memmem might not exist on some systems
Packit Service 384592
 */
Packit Service 384592
static const char *
Packit Service 384592
my_memmem(const char* haystack, size_t hlen, const char* needle, size_t nlen)
Packit Service 384592
{
Packit Service 384592
    const char* cur;
Packit Service 384592
    const char* last;
Packit Service 384592
    assert(haystack);
Packit Service 384592
    assert(needle);
Packit Service 384592
    assert(nlen > 1);
Packit Service 384592
    last =  haystack + hlen - nlen;
Packit Service 384592
    for (cur = haystack; cur <= last; ++cur) {
Packit Service 384592
        if (cur[0] == needle[0] && memcmp(cur, needle, nlen) == 0) {
Packit Service 384592
            return cur;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    return NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/** Find largest string containing certain characters.
Packit Service 384592
 *
Packit Service 384592
 * C Standard library 'strspn' only works for 'c-strings' (null terminated)
Packit Service 384592
 * This works on arbitrary length.
Packit Service 384592
 *
Packit Service 384592
 * Performance notes:
Packit Service 384592
 *   not critical
Packit Service 384592
 *
Packit Service 384592
 * Porting notes:
Packit Service 384592
 *   if accept is 'ABC', then this function would be similar to
Packit Service 384592
 *   a_regexp.match(a_str, '[ABC]*'),
Packit Service 384592
 */
Packit Service 384592
static size_t
Packit Service 384592
strlenspn(const char *s, size_t len, const char *accept)
Packit Service 384592
{
Packit Service 384592
    size_t i;
Packit Service 384592
    for (i = 0; i < len; ++i) {
Packit Service 384592
        /* likely we can do better by inlining this function
Packit Service 384592
         * but this works for now
Packit Service 384592
         */
Packit Service 384592
        if (strchr(accept, s[i]) == NULL) {
Packit Service 384592
            return i;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    return len;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t
Packit Service 384592
strlencspn(const char *s, size_t len, const char *accept)
Packit Service 384592
{
Packit Service 384592
    size_t i;
Packit Service 384592
    for (i = 0; i < len; ++i) {
Packit Service 384592
        /* likely we can do better by inlining this function
Packit Service 384592
         * but this works for now
Packit Service 384592
         */
Packit Service 384592
        if (strchr(accept, s[i]) != NULL) {
Packit Service 384592
            return i;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    return len;
Packit Service 384592
}
Packit Service 384592
static int char_is_white(char ch) {
Packit Service 384592
    /* ' '  space is 0x32
Packit Service 384592
       '\t  0x09 \011 horizontal tab
Packit Service 384592
       '\n' 0x0a \012 new line
Packit Service 384592
       '\v' 0x0b \013 vertical tab
Packit Service 384592
       '\f' 0x0c \014 new page
Packit Service 384592
       '\r' 0x0d \015 carriage return
Packit Service 384592
            0x00 \000 null (oracle)
Packit Service 384592
            0xa0 \240 is Latin-1
Packit Service 384592
    */
Packit Service 384592
    return strchr(" \t\n\v\f\r\240\000", ch) != NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* DANGER DANGER
Packit Service 384592
 * This is -very specialized function-
Packit Service 384592
 *
Packit Service 384592
 * this compares a ALL_UPPER CASE C STRING
Packit Service 384592
 * with a *arbitrary memory* + length
Packit Service 384592
 *
Packit Service 384592
 * Sane people would just make a copy, up-case
Packit Service 384592
 * and use a hash table.
Packit Service 384592
 *
Packit Service 384592
 * Required since libc version uses the current locale
Packit Service 384592
 * and is much slower.
Packit Service 384592
 */
Packit Service 384592
static int cstrcasecmp(const char *a, const char *b, size_t n)
Packit Service 384592
{
Packit Service 384592
    char cb;
Packit Service 384592
Packit Service 384592
    for (; n > 0; a++, b++, n--) {
Packit Service 384592
        cb = *b;
Packit Service 384592
        if (cb >= 'a' && cb <= 'z') {
Packit Service 384592
            cb -= 0x20;
Packit Service 384592
        }
Packit Service 384592
        if (*a != cb) {
Packit Service 384592
            return *a - cb;
Packit Service 384592
        } else if (*a == '\0') {
Packit Service 384592
            return -1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return (*a == 0) ? 0 : 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Case sensitive string compare.
Packit Service 384592
 *  Here only to make code more readable
Packit Service 384592
 */
Packit Service 384592
static int streq(const char *a, const char *b)
Packit Service 384592
{
Packit Service 384592
    return strcmp(a, b) == 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 *
Packit Service 384592
 *
Packit Service 384592
 * Porting Notes:
Packit Service 384592
 *  given a mapping/hash of string to char
Packit Service 384592
 *  this is just
Packit Service 384592
 *    typecode = mapping[key.upper()]
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
static char bsearch_keyword_type(const char *key, size_t len,
Packit Service 384592
                                 const keyword_t * keywords, size_t numb)
Packit Service 384592
{
Packit Service 384592
    size_t pos;
Packit Service 384592
    size_t left = 0;
Packit Service 384592
    size_t right = numb - 1;
Packit Service 384592
Packit Service 384592
    while (left < right) {
Packit Service 384592
        pos = (left + right) >> 1;
Packit Service 384592
Packit Service 384592
        /* arg0 = upper case only, arg1 = mixed case */
Packit Service 384592
        if (cstrcasecmp(keywords[pos].word, key, len) < 0) {
Packit Service 384592
            left = pos + 1;
Packit Service 384592
        } else {
Packit Service 384592
            right = pos;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    if ((left == right) && cstrcasecmp(keywords[left].word, key, len) == 0) {
Packit Service 384592
        return keywords[left].type;
Packit Service 384592
    } else {
Packit Service 384592
        return CHAR_NULL;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static char is_keyword(const char* key, size_t len)
Packit Service 384592
{
Packit Service 384592
    return bsearch_keyword_type(key, len, sql_keywords, sql_keywords_sz);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* st_token methods
Packit Service 384592
 *
Packit Service 384592
 * The following functions manipulates the stoken_t type
Packit Service 384592
 *
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
static void st_clear(stoken_t * st)
Packit Service 384592
{
Packit Service 384592
    memset(st, 0, sizeof(stoken_t));
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len,
Packit Service 384592
                           const char value)
Packit Service 384592
{
Packit Service 384592
    /* done to eliminate unused warning */
Packit Service 384592
    (void)len;
Packit Service 384592
    st->type = (char) stype;
Packit Service 384592
    st->pos = pos;
Packit Service 384592
    st->len = 1;
Packit Service 384592
    st->val[0] = value;
Packit Service 384592
    st->val[1] = CHAR_NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static void st_assign(stoken_t * st, const char stype,
Packit Service 384592
                      size_t pos, size_t len, const char* value)
Packit Service 384592
{
Packit Service 384592
    const size_t MSIZE = LIBINJECTION_SQLI_TOKEN_SIZE;
Packit Service 384592
    size_t last = len < MSIZE ? len : (MSIZE - 1);
Packit Service 384592
    st->type = (char) stype;
Packit Service 384592
    st->pos = pos;
Packit Service 384592
    st->len = last;
Packit Service 384592
    memcpy(st->val, value, last);
Packit Service 384592
    st->val[last] = CHAR_NULL;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static void st_copy(stoken_t * dest, const stoken_t * src)
Packit Service 384592
{
Packit Service 384592
    memcpy(dest, src, sizeof(stoken_t));
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static int st_is_arithmetic_op(const stoken_t* st)
Packit Service 384592
{
Packit Service 384592
    const char ch = st->val[0];
Packit Service 384592
    return (st->type == TYPE_OPERATOR && st->len == 1 &&
Packit Service 384592
            (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '%'));
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static int st_is_unary_op(const stoken_t * st)
Packit Service 384592
{
Packit Service 384592
    const char* str = st->val;
Packit Service 384592
    const size_t len = st->len;
Packit Service 384592
Packit Service 384592
    if (st->type != TYPE_OPERATOR) {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    switch (len) {
Packit Service 384592
    case 1:
Packit Service 384592
        return *str == '+' || *str == '-' || *str == '!' || *str == '~';
Packit Service 384592
    case 2:
Packit Service 384592
        return str[0] == '!' && str[1] == '!';
Packit Service 384592
    case 3:
Packit Service 384592
        return cstrcasecmp("NOT", str, 3) == 0;
Packit Service 384592
    default:
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* Parsers
Packit Service 384592
 *
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
static size_t parse_white(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    return sf->pos + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_operator1(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    st_assign_char(sf->current, TYPE_OPERATOR, pos, 1, cs[pos]);
Packit Service 384592
    return pos + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_other(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    st_assign_char(sf->current, TYPE_UNKNOWN, pos, 1, cs[pos]);
Packit Service 384592
    return pos + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_char(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    st_assign_char(sf->current, cs[pos], pos, 1, cs[pos]);
Packit Service 384592
    return pos + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_eol_comment(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    const char *endpos =
Packit Service 384592
        (const char *) memchr((const void *) (cs + pos), '\n', slen - pos);
Packit Service 384592
    if (endpos == NULL) {
Packit Service 384592
        st_assign(sf->current, TYPE_COMMENT, pos, slen - pos, cs + pos);
Packit Service 384592
        return slen;
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_COMMENT, pos, (size_t)(endpos - cs) - pos, cs + pos);
Packit Service 384592
        return (size_t)((endpos - cs) + 1);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/** In ANSI mode, hash is an operator
Packit Service 384592
 *  In MYSQL mode, it's a EOL comment like '--'
Packit Service 384592
 */
Packit Service 384592
static size_t parse_hash(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    sf->stats_comment_hash += 1;
Packit Service 384592
    if (sf->flags & FLAG_SQL_MYSQL) {
Packit Service 384592
        sf->stats_comment_hash += 1;
Packit Service 384592
        return parse_eol_comment(sf);
Packit Service 384592
    } else {
Packit Service 384592
        st_assign_char(sf->current, TYPE_OPERATOR, sf->pos, 1, '#');
Packit Service 384592
        return sf->pos + 1;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_dash(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * five cases
Packit Service 384592
     * 1) --[white]  this is always a SQL comment
Packit Service 384592
     * 2) --[EOF]    this is a comment
Packit Service 384592
     * 3) --[notwhite] in MySQL this is NOT a comment but two unary operators
Packit Service 384592
     * 4) --[notwhite] everyone else thinks this is a comment
Packit Service 384592
     * 5) -[not dash]  '-' is a unary operator
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if (pos + 2 < slen && cs[pos + 1] == '-' && char_is_white(cs[pos+2]) ) {
Packit Service 384592
        return parse_eol_comment(sf);
Packit Service 384592
    } else if (pos +2 == slen && cs[pos + 1] == '-') {
Packit Service 384592
        return parse_eol_comment(sf);
Packit Service 384592
    } else if (pos + 1 < slen && cs[pos + 1] == '-' && (sf->flags & FLAG_SQL_ANSI)) {
Packit Service 384592
        /* --[not-white] not-white case:
Packit Service 384592
         *
Packit Service 384592
         */
Packit Service 384592
        sf->stats_comment_ddx += 1;
Packit Service 384592
        return parse_eol_comment(sf);
Packit Service 384592
    } else {
Packit Service 384592
        st_assign_char(sf->current, TYPE_OPERATOR, pos, 1, '-');
Packit Service 384592
        return pos + 1;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
/** This detects MySQL comments, comments that
Packit Service 384592
 * start with /x!   We just ban these now but
Packit Service 384592
 * previously we attempted to parse the inside
Packit Service 384592
 *
Packit Service 384592
 * For reference:
Packit Service 384592
 * the form of /x![anything]x/ or /x!12345[anything] x/
Packit Service 384592
 *
Packit Service 384592
 * Mysql 3 (maybe 4), allowed this:
Packit Service 384592
 *    /x!0selectx/ 1;
Packit Service 384592
 * where 0 could be any number.
Packit Service 384592
 *
Packit Service 384592
 * The last version of MySQL 3 was in 2003.
Packit Service 384592
Packit Service 384592
 * It is unclear if the MySQL 3 syntax was allowed
Packit Service 384592
 * in MySQL 4.  The last version of MySQL 4 was in 2008
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static size_t is_mysql_comment(const char *cs, const size_t len, size_t pos)
Packit Service 384592
{
Packit Service 384592
    /* so far...
Packit Service 384592
     * cs[pos] == '/' && cs[pos+1] == '*'
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if (pos + 2 >= len) {
Packit Service 384592
        /* not a mysql comment */
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (cs[pos + 2] != '!') {
Packit Service 384592
        /* not a mysql comment */
Packit Service 384592
        return 0;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * this is a mysql comment
Packit Service 384592
     *  got "/x!"
Packit Service 384592
     */
Packit Service 384592
    return 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_slash(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char* ptr;
Packit Service 384592
    size_t clen;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    const char* cur = cs + pos;
Packit Service 384592
    char ctype = TYPE_COMMENT;
Packit Service 384592
    size_t pos1 = pos + 1;
Packit Service 384592
    if (pos1 == slen || cs[pos1] != '*') {
Packit Service 384592
        return parse_operator1(sf);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * skip over initial '/x'
Packit Service 384592
     */
Packit Service 384592
    ptr = memchr2(cur + 2, slen - (pos + 2), '*', '/');
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * (ptr == NULL) causes false positive in cppcheck 1.61
Packit Service 384592
     * casting to type seems to fix it
Packit Service 384592
     */
Packit Service 384592
    if (ptr == (const char*) NULL) {
Packit Service 384592
        /* till end of line */
Packit Service 384592
        clen = slen - pos;
Packit Service 384592
    } else {
Packit Service 384592
        clen = (size_t)(ptr + 2 - cur);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * postgresql allows nested comments which makes
Packit Service 384592
     * this is incompatible with parsing so
Packit Service 384592
     * if we find a '/x' inside the coment, then
Packit Service 384592
     * make a new token.
Packit Service 384592
     *
Packit Service 384592
     * Also, Mysql's "conditional" comments for version
Packit Service 384592
     *  are an automatic black ban!
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if (memchr2(cur + 2, (size_t)(ptr - (cur + 1)), '/', '*') !=  NULL) {
Packit Service 384592
        ctype = TYPE_EVIL;
Packit Service 384592
    } else if (is_mysql_comment(cs, slen, pos)) {
Packit Service 384592
        ctype = TYPE_EVIL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    st_assign(sf->current, ctype, pos, clen, cs + pos);
Packit Service 384592
    return pos + clen;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
Packit Service 384592
static size_t parse_backslash(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * Weird MySQL alias for NULL, "\N" (capital N only)
Packit Service 384592
     */
Packit Service 384592
    if (pos + 1 < slen && cs[pos +1] == 'N') {
Packit Service 384592
        st_assign(sf->current, TYPE_NUMBER, pos, 2, cs + pos);
Packit Service 384592
        return pos + 2;
Packit Service 384592
    } else {
Packit Service 384592
        st_assign_char(sf->current, TYPE_BACKSLASH, pos, 1, cs[pos]);
Packit Service 384592
        return pos + 1;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_operator2(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    char ch;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    if (pos + 1 >= slen) {
Packit Service 384592
        return parse_operator1(sf);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (pos + 2 < slen &&
Packit Service 384592
        cs[pos] == '<' &&
Packit Service 384592
        cs[pos + 1] == '=' &&
Packit Service 384592
        cs[pos + 2] == '>') {
Packit Service 384592
        /*
Packit Service 384592
         * special 3-char operator
Packit Service 384592
         */
Packit Service 384592
        st_assign(sf->current, TYPE_OPERATOR, pos, 3, cs + pos);
Packit Service 384592
        return pos + 3;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    ch = sf->lookup(sf, LOOKUP_OPERATOR, cs + pos, 2);
Packit Service 384592
    if (ch != CHAR_NULL) {
Packit Service 384592
        st_assign(sf->current, ch, pos, 2, cs+pos);
Packit Service 384592
        return pos + 2;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * not an operator.. what to do with the two
Packit Service 384592
     * characters we got?
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if (cs[pos] == ':') {
Packit Service 384592
        /* ':' is not an operator */
Packit Service 384592
        st_assign(sf->current, TYPE_COLON, pos, 1, cs+pos);
Packit Service 384592
        return pos + 1;
Packit Service 384592
    } else {
Packit Service 384592
        /*
Packit Service 384592
         * must be a single char operator
Packit Service 384592
         */
Packit Service 384592
        return parse_operator1(sf);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Ok!   "  \"   "  one backslash = escaped!
Packit Service 384592
 *       " \\"   "  two backslash = not escaped!
Packit Service 384592
 *       "\\\"   "  three backslash = escaped!
Packit Service 384592
 */
Packit Service 384592
static int is_backslash_escaped(const char* end, const char* start)
Packit Service 384592
{
Packit Service 384592
    const char* ptr;
Packit Service 384592
    for (ptr = end; ptr >= start; ptr--) {
Packit Service 384592
        if (*ptr != '\\') {
Packit Service 384592
            break;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    /* if number of backslashes is odd, it is escaped */
Packit Service 384592
Packit Service 384592
    return (end - ptr) & 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t is_double_delim_escaped(const char* cur,  const char* end)
Packit Service 384592
{
Packit Service 384592
    return  ((cur + 1) < end) && *(cur+1) == *cur;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* Look forward for doubling of delimiter
Packit Service 384592
 *
Packit Service 384592
 * case 'foo''bar' --> foo''bar
Packit Service 384592
 *
Packit Service 384592
 * ending quote isn't duplicated (i.e. escaped)
Packit Service 384592
 * since it's the wrong char or EOL
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static size_t parse_string_core(const char *cs, const size_t len, size_t pos,
Packit Service 384592
                                stoken_t * st, char delim, size_t offset)
Packit Service 384592
{
Packit Service 384592
    /*
Packit Service 384592
     * offset is to skip the perhaps first quote char
Packit Service 384592
     */
Packit Service 384592
    const char *qpos =
Packit Service 384592
        (const char *) memchr((const void *) (cs + pos + offset), delim,
Packit Service 384592
                              len - pos - offset);
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * then keep string open/close info
Packit Service 384592
     */
Packit Service 384592
    if (offset > 0) {
Packit Service 384592
        /*
Packit Service 384592
         * this is real quote
Packit Service 384592
         */
Packit Service 384592
        st->str_open = delim;
Packit Service 384592
    } else {
Packit Service 384592
        /*
Packit Service 384592
         * this was a simulated quote
Packit Service 384592
         */
Packit Service 384592
        st->str_open = CHAR_NULL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    while (TRUE) {
Packit Service 384592
        if (qpos == NULL) {
Packit Service 384592
            /*
Packit Service 384592
             * string ended with no trailing quote
Packit Service 384592
             * assign what we have
Packit Service 384592
             */
Packit Service 384592
            st_assign(st, TYPE_STRING, pos + offset, len - pos - offset, cs + pos + offset);
Packit Service 384592
            st->str_close = CHAR_NULL;
Packit Service 384592
            return len;
Packit Service 384592
        } else if ( is_backslash_escaped(qpos - 1, cs + pos + offset)) {
Packit Service 384592
            /* keep going, move ahead one character */
Packit Service 384592
            qpos =
Packit Service 384592
                (const char *) memchr((const void *) (qpos + 1), delim,
Packit Service 384592
                                      (size_t)((cs + len) - (qpos + 1)));
Packit Service 384592
            continue;
Packit Service 384592
        } else if (is_double_delim_escaped(qpos, cs + len)) {
Packit Service 384592
            /* keep going, move ahead two characters */
Packit Service 384592
            qpos =
Packit Service 384592
                (const char *) memchr((const void *) (qpos + 2), delim,
Packit Service 384592
                                      (size_t)((cs + len) - (qpos + 2)));
Packit Service 384592
            continue;
Packit Service 384592
        } else {
Packit Service 384592
            /* hey it's a normal string */
Packit Service 384592
            st_assign(st, TYPE_STRING, pos + offset,
Packit Service 384592
                      (size_t)(qpos - (cs + pos + offset)), cs + pos + offset);
Packit Service 384592
            st->str_close = delim;
Packit Service 384592
            return (size_t)(qpos - cs + 1);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Used when first char is a ' or "
Packit Service 384592
 */
Packit Service 384592
static size_t parse_string(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * assert cs[pos] == single or double quote
Packit Service 384592
     */
Packit Service 384592
    return parse_string_core(cs, slen, pos, sf->current, cs[pos], 1);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Used when first char is:
Packit Service 384592
 *    N or n:  mysql "National Character set"
Packit Service 384592
 *    E     :  psql  "Escaped String"
Packit Service 384592
 */
Packit Service 384592
static size_t parse_estring(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    if (pos + 2 >= slen || cs[pos+1] != CHAR_SINGLE) {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
    return parse_string_core(cs, slen, pos, sf->current, CHAR_SINGLE, 2);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_ustring(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    if (pos + 2 < slen && cs[pos+1] == '&' && cs[pos+2] == '\'') {
Packit Service 384592
        sf->pos += 2;
Packit Service 384592
        pos = parse_string(sf);
Packit Service 384592
        sf->current->str_open = 'u';
Packit Service 384592
        if (sf->current->str_close == '\'') {
Packit Service 384592
            sf->current->str_close = 'u';
Packit Service 384592
        }
Packit Service 384592
        return pos;
Packit Service 384592
    } else {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_qstring_core(struct libinjection_sqli_state * sf, size_t offset)
Packit Service 384592
{
Packit Service 384592
    char ch;
Packit Service 384592
    const char *strend;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos + offset;
Packit Service 384592
Packit Service 384592
    /* if we are already at end of string..
Packit Service 384592
       if current char is not q or Q
Packit Service 384592
       if we don't have 2 more chars
Packit Service 384592
       if char2 != a single quote
Packit Service 384592
       then, just treat as word
Packit Service 384592
    */
Packit Service 384592
    if (pos >= slen ||
Packit Service 384592
        (cs[pos] != 'q' && cs[pos] != 'Q') ||
Packit Service 384592
        pos + 2 >= slen ||
Packit Service 384592
        cs[pos + 1] != '\'') {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    ch = cs[pos + 2];
Packit Service 384592
Packit Service 384592
    /* the ch > 127 is un-needed since
Packit Service 384592
     * we assume char is signed
Packit Service 384592
     */
Packit Service 384592
    if (ch < 33 /* || ch > 127 */) {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
    switch (ch) {
Packit Service 384592
    case '(' : ch = ')'; break;
Packit Service 384592
    case '[' : ch = ']'; break;
Packit Service 384592
    case '{' : ch = '}'; break;
Packit Service 384592
    case '<' : ch = '>'; break;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    strend = memchr2(cs + pos + 3, slen - pos - 3, ch, '\'');
Packit Service 384592
    if (strend == NULL) {
Packit Service 384592
        st_assign(sf->current, TYPE_STRING, pos + 3, slen - pos - 3, cs + pos + 3);
Packit Service 384592
        sf->current->str_open = 'q';
Packit Service 384592
        sf->current->str_close = CHAR_NULL;
Packit Service 384592
        return slen;
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_STRING, pos + 3, (size_t)(strend - cs) - pos -  3, cs + pos + 3);
Packit Service 384592
        sf->current->str_open = 'q';
Packit Service 384592
        sf->current->str_close = 'q';
Packit Service 384592
        return (size_t)(strend - cs + 2);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * Oracle's q string
Packit Service 384592
 */
Packit Service 384592
static size_t parse_qstring(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    return parse_qstring_core(sf, 0);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * mysql's N'STRING' or
Packit Service 384592
 * ...  Oracle's nq string
Packit Service 384592
 */
Packit Service 384592
static size_t parse_nqstring(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    if (pos + 2 < slen && sf->s[pos+1] == CHAR_SINGLE) {
Packit Service 384592
        return parse_estring(sf);
Packit Service 384592
    }
Packit Service 384592
    return parse_qstring_core(sf, 1);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * binary literal string
Packit Service 384592
 * re: [bB]'[01]*'
Packit Service 384592
 */
Packit Service 384592
static size_t parse_bstring(struct libinjection_sqli_state *sf)
Packit Service 384592
{
Packit Service 384592
    size_t wlen;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    size_t slen = sf->slen;
Packit Service 384592
Packit Service 384592
    /* need at least 2 more characters
Packit Service 384592
     * if next char isn't a single quote, then
Packit Service 384592
     * continue as normal word
Packit Service 384592
     */
Packit Service 384592
    if (pos + 2 >= slen || cs[pos+1] !=  '\'') {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    wlen = strlenspn(cs + pos + 2, sf->slen - pos - 2, "01");
Packit Service 384592
    if (pos + 2 + wlen  >= slen || cs[pos + 2 + wlen] != '\'') {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
    st_assign(sf->current, TYPE_NUMBER, pos, wlen + 3, cs + pos);
Packit Service 384592
    return pos + 2 + wlen + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * hex literal string
Packit Service 384592
 * re: [xX]'[0123456789abcdefABCDEF]*'
Packit Service 384592
 * mysql has requirement of having EVEN number of chars,
Packit Service 384592
 *  but pgsql does not
Packit Service 384592
 */
Packit Service 384592
static size_t parse_xstring(struct libinjection_sqli_state *sf)
Packit Service 384592
{
Packit Service 384592
    size_t wlen;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    size_t slen = sf->slen;
Packit Service 384592
Packit Service 384592
    /* need at least 2 more characters
Packit Service 384592
     * if next char isn't a single quote, then
Packit Service 384592
     * continue as normal word
Packit Service 384592
     */
Packit Service 384592
    if (pos + 2 >= slen || cs[pos+1] !=  '\'') {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    wlen = strlenspn(cs + pos + 2, sf->slen - pos - 2, "0123456789ABCDEFabcdef");
Packit Service 384592
    if (pos + 2 + wlen  >= slen || cs[pos + 2 + wlen] != '\'') {
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    }
Packit Service 384592
    st_assign(sf->current, TYPE_NUMBER, pos, wlen + 3, cs + pos);
Packit Service 384592
    return pos + 2 + wlen + 1;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * This handles MS SQLSERVER bracket words
Packit Service 384592
 * http://stackoverflow.com/questions/3551284/sql-serverwhat-do-brackets-mean-around-column-name
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static size_t parse_bword(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    const char* endptr = (const char*) memchr(cs + pos, ']', sf->slen - pos);
Packit Service 384592
    if (endptr == NULL) {
Packit Service 384592
        st_assign(sf->current, TYPE_BAREWORD, pos, sf->slen - pos, cs + pos);
Packit Service 384592
        return sf->slen;
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_BAREWORD, pos, (size_t)(endptr - cs) - pos + 1, cs + pos);
Packit Service 384592
        return (size_t)((endptr - cs) + 1);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_word(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    char ch;
Packit Service 384592
    char delim;
Packit Service 384592
    size_t i;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    size_t wlen = strlencspn(cs + pos, sf->slen - pos,
Packit Service 384592
                             " []{}<>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r\"\240\000");
Packit Service 384592
Packit Service 384592
    st_assign(sf->current, TYPE_BAREWORD, pos, wlen, cs + pos);
Packit Service 384592
Packit Service 384592
    /* now we need to look inside what we good for "." and "`"
Packit Service 384592
     * and see if what is before is a keyword or not
Packit Service 384592
     */
Packit Service 384592
    for (i =0; i < sf->current->len; ++i) {
Packit Service 384592
        delim = sf->current->val[i];
Packit Service 384592
        if (delim == '.' || delim == '`') {
Packit Service 384592
            ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, i);
Packit Service 384592
            if (ch != TYPE_NONE && ch != TYPE_BAREWORD) {
Packit Service 384592
                /* needed for swig */
Packit Service 384592
                st_clear(sf->current);
Packit Service 384592
                /*
Packit Service 384592
                 * we got something like "SELECT.1"
Packit Service 384592
                 * or SELECT`column`
Packit Service 384592
                 */
Packit Service 384592
                st_assign(sf->current, ch, pos, i, cs + pos);
Packit Service 384592
                return pos + i;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * do normal lookup with word including '.'
Packit Service 384592
     */
Packit Service 384592
    if (wlen < LIBINJECTION_SQLI_TOKEN_SIZE) {
Packit Service 384592
Packit Service 384592
        ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, wlen);
Packit Service 384592
        if (ch == CHAR_NULL) {
Packit Service 384592
            ch = TYPE_BAREWORD;
Packit Service 384592
        }
Packit Service 384592
        sf->current->type = ch;
Packit Service 384592
    }
Packit Service 384592
    return pos + wlen;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* MySQL backticks are a cross between string and
Packit Service 384592
 * and a bare word.
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static size_t parse_tick(struct libinjection_sqli_state* sf)
Packit Service 384592
{
Packit Service 384592
    size_t pos =  parse_string_core(sf->s, sf->slen, sf->pos, sf->current, CHAR_TICK, 1);
Packit Service 384592
Packit Service 384592
    /* we could check to see if start and end of
Packit Service 384592
     * of string are both "`", i.e. make sure we have
Packit Service 384592
     * matching set.  `foo` vs. `foo
Packit Service 384592
     * but I don't think it matters much
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    /* check value of string to see if it's a keyword,
Packit Service 384592
     * function, operator, etc
Packit Service 384592
     */
Packit Service 384592
    char ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, sf->current->len);
Packit Service 384592
    if (ch == TYPE_FUNCTION) {
Packit Service 384592
        /* if it's a function, then convert token */
Packit Service 384592
        sf->current->type = TYPE_FUNCTION;
Packit Service 384592
    } else {
Packit Service 384592
        /* otherwise it's a 'n' type -- mysql treats
Packit Service 384592
         * everything as a bare word
Packit Service 384592
         */
Packit Service 384592
        sf->current->type = TYPE_BAREWORD;
Packit Service 384592
    }
Packit Service 384592
    return pos;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_var(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    size_t xlen;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos + 1;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * var_count is only used to reconstruct
Packit Service 384592
     * the input.  It counts the number of '@'
Packit Service 384592
     * seen 0 in the case of NULL, 1 or 2
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * move past optional other '@'
Packit Service 384592
     */
Packit Service 384592
    if (pos < slen && cs[pos] == '@') {
Packit Service 384592
        pos += 1;
Packit Service 384592
        sf->current->count = 2;
Packit Service 384592
    } else {
Packit Service 384592
        sf->current->count = 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * MySQL allows @@`version`
Packit Service 384592
     */
Packit Service 384592
    if (pos < slen) {
Packit Service 384592
        if (cs[pos] == '`') {
Packit Service 384592
            sf->pos = pos;
Packit Service 384592
            pos = parse_tick(sf);
Packit Service 384592
            sf->current->type = TYPE_VARIABLE;
Packit Service 384592
            return pos;
Packit Service 384592
        } else if (cs[pos] == CHAR_SINGLE || cs[pos] == CHAR_DOUBLE) {
Packit Service 384592
            sf->pos = pos;
Packit Service 384592
            pos = parse_string(sf);
Packit Service 384592
            sf->current->type = TYPE_VARIABLE;
Packit Service 384592
            return pos;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
Packit Service 384592
    xlen = strlencspn(cs + pos, slen - pos,
Packit Service 384592
                     " <>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r'`\"");
Packit Service 384592
    if (xlen == 0) {
Packit Service 384592
        st_assign(sf->current, TYPE_VARIABLE, pos, 0, cs + pos);
Packit Service 384592
        return pos;
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_VARIABLE, pos, xlen, cs + pos);
Packit Service 384592
        return pos + xlen;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_money(struct libinjection_sqli_state *sf)
Packit Service 384592
{
Packit Service 384592
    size_t xlen;
Packit Service 384592
    const char* strend;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
Packit Service 384592
    if (pos + 1 == slen) {
Packit Service 384592
        /* end of line */
Packit Service 384592
        st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$');
Packit Service 384592
        return slen;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * $1,000.00 or $1.000,00 ok!
Packit Service 384592
     * This also parses $....,,,111 but that's ok
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    xlen = strlenspn(cs + pos + 1, slen - pos - 1, "0123456789.,");
Packit Service 384592
    if (xlen == 0) {
Packit Service 384592
        if (cs[pos + 1] == '$') {
Packit Service 384592
            /* we have $$ .. find ending $$ and make string */
Packit Service 384592
            strend = memchr2(cs + pos + 2, slen - pos -2, '$', '$');
Packit Service 384592
            if (strend == NULL) {
Packit Service 384592
                /* fell off edge */
Packit Service 384592
                st_assign(sf->current, TYPE_STRING, pos + 2, slen - (pos + 2), cs + pos + 2);
Packit Service 384592
                sf->current->str_open = '$';
Packit Service 384592
                sf->current->str_close = CHAR_NULL;
Packit Service 384592
                return slen;
Packit Service 384592
            } else {
Packit Service 384592
                st_assign(sf->current, TYPE_STRING, pos + 2,
Packit Service 384592
                          (size_t)(strend - (cs + pos + 2)), cs + pos + 2);
Packit Service 384592
                sf->current->str_open = '$';
Packit Service 384592
                sf->current->str_close = '$';
Packit Service 384592
                return (size_t)(strend - cs + 2);
Packit Service 384592
            }
Packit Service 384592
        } else {
Packit Service 384592
            /* ok it's not a number or '$$', but maybe it's pgsql "$ quoted strings" */
Packit Service 384592
            xlen = strlenspn(cs + pos + 1, slen - pos - 1, "abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
Packit Service 384592
            if (xlen == 0) {
Packit Service 384592
                /* hmm it's "$" _something_ .. just add $ and keep going*/
Packit Service 384592
                st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$');
Packit Service 384592
                return pos + 1;
Packit Service 384592
            }
Packit Service 384592
            /* we have $foobar????? */
Packit Service 384592
            /* is it $foobar$ */
Packit Service 384592
            if (pos + xlen + 1 == slen || cs[pos+xlen+1] != '$') {
Packit Service 384592
                /* not $foobar$, or fell off edge */
Packit Service 384592
                st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$');
Packit Service 384592
                return pos + 1;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* we have $foobar$ ... find it again */
Packit Service 384592
            strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2);
Packit Service 384592
Packit Service 384592
            if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) {
Packit Service 384592
                /* fell off edge */
Packit Service 384592
                st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2);
Packit Service 384592
                sf->current->str_open = '$';
Packit Service 384592
                sf->current->str_close = CHAR_NULL;
Packit Service 384592
                return slen;
Packit Service 384592
            } else {
Packit Service 384592
                /* got one */
Packit Service 384592
                st_assign(sf->current, TYPE_STRING, pos+xlen+2,
Packit Service 384592
                          (size_t)(strend - (cs + pos + xlen + 2)), cs+pos+xlen+2);
Packit Service 384592
                sf->current->str_open = '$';
Packit Service 384592
                sf->current->str_close = '$';
Packit Service 384592
                return (size_t)((strend + xlen + 2) - cs);
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    } else if (xlen == 1 && cs[pos + 1] == '.') {
Packit Service 384592
        /* $. should parsed as a word */
Packit Service 384592
        return parse_word(sf);
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_NUMBER, pos, 1 + xlen, cs + pos);
Packit Service 384592
        return pos + 1 + xlen;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static size_t parse_number(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    size_t xlen;
Packit Service 384592
    size_t start;
Packit Service 384592
    const char* digits = NULL;
Packit Service 384592
    const char *cs = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
    size_t pos = sf->pos;
Packit Service 384592
    int have_e = 0;
Packit Service 384592
    int have_exp = 0;
Packit Service 384592
Packit Service 384592
    /* cs[pos] == '0' has 1/10 chance of being true,
Packit Service 384592
     * while pos+1< slen is almost always true
Packit Service 384592
     */
Packit Service 384592
    if (cs[pos] == '0' && pos + 1 < slen) {
Packit Service 384592
        if (cs[pos + 1] == 'X' || cs[pos + 1] == 'x') {
Packit Service 384592
            digits = "0123456789ABCDEFabcdef";
Packit Service 384592
        } else if (cs[pos + 1] == 'B' || cs[pos + 1] == 'b') {
Packit Service 384592
            digits = "01";
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (digits) {
Packit Service 384592
            xlen = strlenspn(cs + pos + 2, slen - pos - 2, digits);
Packit Service 384592
            if (xlen == 0) {
Packit Service 384592
                st_assign(sf->current, TYPE_BAREWORD, pos, 2, cs + pos);
Packit Service 384592
                return pos + 2;
Packit Service 384592
            } else {
Packit Service 384592
                st_assign(sf->current, TYPE_NUMBER, pos, 2 + xlen, cs + pos);
Packit Service 384592
                return pos + 2 + xlen;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    start = pos;
Packit Service 384592
    while (pos < slen && ISDIGIT(cs[pos])) {
Packit Service 384592
        pos += 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (pos < slen && cs[pos] == '.') {
Packit Service 384592
        pos += 1;
Packit Service 384592
        while (pos < slen && ISDIGIT(cs[pos])) {
Packit Service 384592
            pos += 1;
Packit Service 384592
        }
Packit Service 384592
        if (pos - start == 1) {
Packit Service 384592
            /* only one character read so far */
Packit Service 384592
            st_assign_char(sf->current, TYPE_DOT, start, 1, '.');
Packit Service 384592
            return pos;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (pos < slen) {
Packit Service 384592
        if (cs[pos] == 'E' || cs[pos] == 'e') {
Packit Service 384592
            have_e = 1;
Packit Service 384592
            pos += 1;
Packit Service 384592
            if (pos < slen && (cs[pos] == '+' || cs[pos] == '-')) {
Packit Service 384592
                pos += 1;
Packit Service 384592
            }
Packit Service 384592
            while (pos < slen && ISDIGIT(cs[pos])) {
Packit Service 384592
                have_exp = 1;
Packit Service 384592
                pos += 1;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* oracle's ending float or double suffix
Packit Service 384592
     * http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements003.htm#i139891
Packit Service 384592
     */
Packit Service 384592
    if (pos < slen && (cs[pos] == 'd' || cs[pos] == 'D' || cs[pos] == 'f' || cs[pos] == 'F')) {
Packit Service 384592
        if (pos + 1 == slen) {
Packit Service 384592
            /* line ends evaluate "... 1.2f$" as '1.2f' */
Packit Service 384592
            pos += 1;
Packit Service 384592
        } else if ((char_is_white(cs[pos+1]) || cs[pos+1] == ';')) {
Packit Service 384592
            /*
Packit Service 384592
             * easy case, evaluate "... 1.2f ... as '1.2f'
Packit Service 384592
             */
Packit Service 384592
            pos += 1;
Packit Service 384592
        } else if (cs[pos+1] == 'u' || cs[pos+1] == 'U') {
Packit Service 384592
            /*
Packit Service 384592
             * a bit of a hack but makes '1fUNION' parse as '1f UNION'
Packit Service 384592
             */
Packit Service 384592
            pos += 1;
Packit Service 384592
        } else {
Packit Service 384592
            /* it's like "123FROM" */
Packit Service 384592
            /* parse as "123" only */
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (have_e == 1 && have_exp == 0) {
Packit Service 384592
        /* very special form of
Packit Service 384592
         * "1234.e"
Packit Service 384592
         * "10.10E"
Packit Service 384592
         * ".E"
Packit Service 384592
         * this is a WORD not a number!! */
Packit Service 384592
        st_assign(sf->current, TYPE_BAREWORD, start, pos - start, cs + start);
Packit Service 384592
    } else {
Packit Service 384592
        st_assign(sf->current, TYPE_NUMBER, start, pos - start, cs + start);
Packit Service 384592
    }
Packit Service 384592
    return pos;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * API to return version.  This allows us to increment the version
Packit Service 384592
 * without having to regenerated the SWIG (or other binding) in minor
Packit Service 384592
 * releases.
Packit Service 384592
 */
Packit Service 384592
const char* libinjection_version()
Packit Service 384592
{
Packit Service 384592
    return LIBINJECTION_VERSION;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    pt2Function fnptr;
Packit Service 384592
    size_t *pos = &sf->pos;
Packit Service 384592
    stoken_t *current = sf->current;
Packit Service 384592
    const char *s = sf->s;
Packit Service 384592
    const size_t slen = sf->slen;
Packit Service 384592
Packit Service 384592
    if (slen == 0) {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    st_clear(current);
Packit Service 384592
    sf->current = current;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * if we are at beginning of string
Packit Service 384592
     *  and in single-quote or double quote mode
Packit Service 384592
     *  then pretend the input starts with a quote
Packit Service 384592
     */
Packit Service 384592
    if (*pos == 0 && (sf->flags & (FLAG_QUOTE_SINGLE | FLAG_QUOTE_DOUBLE))) {
Packit Service 384592
        *pos = parse_string_core(s, slen, 0, current, flag2delim(sf->flags), 0);
Packit Service 384592
        sf->stats_tokens += 1;
Packit Service 384592
        return TRUE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    while (*pos < slen) {
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * get current character
Packit Service 384592
         */
Packit Service 384592
        const unsigned char ch = (unsigned char) (s[*pos]);
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * look up the parser, and call it
Packit Service 384592
         *
Packit Service 384592
         * Porting Note: this is mapping of char to function
Packit Service 384592
         *   charparsers[ch]()
Packit Service 384592
         */
Packit Service 384592
        fnptr = char_parse_map[ch];
Packit Service 384592
Packit Service 384592
        *pos = (*fnptr) (sf);
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         *
Packit Service 384592
         */
Packit Service 384592
        if (current->type != CHAR_NULL) {
Packit Service 384592
            sf->stats_tokens += 1;
Packit Service 384592
            return TRUE;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    return FALSE;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
void libinjection_sqli_init(struct libinjection_sqli_state * sf, const char *s, size_t len, int flags)
Packit Service 384592
{
Packit Service 384592
    if (flags == 0) {
Packit Service 384592
        flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    memset(sf, 0, sizeof(struct libinjection_sqli_state));
Packit Service 384592
    sf->s        = s;
Packit Service 384592
    sf->slen     = len;
Packit Service 384592
    sf->lookup   = libinjection_sqli_lookup_word;
Packit Service 384592
    sf->userdata = 0;
Packit Service 384592
    sf->flags    = flags;
Packit Service 384592
    sf->current  = &(sf->tokenvec[0]);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
void libinjection_sqli_reset(struct libinjection_sqli_state * sf, int flags)
Packit Service 384592
{
Packit Service 384592
    void *userdata = sf->userdata;
Packit Service 384592
    ptr_lookup_fn lookup = sf->lookup;;
Packit Service 384592
Packit Service 384592
    if (flags == 0) {
Packit Service 384592
        flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI;
Packit Service 384592
    }
Packit Service 384592
    libinjection_sqli_init(sf, sf->s, sf->slen, flags);
Packit Service 384592
    sf->lookup = lookup;
Packit Service 384592
    sf->userdata = userdata;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
void libinjection_sqli_callback(struct libinjection_sqli_state * sf, ptr_lookup_fn fn, void* userdata)
Packit Service 384592
{
Packit Service 384592
    if (fn == NULL) {
Packit Service 384592
        sf->lookup = libinjection_sqli_lookup_word;
Packit Service 384592
        sf->userdata = (void*)(NULL);
Packit Service 384592
    } else {
Packit Service 384592
        sf->lookup = fn;
Packit Service 384592
        sf->userdata = userdata;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/** See if two tokens can be merged since they are compound SQL phrases.
Packit Service 384592
 *
Packit Service 384592
 * This takes two tokens, and, if they are the right type,
Packit Service 384592
 * merges their values together.  Then checks to see if the
Packit Service 384592
 * new value is special using the PHRASES mapping.
Packit Service 384592
 *
Packit Service 384592
 * Example: "UNION" + "ALL" ==> "UNION ALL"
Packit Service 384592
 *
Packit Service 384592
 * C Security Notes: this is safe to use C-strings (null-terminated)
Packit Service 384592
 *  since the types involved by definition do not have embedded nulls
Packit Service 384592
 *  (e.g. there is no keyword with embedded null)
Packit Service 384592
 *
Packit Service 384592
 * Porting Notes: since this is C, it's oddly complicated.
Packit Service 384592
 *  This is just:  multikeywords[token.value + ' ' + token2.value]
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, stoken_t * b)
Packit Service 384592
{
Packit Service 384592
    size_t sz1;
Packit Service 384592
    size_t sz2;
Packit Service 384592
    size_t sz3;
Packit Service 384592
    char tmp[LIBINJECTION_SQLI_TOKEN_SIZE];
Packit Service 384592
    char ch;
Packit Service 384592
Packit Service 384592
    /* first token is of right type? */
Packit Service 384592
    if (!
Packit Service 384592
        (a->type == TYPE_KEYWORD ||
Packit Service 384592
         a->type == TYPE_BAREWORD ||
Packit Service 384592
         a->type == TYPE_OPERATOR ||
Packit Service 384592
         a->type == TYPE_UNION ||
Packit Service 384592
         a->type == TYPE_FUNCTION ||
Packit Service 384592
         a->type == TYPE_EXPRESSION ||
Packit Service 384592
         a->type == TYPE_TSQL ||
Packit Service 384592
         a->type == TYPE_SQLTYPE)) {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (!
Packit Service 384592
        (b->type == TYPE_KEYWORD ||
Packit Service 384592
         b->type == TYPE_BAREWORD ||
Packit Service 384592
         b->type == TYPE_OPERATOR ||
Packit Service 384592
         b->type == TYPE_UNION ||
Packit Service 384592
         b->type == TYPE_FUNCTION ||
Packit Service 384592
         b->type == TYPE_EXPRESSION ||
Packit Service 384592
         b->type == TYPE_TSQL ||
Packit Service 384592
         b->type == TYPE_SQLTYPE ||
Packit Service 384592
         b->type == TYPE_LOGIC_OPERATOR)) {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    sz1 = a->len;
Packit Service 384592
    sz2 = b->len;
Packit Service 384592
    sz3 = sz1 + sz2 + 1; /* +1 for space in the middle */
Packit Service 384592
    if (sz3 >= LIBINJECTION_SQLI_TOKEN_SIZE) { /* make sure there is room for ending null */
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
    /*
Packit Service 384592
     * oddly annoying  last.val + ' ' + current.val
Packit Service 384592
     */
Packit Service 384592
    memcpy(tmp, a->val, sz1);
Packit Service 384592
    tmp[sz1] = ' ';
Packit Service 384592
    memcpy(tmp + sz1 + 1, b->val, sz2);
Packit Service 384592
    tmp[sz3] = CHAR_NULL;
Packit Service 384592
    ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3);
Packit Service 384592
Packit Service 384592
    if (ch != CHAR_NULL) {
Packit Service 384592
        st_assign(a, ch, a->pos, sz3, tmp);
Packit Service 384592
        return TRUE;
Packit Service 384592
    } else {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
Packit Service 384592
{
Packit Service 384592
    stoken_t last_comment;
Packit Service 384592
Packit Service 384592
    /* POS is the position of where the NEXT token goes */
Packit Service 384592
    size_t pos = 0;
Packit Service 384592
Packit Service 384592
    /* LEFT is a count of how many tokens that are already
Packit Service 384592
       folded or processed (i.e. part of the fingerprint) */
Packit Service 384592
    size_t left =  0;
Packit Service 384592
Packit Service 384592
    int more = 1;
Packit Service 384592
Packit Service 384592
    st_clear(&last_comment);
Packit Service 384592
Packit Service 384592
    /* Skip all initial comments, right-parens ( and unary operators
Packit Service 384592
     *
Packit Service 384592
     */
Packit Service 384592
    sf->current = &(sf->tokenvec[0]);
Packit Service 384592
    while (more) {
Packit Service 384592
        more = libinjection_sqli_tokenize(sf);
Packit Service 384592
        if ( ! (sf->current->type == TYPE_COMMENT ||
Packit Service 384592
                sf->current->type == TYPE_LEFTPARENS ||
Packit Service 384592
                sf->current->type == TYPE_SQLTYPE ||
Packit Service 384592
                st_is_unary_op(sf->current))) {
Packit Service 384592
            break;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    if (! more) {
Packit Service 384592
        /* If input was only comments, unary or (, then exit */
Packit Service 384592
        return 0;
Packit Service 384592
    } else {
Packit Service 384592
        /* it's some other token */
Packit Service 384592
        pos += 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    while (1) {
Packit Service 384592
        FOLD_DEBUG;
Packit Service 384592
Packit Service 384592
        /* do we have all the max number of tokens?  if so do
Packit Service 384592
         * some special cases for 5 tokens
Packit Service 384592
         */
Packit Service 384592
        if (pos >= LIBINJECTION_SQLI_MAX_TOKENS) {
Packit Service 384592
            if (
Packit Service 384592
                (
Packit Service 384592
                    sf->tokenvec[0].type == TYPE_NUMBER &&
Packit Service 384592
                    (sf->tokenvec[1].type == TYPE_OPERATOR || sf->tokenvec[1].type == TYPE_COMMA) &&
Packit Service 384592
                    sf->tokenvec[2].type == TYPE_LEFTPARENS &&
Packit Service 384592
                    sf->tokenvec[3].type == TYPE_NUMBER &&
Packit Service 384592
                    sf->tokenvec[4].type == TYPE_RIGHTPARENS
Packit Service 384592
                    ) ||
Packit Service 384592
                (
Packit Service 384592
                    sf->tokenvec[0].type == TYPE_BAREWORD &&
Packit Service 384592
                    sf->tokenvec[1].type == TYPE_OPERATOR &&
Packit Service 384592
                    sf->tokenvec[2].type == TYPE_LEFTPARENS &&
Packit Service 384592
                    (sf->tokenvec[3].type == TYPE_BAREWORD || sf->tokenvec[3].type == TYPE_NUMBER) &&
Packit Service 384592
                    sf->tokenvec[4].type == TYPE_RIGHTPARENS
Packit Service 384592
                    ) ||
Packit Service 384592
                (
Packit Service 384592
                    sf->tokenvec[0].type == TYPE_NUMBER &&
Packit Service 384592
                    sf->tokenvec[1].type == TYPE_RIGHTPARENS &&
Packit Service 384592
                    sf->tokenvec[2].type == TYPE_COMMA &&
Packit Service 384592
                    sf->tokenvec[3].type == TYPE_LEFTPARENS &&
Packit Service 384592
                    sf->tokenvec[4].type == TYPE_NUMBER
Packit Service 384592
                    ) ||
Packit Service 384592
                (
Packit Service 384592
                    sf->tokenvec[0].type == TYPE_BAREWORD &&
Packit Service 384592
                    sf->tokenvec[1].type == TYPE_RIGHTPARENS &&
Packit Service 384592
                    sf->tokenvec[2].type == TYPE_OPERATOR &&
Packit Service 384592
                    sf->tokenvec[3].type == TYPE_LEFTPARENS &&
Packit Service 384592
                    sf->tokenvec[4].type == TYPE_BAREWORD
Packit Service 384592
                    )
Packit Service 384592
                )
Packit Service 384592
            {
Packit Service 384592
                if (pos > LIBINJECTION_SQLI_MAX_TOKENS) {
Packit Service 384592
		    st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
Packit Service 384592
                    pos = 2;
Packit Service 384592
                    left = 0;
Packit Service 384592
                } else {
Packit Service 384592
                    pos = 1;
Packit Service 384592
                    left = 0;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        if (! more || left >= LIBINJECTION_SQLI_MAX_TOKENS) {
Packit Service 384592
            left = pos;
Packit Service 384592
            break;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* get up to two tokens */
Packit Service 384592
        while (more && pos <= LIBINJECTION_SQLI_MAX_TOKENS && (pos - left) < 2) {
Packit Service 384592
            sf->current = &(sf->tokenvec[pos]);
Packit Service 384592
            more = libinjection_sqli_tokenize(sf);
Packit Service 384592
            if (more) {
Packit Service 384592
                if (sf->current->type == TYPE_COMMENT) {
Packit Service 384592
                    st_copy(&last_comment, sf->current);
Packit Service 384592
                } else {
Packit Service 384592
                    last_comment.type = CHAR_NULL;
Packit Service 384592
                    pos += 1;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        FOLD_DEBUG;
Packit Service 384592
        /* did we get 2 tokens? if not then we are done */
Packit Service 384592
        if (pos - left < 2) {
Packit Service 384592
            left = pos;
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* FOLD: "ss" -> "s"
Packit Service 384592
         * "foo" "bar" is valid SQL
Packit Service 384592
         * just ignore second string
Packit Service 384592
         */
Packit Service 384592
        if (sf->tokenvec[left].type == TYPE_STRING && sf->tokenvec[left+1].type == TYPE_STRING) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && sf->tokenvec[left+1].type == TYPE_SEMICOLON) {
Packit Service 384592
            /* not sure how various engines handle
Packit Service 384592
             * 'select 1;;drop table foo' or
Packit Service 384592
             * 'select 1; /x foo x/; drop table foo'
Packit Service 384592
             * to prevent surprises, just fold away repeated semicolons
Packit Service 384592
             */
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_OPERATOR ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR) &&
Packit Service 384592
                   (st_is_unary_op(&sf->tokenvec[left+1]) ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_SQLTYPE)) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_LEFTPARENS &&
Packit Service 384592
                   st_is_unary_op(&sf->tokenvec[left+1])) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            if (left > 0) {
Packit Service 384592
                left -= 1;
Packit Service 384592
            }
Packit Service 384592
            continue;
Packit Service 384592
        } else if (syntax_merge_words(sf, &sf->tokenvec[left], &sf->tokenvec[left+1])) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            if (left > 0) {
Packit Service 384592
                left -= 1;
Packit Service 384592
            }
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_SEMICOLON &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_FUNCTION &&
Packit Service 384592
		   (sf->tokenvec[left+1].val[0] == 'I' ||
Packit Service 384592
		    sf->tokenvec[left+1].val[0] == 'i' ) &&
Packit Service 384592
		   (sf->tokenvec[left+1].val[1] == 'F' ||
Packit Service 384592
                    sf->tokenvec[left+1].val[1] == 'f' )) {
Packit Service 384592
            /* IF is normally a function, except in Transact-SQL where it can be used as a
Packit Service 384592
             * standalone control flow operator, e.g. ; IF 1=1 ...
Packit Service 384592
             * if found after a semicolon, convert from 'f' type to 'T' type
Packit Service 384592
             */
Packit Service 384592
            sf->tokenvec[left+1].type = TYPE_TSQL;
Packit Service 384592
            /* left += 2; */
Packit Service 384592
            continue; /* reparse everything, but we probably can advance left, and pos */
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_LEFTPARENS && (
Packit Service 384592
                       /* TSQL functions but common enough to be column names */
Packit Service 384592
                       cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
Packit Service 384592
                       /* Function in MYSQL */
Packit Service 384592
                       cstrcasecmp("DATABASE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("PASSWORD", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
Packit Service 384592
                       /* Mysql words that act as a variable and are a function */
Packit Service 384592
Packit Service 384592
                       /* TSQL current_users is fake-variable */
Packit Service 384592
                       /* http://msdn.microsoft.com/en-us/library/ms176050.aspx */
Packit Service 384592
                       cstrcasecmp("CURRENT_USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("CURRENT_DATE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("CURRENT_TIME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("CURRENT_TIMESTAMP", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("LOCALTIME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("LOCALTIMESTAMP", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0
Packit Service 384592
                       )) {
Packit Service 384592
Packit Service 384592
            /* pos is the same
Packit Service 384592
             * other conversions need to go here... for instance
Packit Service 384592
             * password CAN be a function, coalesce CAN be a function
Packit Service 384592
             */
Packit Service 384592
            sf->tokenvec[left].type = TYPE_FUNCTION;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_KEYWORD && (
Packit Service 384592
                       cstrcasecmp("IN", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("NOT IN", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0
Packit Service 384592
                       )) {
Packit Service 384592
Packit Service 384592
            if (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) {
Packit Service 384592
                /* got .... IN ( ...  (or 'NOT IN')
Packit Service 384592
                 * it's an operator
Packit Service 384592
                 */
Packit Service 384592
                sf->tokenvec[left].type = TYPE_OPERATOR;
Packit Service 384592
            } else {
Packit Service 384592
                /*
Packit Service 384592
                 * it's a nothing
Packit Service 384592
                 */
Packit Service 384592
                sf->tokenvec[left].type = TYPE_BAREWORD;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            /* "IN" can be used as "IN BOOLEAN MODE" for mysql
Packit Service 384592
             *  in which case merging of words can be done later
Packit Service 384592
             * other wise it acts as an equality operator __ IN (values..)
Packit Service 384592
             *
Packit Service 384592
             * here we got "IN" "(" so it's an operator.
Packit Service 384592
             * also back track to handle "NOT IN"
Packit Service 384592
             * might need to do the same with like
Packit Service 384592
             * two use cases   "foo" LIKE "BAR" (normal operator)
Packit Service 384592
             *  "foo" = LIKE(1,2)
Packit Service 384592
             */
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_OPERATOR) && (
Packit Service 384592
                       cstrcasecmp("LIKE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
Packit Service 384592
                       cstrcasecmp("NOT LIKE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0)) {
Packit Service 384592
            if (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) {
Packit Service 384592
                /* SELECT LIKE(...
Packit Service 384592
                 * it's a function
Packit Service 384592
                 */
Packit Service 384592
                sf->tokenvec[left].type = TYPE_FUNCTION;
Packit Service 384592
            }
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_SQLTYPE &&
Packit Service 384592
                   (sf->tokenvec[left+1].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_SQLTYPE ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_LEFTPARENS ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_FUNCTION ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_VARIABLE ||
Packit Service 384592
                    sf->tokenvec[left+1].type == TYPE_STRING))  {
Packit Service 384592
            st_copy(&sf->tokenvec[left], &sf->tokenvec[left+1]);
Packit Service 384592
            pos -= 1;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_COLLATE &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_BAREWORD) {
Packit Service 384592
            /*
Packit Service 384592
             * there are too many collation types.. so if the bareword has a "_"
Packit Service 384592
             * then it's TYPE_SQLTYPE
Packit Service 384592
             */
Packit Service 384592
            if (strchr(sf->tokenvec[left+1].val, '_') != NULL) {
Packit Service 384592
                sf->tokenvec[left+1].type = TYPE_SQLTYPE;
Packit Service 384592
                left = 0;
Packit Service 384592
            }
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_BACKSLASH) {
Packit Service 384592
            if (st_is_arithmetic_op(&(sf->tokenvec[left+1]))) {
Packit Service 384592
                /* very weird case in TSQL where '\%1' is parsed as '0 % 1', etc */
Packit Service 384592
                sf->tokenvec[left].type = TYPE_NUMBER;
Packit Service 384592
            } else {
Packit Service 384592
                /* just ignore it.. Again T-SQL seems to parse \1 as "1" */
Packit Service 384592
                st_copy(&sf->tokenvec[left], &sf->tokenvec[left+1]);
Packit Service 384592
                pos -= 1;
Packit Service 384592
                sf->stats_folds += 1;
Packit Service 384592
            }
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_LEFTPARENS &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_LEFTPARENS) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_RIGHTPARENS &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_RIGHTPARENS) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_LEFTBRACE &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_BAREWORD) {
Packit Service 384592
Packit Service 384592
            /*
Packit Service 384592
             * MySQL Degenerate case --
Packit Service 384592
             *
Packit Service 384592
             *   select { ``.``.id };  -- valid !!!
Packit Service 384592
             *   select { ``.``.``.id };  -- invalid
Packit Service 384592
             *   select ``.``.id; -- invalid
Packit Service 384592
             *   select { ``.id }; -- invalid
Packit Service 384592
             *
Packit Service 384592
             * so it appears {``.``.id} is a magic case
Packit Service 384592
             * I suspect this is "current database, current table, field id"
Packit Service 384592
             *
Packit Service 384592
             * The folding code can't look at more than 3 tokens, and
Packit Service 384592
             * I don't want to make two passes.
Packit Service 384592
             *
Packit Service 384592
             * Since "{ ``" so rare, we are just going to blacklist it.
Packit Service 384592
             *
Packit Service 384592
             * Highly likely this will need revisiting!
Packit Service 384592
             *
Packit Service 384592
             * CREDIT @rsalgado 2013-11-25
Packit Service 384592
             */
Packit Service 384592
            if (sf->tokenvec[left+1].len == 0) {
Packit Service 384592
                sf->tokenvec[left+1].type = TYPE_EVIL;
Packit Service 384592
                return (int)(left+2);
Packit Service 384592
            }
Packit Service 384592
            /* weird ODBC / MYSQL  {foo expr} --> expr
Packit Service 384592
             * but for this rule we just strip away the "{ foo" part
Packit Service 384592
             */
Packit Service 384592
            left = 0;
Packit Service 384592
            pos -= 2;
Packit Service 384592
            sf->stats_folds += 2;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left+1].type == TYPE_RIGHTBRACE) {
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            sf->stats_folds += 1;
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* all cases of handing 2 tokens is done
Packit Service 384592
           and nothing matched.  Get one more token
Packit Service 384592
        */
Packit Service 384592
        FOLD_DEBUG;
Packit Service 384592
        while (more && pos <= LIBINJECTION_SQLI_MAX_TOKENS && pos - left < 3) {
Packit Service 384592
            sf->current = &(sf->tokenvec[pos]);
Packit Service 384592
            more = libinjection_sqli_tokenize(sf);
Packit Service 384592
            if (more) {
Packit Service 384592
                if (sf->current->type == TYPE_COMMENT) {
Packit Service 384592
                    st_copy(&last_comment, sf->current);
Packit Service 384592
                } else {
Packit Service 384592
                    last_comment.type = CHAR_NULL;
Packit Service 384592
                    pos += 1;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* do we have three tokens? If not then we are done */
Packit Service 384592
        if (pos -left < 3) {
Packit Service 384592
            left = pos;
Packit Service 384592
            continue;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * now look for three token folding
Packit Service 384592
         */
Packit Service 384592
        if (sf->tokenvec[left].type == TYPE_NUMBER &&
Packit Service 384592
            sf->tokenvec[left+1].type == TYPE_OPERATOR &&
Packit Service 384592
            sf->tokenvec[left+2].type == TYPE_NUMBER) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_OPERATOR &&
Packit Service 384592
                   sf->tokenvec[left+1].type != TYPE_LEFTPARENS &&
Packit Service 384592
                   sf->tokenvec[left+2].type == TYPE_OPERATOR) {
Packit Service 384592
            left = 0;
Packit Service 384592
            pos -= 2;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR &&
Packit Service 384592
                   sf->tokenvec[left+2].type == TYPE_LOGIC_OPERATOR) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_VARIABLE &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_OPERATOR &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_VARIABLE ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_BAREWORD)) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_NUMBER ) &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_OPERATOR &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_BAREWORD)) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_VARIABLE ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_STRING) &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_OPERATOR &&
Packit Service 384592
                   streq(sf->tokenvec[left+1].val, "::") &&
Packit Service 384592
                   sf->tokenvec[left+2].type == TYPE_SQLTYPE) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            sf->stats_folds += 2;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_STRING ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_VARIABLE) &&
Packit Service 384592
                   sf->tokenvec[left+1].type == TYPE_COMMA &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_STRING ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_VARIABLE)) {
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_EXPRESSION ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_GROUP ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_COMMA) &&
Packit Service 384592
                   st_is_unary_op(&sf->tokenvec[left+1]) &&
Packit Service 384592
                   sf->tokenvec[left+2].type == TYPE_LEFTPARENS) {
Packit Service 384592
            /* got something like SELECT + (, LIMIT + (
Packit Service 384592
             * remove unary operator
Packit Service 384592
             */
Packit Service 384592
            st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_KEYWORD ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_EXPRESSION ||
Packit Service 384592
                    sf->tokenvec[left].type == TYPE_GROUP )  &&
Packit Service 384592
                   st_is_unary_op(&sf->tokenvec[left+1]) &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_VARIABLE ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_STRING ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_FUNCTION )) {
Packit Service 384592
            /* remove unary operators
Packit Service 384592
             * select - 1
Packit Service 384592
             */
Packit Service 384592
            st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_COMMA &&
Packit Service 384592
                   st_is_unary_op(&sf->tokenvec[left+1]) &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_NUMBER ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_BAREWORD ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_VARIABLE ||
Packit Service 384592
                    sf->tokenvec[left+2].type == TYPE_STRING)) {
Packit Service 384592
            /*
Packit Service 384592
             * interesting case    turn ", -1"  ->> ",1" PLUS we need to back up
Packit Service 384592
             * one token if possible to see if more folding can be done
Packit Service 384592
             * "1,-1" --> "1"
Packit Service 384592
             */
Packit Service 384592
            st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
Packit Service 384592
            left = 0;
Packit Service 384592
            /* pos is >= 3 so this is safe */
Packit Service 384592
            assert(pos >= 3);
Packit Service 384592
            pos -= 3;
Packit Service 384592
            continue;
Packit Service 384592
        } else if (sf->tokenvec[left].type == TYPE_COMMA &&
Packit Service 384592
                   st_is_unary_op(&sf->tokenvec[left+1]) &&
Packit Service 384592
                   sf->tokenvec[left+2].type == TYPE_FUNCTION) {
Packit Service 384592
Packit Service 384592
            /* Separate case from above since you end up with
Packit Service 384592
             * 1,-sin(1) --> 1 (1)
Packit Service 384592
             * Here, just do
Packit Service 384592
             * 1,-sin(1) --> 1,sin(1)
Packit Service 384592
             * just remove unary operator
Packit Service 384592
             */
Packit Service 384592
            st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_BAREWORD) &&
Packit Service 384592
                   (sf->tokenvec[left+1].type == TYPE_DOT) &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_BAREWORD)) {
Packit Service 384592
            /* ignore the '.n'
Packit Service 384592
             * typically is this databasename.table
Packit Service 384592
             */
Packit Service 384592
            assert(pos >= 3);
Packit Service 384592
            pos -= 2;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_EXPRESSION) &&
Packit Service 384592
                   (sf->tokenvec[left+1].type == TYPE_DOT) &&
Packit Service 384592
                   (sf->tokenvec[left+2].type == TYPE_BAREWORD)) {
Packit Service 384592
            /* select . `foo` --> select `foo` */
Packit Service 384592
            st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
Packit Service 384592
            pos -= 1;
Packit Service 384592
            left = 0;
Packit Service 384592
            continue;
Packit Service 384592
        } else if ((sf->tokenvec[left].type == TYPE_FUNCTION) &&
Packit Service 384592
                   (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) &&
Packit Service 384592
                   (sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) {
Packit Service 384592
            /*
Packit Service 384592
             * whats going on here
Packit Service 384592
             * Some SQL functions like USER() have 0 args
Packit Service 384592
             * if we get User(foo), then User is not a function
Packit Service 384592
             * This should be expanded since it eliminated a lot of false
Packit Service 384592
             * positives. 
Packit Service 384592
             */
Packit Service 384592
            if  (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) {
Packit Service 384592
                sf->tokenvec[left].type = TYPE_BAREWORD;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /* no folding -- assume left-most token is
Packit Service 384592
           is good, now use the existing 2 tokens --
Packit Service 384592
           do not get another
Packit Service 384592
        */
Packit Service 384592
Packit Service 384592
        left += 1;
Packit Service 384592
Packit Service 384592
    } /* while(1) */
Packit Service 384592
Packit Service 384592
    /* if we have 4 or less tokens, and we had a comment token
Packit Service 384592
     * at the end, add it back
Packit Service 384592
     */
Packit Service 384592
Packit Service 384592
    if (left < LIBINJECTION_SQLI_MAX_TOKENS && last_comment.type == TYPE_COMMENT) {
Packit Service 384592
        st_copy(&sf->tokenvec[left], &last_comment);
Packit Service 384592
        left += 1;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* sometimes we grab a 6th token to help
Packit Service 384592
       determine the type of token 5.
Packit Service 384592
    */
Packit Service 384592
    if (left > LIBINJECTION_SQLI_MAX_TOKENS) {
Packit Service 384592
        left = LIBINJECTION_SQLI_MAX_TOKENS;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return (int)left;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/* secondary api: detects SQLi in a string, GIVEN a context.
Packit Service 384592
 *
Packit Service 384592
 * A context can be:
Packit Service 384592
 *   *  CHAR_NULL (\0), process as is
Packit Service 384592
 *   *  CHAR_SINGLE ('), process pretending input started with a
Packit Service 384592
 *          single quote.
Packit Service 384592
 *   *  CHAR_DOUBLE ("), process pretending input started with a
Packit Service 384592
 *          double quote.
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
const char* libinjection_sqli_fingerprint(struct libinjection_sqli_state * sql_state, int flags)
Packit Service 384592
{
Packit Service 384592
    int i;
Packit Service 384592
    int tlen = 0;
Packit Service 384592
Packit Service 384592
    libinjection_sqli_reset(sql_state, flags);
Packit Service 384592
Packit Service 384592
    tlen = libinjection_sqli_fold(sql_state);
Packit Service 384592
Packit Service 384592
    /* Check for magic PHP backquote comment
Packit Service 384592
     * If:
Packit Service 384592
     * * last token is of type "bareword"
Packit Service 384592
     * * And is quoted in a backtick
Packit Service 384592
     * * And isn't closed
Packit Service 384592
     * * And it's empty?
Packit Service 384592
     * Then convert it to comment
Packit Service 384592
     */
Packit Service 384592
    if (tlen > 2 &&
Packit Service 384592
        sql_state->tokenvec[tlen-1].type == TYPE_BAREWORD &&
Packit Service 384592
        sql_state->tokenvec[tlen-1].str_open == CHAR_TICK &&
Packit Service 384592
        sql_state->tokenvec[tlen-1].len == 0 &&
Packit Service 384592
        sql_state->tokenvec[tlen-1].str_close == CHAR_NULL) {
Packit Service 384592
        sql_state->tokenvec[tlen-1].type = TYPE_COMMENT;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    for (i = 0; i < tlen; ++i) {
Packit Service 384592
        sql_state->fingerprint[i] = sql_state->tokenvec[i].type;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * make the fingerprint pattern a c-string (null delimited)
Packit Service 384592
     */
Packit Service 384592
    sql_state->fingerprint[tlen] = CHAR_NULL;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * check for 'X' in pattern, and then
Packit Service 384592
     * clear out all tokens
Packit Service 384592
     *
Packit Service 384592
     * this means parsing could not be done
Packit Service 384592
     * accurately due to pgsql's double comments
Packit Service 384592
     * or other syntax that isn't consistent.
Packit Service 384592
     * Should be very rare false positive
Packit Service 384592
     */
Packit Service 384592
    if (strchr(sql_state->fingerprint, TYPE_EVIL)) {
Packit Service 384592
        /*  needed for SWIG */
Packit Service 384592
        memset((void*)sql_state->fingerprint, 0, LIBINJECTION_SQLI_MAX_TOKENS + 1);
Packit Service 384592
        memset((void*)sql_state->tokenvec[0].val, 0, LIBINJECTION_SQLI_TOKEN_SIZE);
Packit Service 384592
Packit Service 384592
        sql_state->fingerprint[0] = TYPE_EVIL;
Packit Service 384592
Packit Service 384592
        sql_state->tokenvec[0].type = TYPE_EVIL;
Packit Service 384592
        sql_state->tokenvec[0].val[0] = TYPE_EVIL;
Packit Service 384592
        sql_state->tokenvec[1].type = CHAR_NULL;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
Packit Service 384592
    return sql_state->fingerprint;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_sqli_check_fingerprint(struct libinjection_sqli_state* sql_state)
Packit Service 384592
{
Packit Service 384592
    return libinjection_sqli_blacklist(sql_state) &&
Packit Service 384592
        libinjection_sqli_not_whitelist(sql_state);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
char libinjection_sqli_lookup_word(struct libinjection_sqli_state *sql_state, int lookup_type,
Packit Service 384592
                                   const char* str, size_t len)
Packit Service 384592
{
Packit Service 384592
    if (lookup_type == LOOKUP_FINGERPRINT) {
Packit Service 384592
        return libinjection_sqli_check_fingerprint(sql_state) ? 'X' : '\0';
Packit Service 384592
    } else {
Packit Service 384592
        return bsearch_keyword_type(str, len, sql_keywords, sql_keywords_sz);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state)
Packit Service 384592
{
Packit Service 384592
    /*
Packit Service 384592
     * use minimum of 8 bytes to make sure gcc -fstack-protector
Packit Service 384592
     * works correctly
Packit Service 384592
     */
Packit Service 384592
    char fp2[8];
Packit Service 384592
    char ch;
Packit Service 384592
    size_t i;
Packit Service 384592
    size_t len = strlen(sql_state->fingerprint);
Packit Service 384592
    int patmatch;
Packit Service 384592
Packit Service 384592
    if (len < 1) {
Packit Service 384592
        sql_state->reason = __LINE__;
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
      to keep everything compatible, convert the
Packit Service 384592
      v0 fingerprint pattern to v1
Packit Service 384592
      v0: up to 5 chars, mixed case
Packit Service 384592
      v1: 1 char is '0', up to 5 more chars, upper case
Packit Service 384592
    */
Packit Service 384592
Packit Service 384592
    fp2[0] = '0';
Packit Service 384592
    for (i = 0; i < len; ++i) {
Packit Service 384592
        ch = sql_state->fingerprint[i];
Packit Service 384592
        if (ch >= 'a' && ch <= 'z') {
Packit Service 384592
            ch -= 0x20;
Packit Service 384592
        }
Packit Service 384592
        fp2[i+1] = ch;
Packit Service 384592
    }
Packit Service 384592
    fp2[i+1] = '\0';
Packit Service 384592
Packit Service 384592
    patmatch = is_keyword(fp2, len + 1) == TYPE_FINGERPRINT;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * No match.
Packit Service 384592
     *
Packit Service 384592
     * Set sql_state->reason to current line number
Packit Service 384592
     * only for debugging purposes.
Packit Service 384592
     */
Packit Service 384592
    if (!patmatch) {
Packit Service 384592
        sql_state->reason = __LINE__;
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    return TRUE;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * return TRUE if SQLi, false is benign
Packit Service 384592
 */
Packit Service 384592
int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
Packit Service 384592
{
Packit Service 384592
    /*
Packit Service 384592
     * We assume we got a SQLi match
Packit Service 384592
     * This next part just helps reduce false positives.
Packit Service 384592
     *
Packit Service 384592
     */
Packit Service 384592
    char ch;
Packit Service 384592
    size_t tlen = strlen(sql_state->fingerprint);
Packit Service 384592
Packit Service 384592
    if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) {
Packit Service 384592
        /*
Packit Service 384592
         * if ending comment is contains 'sp_password' then it's SQLi!
Packit Service 384592
         * MS Audit log apparently ignores anything with
Packit Service 384592
         * 'sp_password' in it. Unable to find primary reference to
Packit Service 384592
         * this "feature" of SQL Server but seems to be known SQLi
Packit Service 384592
         * technique
Packit Service 384592
         */
Packit Service 384592
        if (my_memmem(sql_state->s, sql_state->slen,
Packit Service 384592
                      "sp_password", strlen("sp_password"))) {
Packit Service 384592
            sql_state->reason = __LINE__;
Packit Service 384592
            return TRUE;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    switch (tlen) {
Packit Service 384592
    case 2:{
Packit Service 384592
        /*
Packit Service 384592
         * case 2 are "very small SQLi" which make them
Packit Service 384592
         * hard to tell from normal input...
Packit Service 384592
         */
Packit Service 384592
Packit Service 384592
        if (sql_state->fingerprint[1] == TYPE_UNION) {
Packit Service 384592
            if (sql_state->stats_tokens == 2) {
Packit Service 384592
                /* not sure why but 1U comes up in SQLi attack
Packit Service 384592
                 * likely part of parameter splitting/etc.
Packit Service 384592
                 * lots of reasons why "1 union" might be normal
Packit Service 384592
                 * input, so beep only if other SQLi things are present
Packit Service 384592
                 */
Packit Service 384592
                /* it really is a number and 'union'
Packit Service 384592
                 * other wise it has folding or comments
Packit Service 384592
                 */
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return FALSE;
Packit Service 384592
            } else {
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        /*
Packit Service 384592
         * if 'comment' is '#' ignore.. too many FP
Packit Service 384592
         */
Packit Service 384592
        if (sql_state->tokenvec[1].val[0] == '#') {
Packit Service 384592
            sql_state->reason = __LINE__;
Packit Service 384592
            return FALSE;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * for fingerprint like 'nc', only comments of /x are treated
Packit Service 384592
         * as SQL... ending comments of "--" and "#" are not SQLi
Packit Service 384592
         */
Packit Service 384592
        if (sql_state->tokenvec[0].type == TYPE_BAREWORD &&
Packit Service 384592
            sql_state->tokenvec[1].type == TYPE_COMMENT &&
Packit Service 384592
            sql_state->tokenvec[1].val[0] != '/') {
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return FALSE;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * if '1c' ends with '/x' then it's SQLi
Packit Service 384592
         */
Packit Service 384592
        if (sql_state->tokenvec[0].type == TYPE_NUMBER &&
Packit Service 384592
            sql_state->tokenvec[1].type == TYPE_COMMENT &&
Packit Service 384592
            sql_state->tokenvec[1].val[0] == '/') {
Packit Service 384592
            return TRUE;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /**
Packit Service 384592
         * there are some odd base64-looking query string values
Packit Service 384592
         * 1234-ABCDEFEhfhihwuefi--
Packit Service 384592
         * which evaluate to "1c"... these are not SQLi
Packit Service 384592
         * but 1234-- probably is.
Packit Service 384592
         * Make sure the "1" in "1c" is actually a true decimal number
Packit Service 384592
         *
Packit Service 384592
         * Need to check -original- string since the folding step
Packit Service 384592
         * may have merged tokens, e.g. "1+FOO" is folded into "1"
Packit Service 384592
         *
Packit Service 384592
         * Note: evasion: 1*1--
Packit Service 384592
         */
Packit Service 384592
        if (sql_state->tokenvec[0].type == TYPE_NUMBER &&
Packit Service 384592
            sql_state->tokenvec[1].type == TYPE_COMMENT) {
Packit Service 384592
            if (sql_state->stats_tokens > 2) {
Packit Service 384592
                /* we have some folding going on, highly likely SQLi */
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
            /*
Packit Service 384592
             * we check that next character after the number is either whitespace,
Packit Service 384592
             * or '/' or a '-' ==> SQLi.
Packit Service 384592
             */
Packit Service 384592
            ch = sql_state->s[sql_state->tokenvec[0].len];
Packit Service 384592
            if ( ch <= 32 ) {
Packit Service 384592
                /* next char was whitespace,e.g. "1234 --"
Packit Service 384592
                 * this isn't exactly correct.. ideally we should skip over all whitespace
Packit Service 384592
                 * but this seems to be ok for now
Packit Service 384592
                 */
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
            if (ch == '/' && sql_state->s[sql_state->tokenvec[0].len + 1] == '*') {
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
            if (ch == '-' && sql_state->s[sql_state->tokenvec[0].len + 1] == '-') {
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
Packit Service 384592
            sql_state->reason = __LINE__;
Packit Service 384592
            return FALSE;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        /*
Packit Service 384592
         * detect obvious SQLi scans.. many people put '--' in plain text
Packit Service 384592
         * so only detect if input ends with '--', e.g. 1-- but not 1-- foo
Packit Service 384592
         */
Packit Service 384592
        if ((sql_state->tokenvec[1].len > 2)
Packit Service 384592
            && sql_state->tokenvec[1].val[0] == '-') {
Packit Service 384592
            sql_state->reason = __LINE__;
Packit Service 384592
            return FALSE;
Packit Service 384592
        }
Packit Service 384592
Packit Service 384592
        break;
Packit Service 384592
    } /* case 2 */
Packit Service 384592
    case 3:{
Packit Service 384592
        /*
Packit Service 384592
         * ...foo' + 'bar...
Packit Service 384592
         * no opening quote, no closing quote
Packit Service 384592
         * and each string has data
Packit Service 384592
         */
Packit Service 384592
Packit Service 384592
        if (streq(sql_state->fingerprint, "sos")
Packit Service 384592
            || streq(sql_state->fingerprint, "s&s")) {
Packit Service 384592
Packit Service 384592
                if ((sql_state->tokenvec[0].str_open == CHAR_NULL)
Packit Service 384592
                    && (sql_state->tokenvec[2].str_close == CHAR_NULL)
Packit Service 384592
                    && (sql_state->tokenvec[0].str_close == sql_state->tokenvec[2].str_open)) {
Packit Service 384592
                    /*
Packit Service 384592
                     * if ....foo" + "bar....
Packit Service 384592
                     */
Packit Service 384592
                    sql_state->reason = __LINE__;
Packit Service 384592
                    return TRUE;
Packit Service 384592
                }
Packit Service 384592
                if (sql_state->stats_tokens == 3) {
Packit Service 384592
                    sql_state->reason = __LINE__;
Packit Service 384592
                    return FALSE;
Packit Service 384592
                }
Packit Service 384592
Packit Service 384592
                /*
Packit Service 384592
                 * not SQLi
Packit Service 384592
                 */
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return FALSE;
Packit Service 384592
        } else if (streq(sql_state->fingerprint, "s&n") ||
Packit Service 384592
                   streq(sql_state->fingerprint, "n&1") ||
Packit Service 384592
                   streq(sql_state->fingerprint, "1&1") ||
Packit Service 384592
                   streq(sql_state->fingerprint, "1&v") ||
Packit Service 384592
                   streq(sql_state->fingerprint, "1&s")) {
Packit Service 384592
            /* 'sexy and 17' not SQLi
Packit Service 384592
             * 'sexy and 17<18'  SQLi
Packit Service 384592
             */
Packit Service 384592
            if (sql_state->stats_tokens == 3) {
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return FALSE;
Packit Service 384592
            }
Packit Service 384592
        } else if (sql_state->tokenvec[1].type == TYPE_KEYWORD) {
Packit Service 384592
            if ((sql_state->tokenvec[1].len < 5) ||
Packit Service 384592
                cstrcasecmp("INTO", sql_state->tokenvec[1].val, 4)) {
Packit Service 384592
                /* if it's not "INTO OUTFILE", or "INTO DUMPFILE" (MySQL)
Packit Service 384592
                 * then treat as safe
Packit Service 384592
                 */
Packit Service 384592
                sql_state->reason = __LINE__;
Packit Service 384592
                return FALSE;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        break;
Packit Service 384592
    }  /* case 3 */
Packit Service 384592
    case 4:
Packit Service 384592
    case 5: {
Packit Service 384592
        /* nothing right now */
Packit Service 384592
        break;
Packit Service 384592
    } /* case 5 */
Packit Service 384592
    } /* end switch */
Packit Service 384592
Packit Service 384592
    return TRUE;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**  Main API, detects SQLi in an input.
Packit Service 384592
 *
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static int reparse_as_mysql(struct libinjection_sqli_state * sql_state)
Packit Service 384592
{
Packit Service 384592
    return sql_state->stats_comment_ddx ||
Packit Service 384592
        sql_state->stats_comment_hash;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 * This function is mostly use with SWIG
Packit Service 384592
 */
Packit Service 384592
struct libinjection_sqli_token*
Packit Service 384592
libinjection_sqli_get_token(struct libinjection_sqli_state * sql_state, int i)
Packit Service 384592
{
Packit Service 384592
    if (i < 0 || i > (int)LIBINJECTION_SQLI_MAX_TOKENS) {
Packit Service 384592
        return NULL;
Packit Service 384592
    }
Packit Service 384592
    return &(sql_state->tokenvec[i]);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_is_sqli(struct libinjection_sqli_state * sql_state)
Packit Service 384592
{
Packit Service 384592
    const char *s = sql_state->s;
Packit Service 384592
    size_t slen = sql_state->slen;
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * no input? not SQLi
Packit Service 384592
     */
Packit Service 384592
    if (slen == 0) {
Packit Service 384592
        return FALSE;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * test input "as-is"
Packit Service 384592
     */
Packit Service 384592
    libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_ANSI);
Packit Service 384592
    if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
Packit Service 384592
                          sql_state->fingerprint, strlen(sql_state->fingerprint))) {
Packit Service 384592
        return TRUE;
Packit Service 384592
    } else if (reparse_as_mysql(sql_state)) {
Packit Service 384592
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_MYSQL);
Packit Service 384592
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
Packit Service 384592
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
Packit Service 384592
            return TRUE;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * if input has a single_quote, then
Packit Service 384592
     * test as if input was actually '
Packit Service 384592
     * example: if input if "1' = 1", then pretend it's
Packit Service 384592
     *   "'1' = 1"
Packit Service 384592
     * Porting Notes: example the same as doing
Packit Service 384592
     *   is_string_sqli(sql_state, "'" + s, slen+1, NULL, fn, arg)
Packit Service 384592
     *
Packit Service 384592
     */
Packit Service 384592
    if (memchr(s, CHAR_SINGLE, slen)) {
Packit Service 384592
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI);
Packit Service 384592
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
Packit Service 384592
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
Packit Service 384592
            return TRUE;
Packit Service 384592
        } else if (reparse_as_mysql(sql_state)) {
Packit Service 384592
            libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL);
Packit Service 384592
            if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
Packit Service 384592
                                  sql_state->fingerprint, strlen(sql_state->fingerprint))) {
Packit Service 384592
                return TRUE;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * same as above but with a double-quote "
Packit Service 384592
     */
Packit Service 384592
    if (memchr(s, CHAR_DOUBLE, slen)) {
Packit Service 384592
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL);
Packit Service 384592
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
Packit Service 384592
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
Packit Service 384592
            return TRUE;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /*
Packit Service 384592
     * Hurray, input is not SQLi
Packit Service 384592
     */
Packit Service 384592
    return FALSE;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
int libinjection_sqli(const char* input, size_t slen, char fingerprint[])
Packit Service 384592
{
Packit Service 384592
    int issqli;
Packit Service 384592
    struct libinjection_sqli_state state;
Packit Service 384592
Packit Service 384592
    libinjection_sqli_init(&state, input, slen, 0);
Packit Service 384592
    issqli = libinjection_is_sqli(&state);
Packit Service 384592
    if (issqli) {
Packit Service 384592
        strcpy(fingerprint, state.fingerprint);
Packit Service 384592
    } else {
Packit Service 384592
        fingerprint[0] = '\0';
Packit Service 384592
    }
Packit Service 384592
    return issqli;
Packit Service 384592
}