andrey Tue, 11 Jan 2011 13:02:57 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=307377
Log: Use common code to handle initial authentication and COM_CHANGE_USER Changed paths: U php/php-src/trunk/ext/mysqlnd/mysqlnd.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.h
Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd.c 2011-01-11 13:01:30 UTC (rev 307376) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd.c 2011-01-11 13:02:57 UTC (rev 307377) @@ -427,7 +427,63 @@ /* }}} */ -#define MYSQLND_ASSEBLED_PACKET_MAX_SIZE 3UL*1024UL*1024UL*1024UL +#define MYSQLND_ASSEMBLED_PACKET_MAX_SIZE 3UL*1024UL*1024UL*1024UL +/* {{{ mysqlnd_switch_to_ssl_if_needed */ +static MYSQLND_PACKET_AUTH * +mysqlnd_switch_to_ssl_if_needed( + MYSQLND * conn, + const MYSQLND_PACKET_GREET * const greet_packet, + const MYSQLND_OPTIONS * const options, + unsigned long mysql_flags + TSRMLS_DC + ) +{ + const MYSQLND_CHARSET * charset = NULL; + MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); + DBG_ENTER("mysqlnd_switch_to_ssl_if_needed"); + + if (!auth_packet) { + SET_OOM_ERROR(conn->error_info); + goto err; + } + auth_packet->client_flags = mysql_flags; + auth_packet->max_packet_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE; + + if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) { + auth_packet->charset_no = charset->nr; + } else { +#if MYSQLND_UNICODE + auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */ +#else + auth_packet->charset_no = greet_packet->charset_no; +#endif + } + +#ifdef MYSQLND_SSL_SUPPORTED + if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) { + zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE; + DBG_INF("Switching to SSL"); + if (!PACKET_WRITE(auth_packet, conn)) { + CONN_SET_STATE(conn, CONN_QUIT_SENT); + SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); + goto err; + } + + conn->net->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC); + + if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) { + goto err; + } + } +#endif + DBG_RETURN(auth_packet); +err: + PACKET_FREE(auth_packet); + DBG_RETURN(NULL); +} +/* }}} */ + + /* {{{ mysqlnd_connect_run_authentication */ static enum_func_status mysqlnd_connect_run_authentication( @@ -441,39 +497,28 @@ unsigned long mysql_flags TSRMLS_DC) { - const MYSQLND_CHARSET * charset = NULL; enum_func_status ret = FAIL; - MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); + MYSQLND_PACKET_AUTH * auth_packet = NULL; MYSQLND_PACKET_OK * ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); DBG_ENTER("mysqlnd_connect_run_authentication"); - if (!auth_packet || !ok_packet) { + if (!ok_packet) { SET_OOM_ERROR(conn->error_info); goto err; } -#ifdef MYSQLND_SSL_SUPPORTED - if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) { - auth_packet->send_half_packet = TRUE; + auth_packet = mysqlnd_switch_to_ssl_if_needed(conn, greet_packet, options, mysql_flags TSRMLS_CC); + + if (!auth_packet) { + goto err; } -#endif + + auth_packet->send_auth_data = TRUE; auth_packet->user = user; auth_packet->password = passwd; - - if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) { - auth_packet->charset_no = charset->nr; - } else { -#if MYSQLND_UNICODE - auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */ -#else - auth_packet->charset_no = greet_packet->charset_no; -#endif - } auth_packet->db = db; auth_packet->db_len = db_len; - auth_packet->max_packet_size= MYSQLND_ASSEBLED_PACKET_MAX_SIZE; - auth_packet->client_flags= mysql_flags; conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent); if (!conn->scramble) { @@ -488,27 +533,6 @@ goto err; } -#ifdef MYSQLND_SSL_SUPPORTED - if (auth_packet->send_half_packet) { - zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE; - DBG_INF("Switching to SSL"); - - conn->net->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC); - - if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) { - goto err; - } - - auth_packet->send_half_packet = FALSE; - if (!PACKET_WRITE(auth_packet, conn)) { - CONN_SET_STATE(conn, CONN_QUIT_SENT); - SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); - goto err; - } - } -#endif - - if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) { if (ok_packet->field_count == 0xFE) { /* old authentication with new server !*/ @@ -800,7 +824,7 @@ conn->unix_socket_len = strlen(conn->unix_socket); } conn->client_flag = mysql_flags; - conn->max_packet_size = MYSQLND_ASSEBLED_PACKET_MAX_SIZE; + conn->max_packet_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE; /* todo: check if charset is available */ conn->server_capabilities = greet_packet->server_capabilities; conn->upsert_status.warning_count = 0; @@ -1912,19 +1936,27 @@ Stack space is not that expensive, so use a bit more to be protected against buffer overflows. */ - size_t user_len; + size_t user_len, db_len; enum_func_status ret = FAIL; - MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp; + MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = NULL; char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 2 /* charset*/ ]; char *p = buffer; const MYSQLND_CHARSET * old_cs = conn->charset; + MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); + + DBG_ENTER("mysqlnd_conn::change_user"); DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u", conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 ); SET_ERROR_AFF_ROWS(conn); + if (!auth_packet) { + SET_OOM_ERROR(conn->error_info); + goto end; + } + if (!user) { user = ""; } @@ -1934,44 +1966,25 @@ if (!db) { db = ""; } + user_len = strlen(user); + db_len = strlen(db); - /* 1. user ASCIIZ */ - user_len = MIN(strlen(user), MYSQLND_MAX_ALLOWED_USER_LEN); - memcpy(p, user, user_len); - p += user_len; - *p++ = '\0'; - - /* 2. password SCRAMBLE_LENGTH followed by the scramble or \0 */ - if (passwd[0]) { - *p++ = SCRAMBLE_LENGTH; - php_mysqlnd_scramble((unsigned char *)p, conn->scramble, (unsigned char *)passwd); - p += SCRAMBLE_LENGTH; - } else { - *p++ = '\0'; - } - - /* 3. db ASCIIZ */ - if (db[0]) { - size_t db_len = MIN(strlen(db), MYSQLND_MAX_ALLOWED_DB_LEN); - memcpy(p, db, db_len); - p += db_len; - } - *p++ = '\0'; - - /* - 4. request the current charset, or it will be reset to the system one. - 5.0 doesn't support it. Support added in 5.1.23 by fixing the following bug : - Bug #30472 libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call - */ + auth_packet->is_change_user_packet = TRUE; + auth_packet->user = user; + auth_packet->password = passwd; + auth_packet->db = db; + auth_packet->db_len = db_len; + auth_packet->server_scramble_buf = conn->scramble; + auth_packet->silent = silent; if (mysqlnd_get_server_version(conn) >= 50123) { - int2store(p, conn->charset->nr); + auth_packet->charset_no = conn->charset->nr; p+=2; } - - if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer, p - buffer, - PROT_LAST /* we will handle the OK packet*/, - silent, TRUE TSRMLS_CC)) { - DBG_RETURN(FAIL); + + if (!PACKET_WRITE(auth_packet, conn)) { + CONN_SET_STATE(conn, CONN_QUIT_SENT); + SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); + goto end; } chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC); @@ -2030,6 +2043,7 @@ SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); } end: + PACKET_FREE(auth_packet); PACKET_FREE(chg_user_resp); /* Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.c 2011-01-11 13:01:30 UTC (rev 307376) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.c 2011-01-11 13:02:57 UTC (rev 307377) @@ -447,7 +447,7 @@ /* }}} */ -#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SHA1_MAX_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 128) +#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 128) /* {{{ php_mysqlnd_auth_write */ static @@ -460,19 +460,21 @@ DBG_ENTER("php_mysqlnd_auth_write"); - int4store(p, packet->client_flags); - p+= 4; + if (!packet->is_change_user_packet) { + int4store(p, packet->client_flags); + p+= 4; - int4store(p, packet->max_packet_size); - p+= 4; + int4store(p, packet->max_packet_size); + p+= 4; - int1store(p, packet->charset_no); - p++; + int1store(p, packet->charset_no); + p++; - memset(p, 0, 23); /* filler */ - p+= 23; + memset(p, 0, 23); /* filler */ + p+= 23; + } - if (!packet->send_half_packet) { + if (packet->send_auth_data || packet->is_change_user_packet) { len = MIN(strlen(packet->user), MYSQLND_MAX_ALLOWED_USER_LEN); memcpy(p, packet->user, len); p+= len; @@ -481,10 +483,10 @@ /* copy scrambled pass*/ if (packet->password && packet->password[0]) { /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */ - int1store(p, SHA1_MAX_LENGTH); + int1store(p, SCRAMBLE_LENGTH); p++; php_mysqlnd_scramble((zend_uchar*)p, packet->server_scramble_buf, (zend_uchar*)packet->password); - p+= SHA1_MAX_LENGTH; + p+= SCRAMBLE_LENGTH; } else { /* Zero length */ int1store(p, 0); @@ -492,16 +494,29 @@ } if (packet->db) { + /* CLIENT_CONNECT_WITH_DB should have been set */ size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len); memcpy(p, packet->db, real_db_len); p+= real_db_len; *p++= '\0'; } - /* Handle CLIENT_CONNECT_WITH_DB */ /* no \0 for no DB */ + + if (packet->is_change_user_packet && packet->charset_no) { + int2store(p, packet->charset_no); + p+= 2; + } } - - DBG_RETURN(conn->net->m.send(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC)); + if (packet->is_change_user_packet) { + if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer + MYSQLND_HEADER_SIZE, p - buffer - MYSQLND_HEADER_SIZE, + PROT_LAST /* the caller will handle the OK packet */, + packet->silent, TRUE TSRMLS_CC)) { + DBG_RETURN(0); + } + DBG_RETURN(p - buffer - MYSQLND_HEADER_SIZE); + } else { + DBG_RETURN(conn->net->m.send(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC)); + } } /* }}} */ Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.h =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.h 2011-01-11 13:01:30 UTC (rev 307376) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_wireprotocol.h 2011-01-11 13:02:57 UTC (rev 307377) @@ -101,7 +101,9 @@ /* +1 for \0 because of scramble() */ unsigned char *server_scramble_buf; size_t db_len; - zend_bool send_half_packet; + zend_bool send_auth_data; + zend_bool is_change_user_packet; + zend_bool silent; } MYSQLND_PACKET_AUTH; /* OK packet */
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php