示例#1
0
static enum proto_parse_status pg_parse_error(struct sql_proto_info *info, struct cursor *cursor, size_t len)
{
    enum proto_parse_status status;
    info->set_values |= SQL_REQUEST_STATUS;
    info->request_status = SQL_REQUEST_ERROR;

    size_t size = 0;
    char *str;

    while (size <= len) {
        size++;
        if (size > len) return PROTO_PARSE_ERR;
        char type = cursor_read_u8(cursor);
        if (type == 0x00) {
            break;
        }
        status = cursor_read_string(cursor, &str, len - size);
        if (status != PROTO_OK) return status;
        size += strlen(str) + 1;
        switch (type) {
            case 'C':
                info->set_values |= SQL_ERROR_SQL_STATUS;
                snprintf(info->error_sql_status, sizeof(info->error_sql_status), "%s", str);
                break;
            case 'M':
                info->set_values |= SQL_ERROR_MESSAGE;
                snprintf(info->error_message, sizeof(info->error_message), "%s", str);
                break;
        }
    }
    return PROTO_OK;
}
示例#2
0
static enum proto_parse_status pg_parse_startup(struct pgsql_parser *pg_parser, struct sql_proto_info *info, unsigned way, uint8_t const *payload, size_t cap_len, size_t unused_ wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    info->msg_type = SQL_STARTUP;

    struct cursor cursor;
    cursor_ctor(&cursor, payload, cap_len);
    uint8_t type;
    size_t len;
    enum proto_parse_status status = cursor_read_msg(&cursor, &type, &len);
    if (status != PROTO_OK) return status;

    /* In this phase, we expect to see from the client the pwd message,
     * and from the server the authentication request. */
    if (info->is_query) {   // password message
        if (type != 'p') return PROTO_PARSE_ERR;
        char *passwd;
        status = cursor_read_string(&cursor, &passwd, len);
        if (status == PROTO_PARSE_ERR) return status;
        if (status == PROTO_TOO_SHORT) {    // in case of GSSAPI or SSPI authentication then the "string" is in fact arbitrary bytes
            passwd = "GSSAPI/SSPI";
        }
        info->set_values |= SQL_PASSWD;
        snprintf(info->u.startup.passwd, sizeof(info->u.startup.passwd), "%s", passwd);
    } else {    // Authentication request
        SLOG(LOG_DEBUG, "Authentification response from server with type %c", type);
        if (len < 4) return PROTO_PARSE_ERR;
        if (type == 'E') {
            status = pg_parse_error(info, &cursor, len);
            if (status != PROTO_OK) return status;
        } else if (type == 'R' ) {
            // We don't care about the auth method, we just want to know when auth is complete
            uint32_t auth_type = cursor_read_u32n(&cursor);
            if (auth_type == 0) {   // AuthenticationOK
                pg_parser->phase = QUERY;   // we don't wait for the ReadyForQuery msg since we are not interrested in following messages
                info->set_values |= SQL_REQUEST_STATUS;
                info->request_status = SQL_REQUEST_COMPLETE;
            }
        } else {
            SLOG(LOG_DEBUG, "Unknown startup message with type %c", type);
            return PROTO_PARSE_ERR;
        }
    }

    // Discard the rest of the packet
    return proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
}
示例#3
0
文件: skinny.c 项目: haiwanxue/junkie
static enum proto_parse_status skinny_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    struct skinny_parser *skinny_parser = DOWNCAST(parser, parser, skinny_parser);

#   define SKINNY_HDR_SIZE 8
#   define SKINNY_MIN_MSG_SIZE 12
    if (wire_len < SKINNY_MIN_MSG_SIZE) {
        streambuf_set_restart(&skinny_parser->sbuf, way, packet, true); // wait for more
        return PROTO_OK;
    }
    if (cap_len < SKINNY_MIN_MSG_SIZE) return PROTO_TOO_SHORT;

    struct cursor curs;
    cursor_ctor(&curs, packet, cap_len);
    uint32_t msg_len = cursor_read_u32le(&curs);
    enum skinny_header_version header_ver = cursor_read_u32le(&curs);
    enum skinny_msgid msg_id = cursor_read_u32le(&curs);
    SLOG(LOG_DEBUG, "New SKINNY msg of size %"PRIu32", msgid=0x%"PRIx32, msg_len, msg_id);
    if (header_ver != SKINNY_BASIC && header_ver != SKINNY_CM7_TYPE_A && header_ver != SKINNY_CM7_TYPE_B && header_ver != SKINNY_CM7_TYPE_C) return PROTO_PARSE_ERR;
    if (msg_len < 4 || msg_len > SKINNY_MAX_HDR_SIZE /* guestimated */) return PROTO_PARSE_ERR;
    if (wire_len < msg_len + SKINNY_HDR_SIZE) return PROTO_TOO_SHORT; // wait for the message to be complete
    // Ok we have what looks like a skinny message in there
    struct skinny_proto_info info;
    skinny_proto_info_ctor(&info, parser, parent, SKINNY_HDR_SIZE, msg_len, msg_id, header_ver);
    switch (msg_id) {
        case SKINNY_STATION_KEY_PAD_BUTTON:
            if (curs.cap_len < 12) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_NEW_KEY_PAD | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.new_key_pad = cursor_read_u32le(&curs);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_CALL_STATE:
            if (curs.cap_len < 12) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALL_STATE | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.call_state = cursor_read_u32le(&curs);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            SLOG(LOG_DEBUG, "New call state: %s", skinny_call_state_2_str(info.call_state));
            break;
        case SKINNY_MGR_CLOSE_RECV_CHANNEL:
        case SKINNY_MGR_STOP_MEDIA_TRANSMIT:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_START_MEDIA_TRANSMIT:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            enum proto_parse_status status = read_channel(skinny_parser, FROM_MGR, &info, &curs, now);
            if (PROTO_OK != status) return status;
            break;
        case SKINNY_STATION_OPEN_RECV_CHANNEL_ACK:
            if (curs.cap_len < 4) return PROTO_TOO_SHORT;
            uint32_t open_status = cursor_read_u32le(&curs);
            if (open_status == 0 /* Ok */) {
                enum proto_parse_status status = read_channel(skinny_parser, FROM_STATION, &info, &curs, now);
                if (PROTO_OK != status) return status;
                info.set_values |= SKINNY_PASS_THRU_ID;
                if (curs.cap_len < 4) return PROTO_TOO_SHORT;
                info.pass_thru_id = cursor_read_u32le(&curs);
            }
            break;
        case SKINNY_MGR_OPEN_RECV_CHANNEL:
            if (curs.cap_len < 8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CONFERENCE_ID | SKINNY_PASS_THRU_ID;
            info.conf_id = cursor_read_u32le(&curs);
            info.pass_thru_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_DIALED_NUMBER:
#           define DIALED_NUMBER_SIZE 24
            if (curs.cap_len < DIALED_NUMBER_SIZE+8) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALLED_PARTY | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            // 24 chars, terminated with 0 (if fits)
            snprintf(info.called_party, sizeof(info.called_party), "%.*s", (int)DIALED_NUMBER_SIZE, curs.head);
            cursor_drop(&curs, DIALED_NUMBER_SIZE);
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            break;
        case SKINNY_MGR_CALL_INFO:
            if (curs.cap_len < 8 + 4 + 5*4) return PROTO_TOO_SHORT;
            info.set_values |= SKINNY_CALLING_PARTY | SKINNY_CALLED_PARTY | SKINNY_LINE_INSTANCE | SKINNY_CALL_ID;
            info.line_instance = cursor_read_u32le(&curs);
            info.call_id = cursor_read_u32le(&curs);
            cursor_drop(&curs, 4 + 5*4);  // drop Call Type and 5 unknown fields
            // From now on, informations are nul terminated strings
            if (PROTO_OK != (status = read_string(info.calling_party, sizeof(info.calling_party), &curs))) return status; // Calling party
            if (header_ver == SKINNY_CM7_TYPE_A || header_ver == SKINNY_CM7_TYPE_B || header_ver == SKINNY_CM7_TYPE_C) {
                    cursor_read_string(&curs, NULL, 24); // Drop calling party voice mailbox
            }
            if (PROTO_OK != (status = read_string(info.called_party,  sizeof(info.called_party),  &curs))) return status; // Called party
            // discard the rest of informations
            break;
        default:
            break;
    }
    (void)proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);

    streambuf_set_restart(&skinny_parser->sbuf, way, packet + SKINNY_HDR_SIZE + msg_len, false); // go to next msg

    return PROTO_OK;
}
示例#4
0
static enum proto_parse_status pg_parse_query(struct pgsql_parser *pg_parser, struct sql_proto_info *info, unsigned way, uint8_t const *payload, size_t cap_len, size_t unused_ wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    enum proto_parse_status status;
    info->msg_type = SQL_QUERY;

    struct cursor cursor;
    cursor_ctor(&cursor, payload, cap_len);
    uint8_t type;
    size_t len;

    /* In this phase, we are looking for SimpleQuery from the client and Data from the server.
     * This is very simplistic, to be completed later with more interresting query types.
     * Also, the client can send a termination request. */
    if (info->is_query) {
        status = cursor_read_msg(&cursor, &type, &len);
        if (status != PROTO_OK) return status;

        if (type == 'Q') {  // simple query
            char *sql;
            status = cursor_read_string(&cursor, &sql, len);
            if (status != PROTO_OK) return status;
            info->set_values |= SQL_SQL;
            snprintf(info->u.query.sql, sizeof(info->u.query.sql), "%s", sql);
        } else if (type == 'X') {
            info->msg_type = SQL_EXIT;
            info->set_values |= SQL_REQUEST_STATUS;
            info->request_status = SQL_REQUEST_COMPLETE;
            pg_parser->phase = EXIT;
        } else return PROTO_PARSE_ERR;
    } else {
        while (! cursor_is_empty(&cursor)) {
            uint8_t const *const msg_start = cursor.head;
            status = cursor_read_msg(&cursor, &type, &len);
            if (status == PROTO_PARSE_ERR) return status;
            else if (status == PROTO_TOO_SHORT) {
                SLOG(LOG_DEBUG, "Payload too short for parsing message, will restart");
                status = proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);    // ack what we had so far
                streambuf_set_restart(&pg_parser->sbuf, way, msg_start, true);
                return PROTO_OK;
            }

            uint8_t const *const msg_end = cursor.head + len;
            if (type == 'T') {  // row description (fetch nb_fields)
                if (len < 2) return PROTO_PARSE_ERR;
                info->u.query.nb_fields = cursor_read_u16n(&cursor);
                info->set_values |= SQL_NB_FIELDS;
                SLOG(LOG_DEBUG, "Setting nb_fields to %u", info->u.query.nb_fields);
            } else if (type == 'D') {   // data row
                if (len < 2) return PROTO_PARSE_ERR;
                if (! (info->set_values & SQL_NB_ROWS)) {
                    info->set_values |= SQL_NB_ROWS;
                    info->u.query.nb_rows = 0;
                }
                info->u.query.nb_rows ++;
                SLOG(LOG_DEBUG, "Incrementing nb_rows (now %u)", info->u.query.nb_rows);
            } else if (type == 'C') {   // command complete (fetch nb rows)
                char *result;
                info->set_values |= SQL_REQUEST_STATUS;
                info->request_status = SQL_REQUEST_COMPLETE;
                status = cursor_read_string(&cursor, &result, len);
                if (status != PROTO_OK) return status;
                status = fetch_nb_rows(result, &info->u.query.nb_rows);
                if (status == PROTO_OK) {
                    info->set_values |= SQL_NB_ROWS;
                } else {
                    //return status;    // Do not use this as the actual protocol does not seam to implement the doc :-<
                }
            } else if (type == 'E') {   // error
                status = pg_parse_error(info, &cursor, len);
                if (status != PROTO_OK) return status;
            }
            // Skip what's left of this message and go for the next
            assert(msg_end >= cursor.head);
            cursor_drop(&cursor, msg_end - cursor.head);
        }
    }

    return proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
}
示例#5
0
static enum proto_parse_status pg_parse_init(struct pgsql_parser *pg_parser, struct sql_proto_info *info, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet)
{
    info->msg_type = SQL_STARTUP;

    /* NONE phase is when we haven't seen the startup message yet.
     * In this phase, we expect to see from the client a startup message,
     * and from the server nothing but an answer to an SSL request. */
    if (info->is_query) {
        struct cursor cursor;
        cursor_ctor(&cursor, payload, cap_len);

        // Startup message comes without a type tag
        size_t len;
        enum proto_parse_status status = cursor_read_msg(&cursor, NULL, &len);
        if (status != PROTO_OK) return status;
        SLOG(LOG_DEBUG, "Msg of length %zu", len);
        if (len < 4) return PROTO_PARSE_ERR;
        uint32_t msg = cursor_read_u32n(&cursor);
        if (msg == 80877103) {  // magic value for SSL request
            SLOG(LOG_DEBUG, "Msg is an SSL request");
            info->set_values |= SQL_SSL_REQUEST;
            info->u.startup.ssl_request = SQL_SSL_REQUESTED;
        } else if (msg == 196608) { // version number, here 00 03 00 00 (ie. 3.0), which is parsed here
            SLOG(LOG_DEBUG, "Msg is a startup message for v3.0");
            info->version_maj = 3;
            info->version_min = 0;
            info->set_values |= SQL_VERSION;
            // fine, now parse all the strings that follow
            do {
                char *name, *value;
                status = cursor_read_string(&cursor, &name, len);
                if (status != PROTO_OK) return status;
                if (name[0] == '\0') break;
                status = cursor_read_string(&cursor, &value, len);
                if (status != PROTO_OK) return status;
                if (0 == strcmp(name, "user")) {
                    info->set_values |= SQL_USER;
                    snprintf(info->u.startup.user, sizeof(info->u.startup.user), "%s", value);
                } else if (0 == strcmp(name, "database")) {
                    info->set_values |= SQL_DBNAME;
                    snprintf(info->u.startup.dbname, sizeof(info->u.startup.dbname), "%s", value);
                }
            } while (1);
            // and enter "startup phase" untill the server is ready for query
            pg_parser->phase = STARTUP;
        } else {
            SLOG(LOG_DEBUG, "Unknown message");
            return PROTO_PARSE_ERR;
        }
    } else {    // reply (to an SSL request)
        if (wire_len != 1 || cap_len < 1) return PROTO_TOO_SHORT;
        info->set_values |= SQL_SSL_REQUEST;
        if (payload[0] == 'S') {
            info->u.startup.ssl_request = SQL_SSL_GRANTED;  // We will get parse errors from now on :-<
        } else if (payload[0] == 'N') {
            info->u.startup.ssl_request = SQL_SSL_REFUSED;
        } else {
            return PROTO_PARSE_ERR;
        }
    }

    return proto_parse(NULL, &info->info, way, NULL, 0, 0, now, tot_cap_len, tot_packet);
}