diff --git a/core/gateway_mysql_protocol.c b/core/gateway_mysql_protocol.c index 941548d4c..17f2638d2 100644 --- a/core/gateway_mysql_protocol.c +++ b/core/gateway_mysql_protocol.c @@ -50,7 +50,7 @@ * @param packet_number * @param in_affected_rows * @param mysql_message - * @return + * @return packet length * */ int @@ -122,6 +122,89 @@ mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mys return sizeof(mysql_packet_header) + mysql_payload_size; } +/* + * mysql_send_auth_error + * + * Send a MySQL protocol ERR message, for gatewayauthentication error to the dcb + * + * @param dcb Descriptor Control Block for the connection to which the OK is sent + * @param packet_number + * @param in_affected_rows + * @param mysql_message + * @return packet lenght + * + */ +int +mysql_send_auth_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { + uint8_t *outbuf = NULL; + uint8_t mysql_payload_size = 0; + uint8_t mysql_packet_header[4]; + uint8_t *mysql_payload = NULL; + uint8_t field_count = 0; + uint8_t affected_rows = 0; + uint8_t insert_id = 0; + uint8_t mysql_err[2]; + uint8_t mysql_statemsg[6]; + unsigned int mysql_errno = 0; + const char *mysql_error_msg = NULL; + const char *mysql_state = NULL; + + GWBUF *buf; + + mysql_errno = 1045; + mysql_error_msg = "Access denied!"; + mysql_state = "2800"; + + field_count = 0xff; + gw_mysql_set_byte2(mysql_err, mysql_errno); + mysql_statemsg[0]='#'; + memcpy(mysql_statemsg+1, mysql_state, 5); + + if (mysql_message != NULL) { + mysql_error_msg = mysql_message; + } else { + mysql_error_msg = "Access denied!"; + + } + + mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg); + + // allocate memory for packet header + payload + if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL) + { + return 0; + } + outbuf = GWBUF_DATA(buf); + + // write packet header with packet number + gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size); + mysql_packet_header[3] = packet_number; + + // write header + memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header)); + + mysql_payload = outbuf + sizeof(mysql_packet_header); + + // write field + memcpy(mysql_payload, &field_count, sizeof(field_count)); + mysql_payload = mysql_payload + sizeof(field_count); + + // write errno + memcpy(mysql_payload, mysql_err, sizeof(mysql_err)); + mysql_payload = mysql_payload + sizeof(mysql_err); + + // write sqlstate + memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg)); + mysql_payload = mysql_payload + sizeof(mysql_statemsg); + + // write err messg + memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg)); + + // write data + dcb->func.write(dcb, buf); + + return sizeof(mysql_packet_header) + mysql_payload_size; +} /* * MySQLSendHandshake @@ -304,6 +387,11 @@ int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { fprintf(stderr, "<<< Client is NOT connected with db\n"); } + if (connect_with_db) { + strncpy(database, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1 + auth_token_len, 128); + } + fprintf(stderr, "<<< Client selected db is [%s]\n", database); + fprintf(stderr, "<<< Client username is [%s]\n", username); // decode the token and check the password @@ -315,13 +403,7 @@ int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { fprintf(stderr, "<<< CLIENT AUTH FAILED\n"); } - if (connect_with_db) { - strncpy(database, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1 + auth_token_len, 128); - } - - fprintf(stderr, "<<< Client selected db is [%s]\n", database); - - return 0; + return auth_ret; } diff --git a/core/utils.c b/core/utils.c index 093c1bcfc..72c4fadf3 100644 --- a/core/utils.c +++ b/core/utils.c @@ -21,7 +21,11 @@ * Revision History * * Date Who Description - * 10/06/13 Massimiliano Pinto Initial implementation + * 10-06-2013 Massimiliano Pinto Initial implementation + * 12-06-2013 Massimiliano Pinto Read function trought + * the gwbuff strategy + * 13-06-2013 Massimiliano Pinto Gateway local authentication + * basics * */ @@ -225,6 +229,7 @@ int gw_route_read_event(DCB* dcb, int epfd) { int ret = -1; GWBUF *queue = NULL; GWBUF *gw_buffer = NULL; + int auth_val = -1; ////////////////////////////////////////////////////// // read and handle errors & close, or return if busyA // note: if b == 0 error handling is not triggered, just return @@ -240,24 +245,19 @@ int gw_route_read_event(DCB* dcb, int epfd) { fprintf(stderr, "<<< Reading from Client %i bytes: [%s]\n", len, GWBUF_DATA(queue)); - gw_mysql_do_authentication(dcb, queue); + auth_val = gw_mysql_do_authentication(dcb, queue); - // Data printed on stderr or handled withot the dcb->func.write + // Data handled withot the dcb->func.write // so consume it now + // be sure to consume it all queue = gwbuf_consume(queue, len); + + if (auth_val == 0) + protocol->state = MYSQL_AUTH_RECV; + else + protocol->state = MYSQL_AUTH_FAILED; } - // ToDo - // now we have the data in the buffer, do the authentication - // but don't consume the gwbuf as in the above example !!! - - protocol->state = MYSQL_AUTH_RECV; - - // check authentication - // if OK return mysql_ok - // else return error - //protocol->state = MYSQL_AUTH_FAILED; - break; case MYSQL_IDLE: @@ -378,7 +378,11 @@ int gw_handle_write_event(DCB *dcb, int epfd) { if (protocol->state == MYSQL_AUTH_FAILED) { // still to implement - mysql_send_ok(dcb, 2, 0, NULL); + mysql_send_auth_error(dcb, 2, 0, "Authorization failed"); + + dcb->func.error(dcb, -1); + if (dcb->session->backends) + dcb->session->backends->func.error(dcb->session->backends, -1); return 0; }