From b8f590e67ffa7b3512d1f515eb337df4f45e8de2 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Fri, 17 Oct 2014 19:02:19 +0200 Subject: [PATCH] Added database errmsg to change_user Added database errmsg to change_user --- server/modules/protocol/mysql_backend.c | 37 +++++++++--- server/modules/protocol/mysql_client.c | 71 ++++++---------------- server/modules/protocol/mysql_common.c | 79 +++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 68 deletions(-) diff --git a/server/modules/protocol/mysql_backend.c b/server/modules/protocol/mysql_backend.c index 049455686..4dab7a81e 100644 --- a/server/modules/protocol/mysql_backend.c +++ b/server/modules/protocol/mysql_backend.c @@ -66,7 +66,7 @@ static int backend_write_delayqueue(DCB *dcb); static void backend_set_delayqueue(DCB *dcb, GWBUF *queue); static int gw_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue); static GWBUF* process_response_data (DCB* dcb, GWBUF* readbuf, int nbytes_to_process); - +extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1, int dbmatch); #if defined(NOT_USED) @@ -1191,6 +1191,7 @@ static int gw_change_user( uint8_t *auth_token = NULL; int rv = -1; int auth_ret = 1; + int db_exists = 0; current_session = (MYSQL_session *)in_session->client->data; backend_protocol = backend->protocol; @@ -1217,6 +1218,10 @@ static int gw_change_user( memcpy(auth_token, client_auth_packet, auth_token_len); client_auth_packet += auth_token_len; } + + // get db name + strcpy(database, (char *)client_auth_packet); + // decode the token and check the password // Note: if auth_token_len == 0 && auth_token == NULL, user is without password auth_ret = gw_check_mysql_scramble_data(backend->session->client, auth_token, auth_token_len, client_protocol->scramble, sizeof(client_protocol->scramble), username, client_sha1); @@ -1233,17 +1238,33 @@ static int gw_change_user( if (auth_token) free(auth_token); - if (auth_ret != 0) { - /*< vraa : errorHandle */ + if (strlen(database)) { + int i = 0; + while(backend->session->client->service->resources[i]) { + if (strncmp(database, backend->session->client->service->resources[i], MYSQL_DATABASE_MAXLEN) == 0) { + db_exists = 1; + } - // send the error packet - mysql_send_auth_error(backend->session->client, 1, 0, "Authorization failed on change_user"); + i++; + } + + if (!db_exists && auth_ret == 0) { + auth_ret = 2; + } + } + + if (auth_ret != 0) { + + char *message = create_auth_failed_msg(queue, "ipaddr", client_sha1, auth_ret); + /* send the error packet */ + mysql_send_auth_error(backend->session->client, 1, 0, message); + fprintf(stderr, "ERROR change user for [%s] to [%s]\n", username, database); + //mysql_send_auth_error(backend->session->client, 1, 0, "Authorization failed on change_user"); + + free(message); rv = 1; } else { - // get db name - strcpy(database, (char *)client_auth_packet); - rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol); /*< diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index 54d577d4d..ec6ad8d72 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -70,7 +70,7 @@ int MySQLSendHandshake(DCB* dcb); static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue); static int route_by_statement(SESSION *, GWBUF **); static char* create_auth_fail_str(GWBUF* readbuf, char* hostaddr, char* sha1); -static char* get_username_from_auth(char* ptr, uint8_t* data); +extern char* get_username_from_auth(char* ptr, uint8_t* data); /* * The "module object" for the mysqld client protocol module. @@ -394,6 +394,7 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { uint8_t *stage1_hash = NULL; int auth_ret = -1; MYSQL_session *client_data = NULL; + int db_exists = 0; CHK_DCB(dcb); @@ -447,11 +448,15 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1, 1); + /* + * Note: some clients may pass empty database, connect_with_db !=0 but database ="" + */ if (connect_with_db) { database = client_data->db; strncpy(database, (char *)(client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1 + auth_token_len), MYSQL_DATABASE_MAXLEN); + fprintf(stderr, "---- Database name passed [%s], flag [%i]\n", database, connect_with_db); } /* allocate memory for token only if auth_token_len > 0 */ @@ -482,22 +487,23 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { } } + fprintf(stderr, "--- Authentication reply is [%i]\n", auth_ret); + /* let's free the auth_token now */ if (auth_token) free(auth_token); - if (database) { + if (database && strlen(database)) { int i = 0; - int db_exists = 0; while(dcb->service->resources[i]) { if (strncmp(database, dcb->service->resources[i], MYSQL_DATABASE_MAXLEN) == 0) { db_exists = 1; + } + + i++; } - i++; - } - - if (!db_exists && auth_ret == 0) { + if (!db_exists && auth_ret == 0) { auth_ret = 2; } } @@ -510,50 +516,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { return auth_ret; } -/** - * Read username from MySQL authentication packet. - * - * @param ptr address where to write the result or NULL if memory - * is allocated here. - * @param data Address of MySQL packet. - * - * @return Pointer to a copy of the username. NULL if memory allocation - * failed or if username was empty. - */ -static char* get_username_from_auth( - char* ptr, - uint8_t* data) -{ - char* first_letter; - char* rval; - - first_letter = (char *)(data + 4 + 4 + 4 + 1 + 23); - - if (first_letter == '\0') - { - rval = NULL; - goto retblock; - } - - if (ptr == NULL) - { - if ((rval = (char *)malloc(MYSQL_USER_MAXLEN+1)) == NULL) - { - goto retblock; - } - } - else - { - rval = ptr; - } - snprintf(rval, MYSQL_USER_MAXLEN+1, "%s", first_letter); - -retblock: - - return rval; -} - - static char* create_auth_fail_str( GWBUF* readbuf, char* hostaddr, @@ -757,6 +719,7 @@ int gw_read_client_event( 2, 0, fail_str); + free(fail_str); } LOGIF(LD, (skygw_log_write( @@ -767,7 +730,6 @@ int gw_read_client_event( protocol->owner_dcb->fd, pthread_self()))); - free(fail_str); dcb_close(dcb); } read_buffer = gwbuf_consume(read_buffer, nbytes_read); @@ -779,8 +741,9 @@ int gw_read_client_event( uint8_t cap = 0; uint8_t* payload = NULL; bool stmt_input; /*< router input type */ - - ss_dassert(nbytes_read >= 5); + + fprintf(stderr, "NBYTES %i\n", nbytes_read); + //ss_dassert(nbytes_read >= 5); session = dcb->session; ss_dassert( session!= NULL); diff --git a/server/modules/protocol/mysql_common.c b/server/modules/protocol/mysql_common.c index 9e1469878..da0e2ab93 100644 --- a/server/modules/protocol/mysql_common.c +++ b/server/modules/protocol/mysql_common.c @@ -49,6 +49,7 @@ extern int gw_read_backend_event(DCB* dcb); extern int gw_write_backend_event(DCB *dcb); extern int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue); extern int gw_error_backend_event(DCB *dcb); +char* get_username_from_auth(char* ptr, uint8_t* data); static server_command_t* server_command_init(server_command_t* srvcmd, mysql_server_cmd_t cmd); @@ -1117,15 +1118,15 @@ int gw_send_change_user_to_backend( if (curr_passwd != NULL) { bytes += GW_MYSQL_SCRAMBLE_SIZE; - bytes++; - } else { - bytes++; - } + } + // the NULL + bytes++; if (curr_db != NULL) { bytes += strlen(curr_db); - bytes++; } + // the NULL + bytes++; // the charset bytes += 2; @@ -1177,7 +1178,10 @@ int gw_send_change_user_to_backend( memcpy(payload, curr_db, strlen(curr_db)); payload += strlen(curr_db); payload++; - } + } else { + // skip the NULL + payload++; + } // set the charset, 2 bytes!!!! *payload = '\x08'; @@ -1979,3 +1983,66 @@ void protocol_set_response_status ( spinlock_release(&p->protocol_lock); } +char* create_auth_failed_msg( + GWBUF* readbuf, + char* hostaddr, + uint8_t* sha1, int dbmatch) +{ + char* errstr; + char* uname=(char *)GWBUF_DATA(readbuf) + 5; + const char* ferrstr = "Access denied for user '%s'@'%s' (using password: %s)"; + + /** -4 comes from 2X'%s' minus terminating char */ + errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6+1 + strlen(" to database ") + strlen("''") + strlen("datbase") +1); + + if (errstr != NULL) + { + sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES")); + strcat(errstr, " to database 'database'"); + } + + return errstr; +} + +/** + * Read username from MySQL authentication packet. + * + * @param ptr address where to write the result or NULL if memory + * is allocated here. + * @param data Address of MySQL packet. + * + * @return Pointer to a copy of the username. NULL if memory allocation + * failed or if username was empty. + */ +char* get_username_from_auth( + char* ptr, + uint8_t* data) +{ + char* first_letter; + char* rval; + + first_letter = (char *)(data + 4 + 4 + 4 + 1 + 23); + + if (first_letter == '\0') + { + rval = NULL; + goto retblock; + } + + if (ptr == NULL) + { + if ((rval = (char *)malloc(MYSQL_USER_MAXLEN+1)) == NULL) + { + goto retblock; + } + } + else + { + rval = ptr; + } + snprintf(rval, MYSQL_USER_MAXLEN+1, "%s", first_letter); + +retblock: + + return rval; +}