From: Harin Vadodaria Date: September 18 2012 12:46pm Subject: bzr push into mysql-trunk-auth branch (harin.vadodaria:4420 to 4421) WL#6486 List-Archive: http://lists.mysql.com/commits/144807 Message-Id: <20120918124659.7214.62756.4421@hvadodar-ThinkPad-T420> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4421 Harin Vadodaria 2012-09-18 wl#6486 : Refactoring user management code (authentication / authorization) Description : Implementation of Sql_user and Sql_user_implementation classes. added: sql/auth/sql_authorization.cc sql/auth/sql_authorization.h modified: sql/CMakeLists.txt sql/auth/auth_common.h sql/auth/sql_acl.cc sql/auth/sql_authentication.cc sql/auth/sql_authentication.h sql/auth/sql_user_table.cc 4420 Harin Vadodaria 2012-09-18 wl#6486 : Refactoring user management code (authentication / authorization) Description : Changing tree name modified: .bzr-mysql/default.conf === modified file 'sql/CMakeLists.txt' --- a/sql/CMakeLists.txt 2012-09-05 11:40:51 +0000 +++ b/sql/CMakeLists.txt 2012-09-18 12:46:18 +0000 @@ -45,6 +45,7 @@ SET(SQL_SHARED_SOURCES # auth/sql_user_table.cc auth/sql_user_cache.cc auth/sql_authentication.cc + auth/sql_authorization.cc datadict.cc debug_sync.cc derror.cc === modified file 'sql/auth/auth_common.h' --- a/sql/auth/auth_common.h 2012-09-06 12:02:23 +0000 +++ b/sql/auth/auth_common.h 2012-09-18 12:46:18 +0000 @@ -180,9 +180,6 @@ uchar* acl_entry_get_key(acl_entry *entr /* ---- */ -/* Misc functions not yet categorized */ -void -set_user_salt(ACL_USER *acl_user, const char *password, uint password_len); #endif // NO_EMBEDDED_ACCESS_CHECKS /** @@ -190,7 +187,7 @@ set_user_salt(ACL_USER *acl_user, const */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -extern DYNAMIC_ARRAY acl_users, acl_dbs, acl_proxy_users; +extern DYNAMIC_ARRAY sql_users, acl_dbs, acl_proxy_users; extern hash_filo *acl_cache; extern bool initialized; extern bool allow_all_hosts; @@ -205,8 +202,9 @@ extern DYNAMIC_ARRAY acl_wild_hosts; void optimize_plugin_compare_by_pointer(LEX_STRING *plugin_name); #ifndef NO_EMBEDDED_ACCESS_CHECKS -ACL_USER *find_acl_user(const char *host, const char *user, - my_bool exact); +class Sql_user_implementation; +Sql_user_implementation *find_acl_user(const char *host, const char *user, + my_bool exact); #endif #endif /* AUTH_COMMON_INCLUDED */ === modified file 'sql/auth/sql_acl.cc' --- a/sql/auth/sql_acl.cc 2012-09-06 12:02:23 +0000 +++ b/sql/auth/sql_acl.cc 2012-09-18 12:46:18 +0000 @@ -61,6 +61,7 @@ #endif #include "auth_common.h" +#include "sql_authorization.h" #include "sql_authentication.h" using std::min; @@ -429,7 +430,7 @@ uchar* acl_entry_get_key(acl_entry *entr } -DYNAMIC_ARRAY acl_users, acl_dbs, acl_proxy_users; +DYNAMIC_ARRAY sql_users, acl_dbs, acl_proxy_users; static MEM_ROOT global_acl_memory, memex; bool initialized=0; bool allow_all_hosts=1; @@ -440,6 +441,7 @@ hash_filo *acl_cache; static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); +static int sql_user_compare(Sql_user_implementation *a,Sql_user_implementation *b); static ulong get_sort(uint count,...); static void init_check_host(void); static void rebuild_check_host(void); @@ -458,42 +460,6 @@ static inline void get_grantor(THD *thd, #include "sql_user_table.cc" /*************************************************/ -/** - Convert scrambled password to binary form, according to scramble type, - Binary form is stored in user.salt. - - @param acl_user The object where to store the salt - @param password The password hash containing the salt - @param password_len The length of the password hash - - Despite the name of the function it is used when loading ACLs from disk - to store the password hash in the ACL_USER object. -*/ - -void -set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) -{ - /* Using old password protocol */ - if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) - { - get_salt_from_password(acl_user->salt, password); - acl_user->salt_len= SCRAMBLE_LENGTH; - } - else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) - { - get_salt_from_password_323((ulong *) acl_user->salt, password); - acl_user->salt_len= SCRAMBLE_LENGTH_323; - } - else - acl_user->salt_len= 0; - - /* - Since we're changing the password for the user we need to reset the - expiration flag. - */ - acl_user->password_expired= false; -} - /* Initialize structures responsible for user/db-level privilege checking and load privilege information for them from tables in the 'mysql' database. @@ -564,7 +530,7 @@ my_bool acl_init(bool dont_read_acl_tabl void acl_free(bool end) { free_root(&global_acl_memory,MYF(0)); - delete_dynamic(&acl_users); + delete_dynamic(&sql_users); delete_dynamic(&acl_dbs); delete_dynamic(&acl_wild_hosts); delete_dynamic(&acl_proxy_users); @@ -676,7 +642,7 @@ static bool acl_trans_commit_and_close_t my_bool acl_reload(THD *thd) { TABLE_LIST tables[3]; - DYNAMIC_ARRAY old_acl_users, old_acl_dbs, old_acl_proxy_users; + DYNAMIC_ARRAY old_sql_users, old_acl_dbs, old_acl_proxy_users; MEM_ROOT old_mem; bool old_initialized; my_bool return_val= TRUE; @@ -715,7 +681,7 @@ my_bool acl_reload(THD *thd) if ((old_initialized=initialized)) mysql_mutex_lock(&acl_cache->lock); - old_acl_users= acl_users; + old_sql_users= sql_users; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; old_mem= global_acl_memory; @@ -726,7 +692,7 @@ my_bool acl_reload(THD *thd) { // Error. Revert to old list DBUG_PRINT("error",("Reverting to old privileges")); acl_free(); /* purecov: inspected */ - acl_users= old_acl_users; + sql_users= old_sql_users; acl_proxy_users= old_acl_proxy_users; acl_dbs= old_acl_dbs; global_acl_memory= old_mem; @@ -735,7 +701,7 @@ my_bool acl_reload(THD *thd) else { free_root(&old_mem,MYF(0)); - delete_dynamic(&old_acl_users); + delete_dynamic(&old_sql_users); delete_dynamic(&old_acl_proxy_users); delete_dynamic(&old_acl_dbs); } @@ -841,6 +807,17 @@ static int acl_compare(ACL_ACCESS *a,ACL } +static int sql_user_compare(Sql_user_implementation *a, + Sql_user_implementation *b) +{ + if (a->sort() > b->sort()) + return -1; + if (a->sort() < b->sort()) + return 1; + return 0; +} + + /* Gets user credentials without authentication and resource limit checks. @@ -862,7 +839,7 @@ bool acl_getroot(Security_context *sctx, { int res= 1; uint i; - ACL_USER *acl_user= 0; + Sql_user *sql_user= 0; DBUG_ENTER("acl_getroot"); DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'", @@ -894,22 +871,25 @@ bool acl_getroot(Security_context *sctx, a stored procedure; user is set to what is actually a priv_user, which can be ''. */ - for (i=0 ; i < acl_users.elements ; i++) + for (i=0 ; i < sql_users.elements ; i++) { - ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user_tmp->user && !user[0]) || - (acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0)) + Sql_user *sql_user_tmp= dynamic_element(&sql_users,i,Sql_user*); + const String *user_string= sql_user_tmp->user(); + if ((!user_string->ptr() && !user[0]) || + (user_string->ptr() && + strcmp(user, user_string->ptr()) == 0)) { - if (acl_user_tmp->host.compare_hostname(host, ip)) + ACL_HOST_AND_IP *host_ptr= sql_user_tmp->host(); + if (host_ptr->compare_hostname(host, ip)) { - acl_user= acl_user_tmp; + sql_user= sql_user_tmp; res= 0; break; } } } - if (acl_user) + if (sql_user) { for (i=0 ; i < acl_dbs.elements ; i++) { @@ -927,29 +907,30 @@ bool acl_getroot(Security_context *sctx, } } } - sctx->master_access= acl_user->access; + sctx->master_access= sql_user->global_acl(); - if (acl_user->user) + if (sql_user->user()->ptr()) strmake(sctx->priv_user, user, USERNAME_LENGTH); else *sctx->priv_user= 0; - if (acl_user->host.get_host()) - strmake(sctx->priv_host, acl_user->host.get_host(), MAX_HOSTNAME - 1); + if (sql_user->host()->get_host()) + strmake(sctx->priv_host, sql_user->host()->get_host(), MAX_HOSTNAME - 1); else *sctx->priv_host= 0; - sctx->password_expired= acl_user->password_expired; + sctx->password_expired= sql_user->password_expired(); } mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(res); } -static uchar* check_get_key(ACL_USER *buff, size_t *length, +static uchar* check_get_key(Sql_user *buff, size_t *length, my_bool not_used __attribute__((unused))) { - *length=buff->host.get_host_len(); - return (uchar*) buff->host.get_host(); + ACL_HOST_AND_IP *host= buff->host(); + *length=host->get_host_len(); + return (uchar*) host->get_host(); } @@ -966,46 +947,49 @@ static void acl_update_user(const char * { DBUG_ENTER("acl_update_user"); mysql_mutex_assert_owner(&acl_cache->lock); - for (uint i=0 ; i < acl_users.elements ; i++) + for (uint i=0 ; i < sql_users.elements ; i++) { - ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user->user && !user[0]) || - (acl_user->user && !strcmp(user,acl_user->user))) - { - if ((!acl_user->host.get_host() && !host[0]) || - (acl_user->host.get_host() && - !my_strcasecmp(system_charset_info, host, acl_user->host.get_host()))) + Sql_user_implementation *sql_user=dynamic_element(&sql_users,i,Sql_user_implementation*); + const String *user_string= sql_user->user(); + ACL_HOST_AND_IP *host_ptr= sql_user->host(); + if ((!user_string->ptr() && !user[0]) || + (user_string->ptr() && !strcmp(user,user_string->ptr()))) + { + if ((!host_ptr->get_host() && !host[0]) || + (host_ptr->get_host() && + !my_strcasecmp(system_charset_info, host, host_ptr->get_host()))) { if (plugin->length > 0) { - acl_user->plugin.str= strmake_root(&global_acl_memory, plugin->str, plugin->length); - acl_user->plugin.length= plugin->length; - acl_user->auth_string.str= auth->str ? - strmake_root(&global_acl_memory, auth->str, - auth->length) : const_cast(""); - acl_user->auth_string.length= auth->length; + sql_user->set_authentication_plugin(strmake_root(&global_acl_memory, + plugin->str, + plugin->length), + (uint32)(plugin->length)); + sql_user->set_authentication_string(auth->str ? + strmake_root(&global_acl_memory, + auth->str, auth->length) : + const_cast(""), + (uint32)(auth->length)); } - acl_user->access=privileges; - if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR) - acl_user->user_resource.questions=mqh->questions; - if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR) - acl_user->user_resource.updates=mqh->updates; - if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR) - acl_user->user_resource.conn_per_hour= mqh->conn_per_hour; - if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS) - acl_user->user_resource.user_conn= mqh->user_conn; + sql_user->set_global_acl(privileges); + + sql_user->set_user_resources_selective(mqh); + if (ssl_type != SSL_TYPE_NOT_SPECIFIED) { - acl_user->ssl_type= ssl_type; - acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&global_acl_memory, - ssl_cipher) : 0); - acl_user->x509_issuer= (x509_issuer ? strdup_root(&global_acl_memory, - x509_issuer) : 0); - acl_user->x509_subject= (x509_subject ? - strdup_root(&global_acl_memory, x509_subject) : 0); + sql_user->set_ssl_authentication_type(ssl_type); + sql_user->set_ssl_cipher((ssl_cipher ? + strdup_root(&global_acl_memory, + ssl_cipher) : 0)); + sql_user->set_x509_issuer(x509_issuer ? + strdup_root(&global_acl_memory, + x509_issuer) : 0); + sql_user->set_x509_subject(x509_subject ? + strdup_root(&global_acl_memory, + x509_subject) : 0); } if (password) - set_user_salt(acl_user, password, password_len); + sql_user->set_user_salt(password, password_len); /* search complete: */ break; } @@ -1027,50 +1011,58 @@ static void acl_insert_user(const char * const LEX_STRING *auth) { DBUG_ENTER("acl_insert_user"); - ACL_USER acl_user; + Sql_user_implementation sql_user(&global_acl_memory); mysql_mutex_assert_owner(&acl_cache->lock); - acl_user.user= *user ? strdup_root(&global_acl_memory,user) : 0; - acl_user.host.update_hostname(*host ? strdup_root(&global_acl_memory, host) : 0); + sql_user.set_user(*user ? strdup_root(&global_acl_memory,user) : 0); + sql_user.update_hostname(*host ? strdup_root(&global_acl_memory, host) : 0); if (plugin->str[0]) { - acl_user.plugin.str= strmake_root(&global_acl_memory, plugin->str, plugin->length); - acl_user.plugin.length= plugin->length; - acl_user.auth_string.str= auth->str ? - strmake_root(&global_acl_memory, auth->str, - auth->length) : const_cast(""); - acl_user.auth_string.length= auth->length; + sql_user.set_authentication_plugin(strmake_root(&global_acl_memory, + plugin->str, + plugin->length), + plugin->length); + sql_user.set_authentication_string(auth->str ? + strmake_root(&global_acl_memory, + auth->str, auth->length) : + const_cast(""), + auth->length); } else { - acl_user.plugin= password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 ? - old_password_plugin_name : native_password_plugin_name; - acl_user.auth_string.str= const_cast(""); - acl_user.auth_string.length= 0; - } - acl_user.access= privileges; - acl_user.user_resource= *mqh; - acl_user.sort= get_sort(2,acl_user.host.get_host(), acl_user.user); - //acl_user.hostname_length=(uint) strlen(host); - acl_user.ssl_type= - (ssl_type != SSL_TYPE_NOT_SPECIFIED ? ssl_type : SSL_TYPE_NONE); - acl_user.ssl_cipher= - ssl_cipher ? strdup_root(&global_acl_memory, ssl_cipher) : 0; - acl_user.x509_issuer= - x509_issuer ? strdup_root(&global_acl_memory, x509_issuer) : 0; - acl_user.x509_subject= - x509_subject ? strdup_root(&global_acl_memory, x509_subject) : 0; + if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) + sql_user.set_authentication_plugin(old_password_plugin_name.str, + old_password_plugin_name.length); + else + sql_user.set_authentication_plugin(native_password_plugin_name.str, + native_password_plugin_name.length); + + sql_user.set_authentication_string(const_cast(""), 0); + } + + sql_user.set_global_acl(privileges); + sql_user.set_user_resources(mqh); + sql_user.set_sort(get_sort(2,sql_user.host()->get_host(), sql_user.user())); + + sql_user.set_ssl_authentication_type(ssl_type != SSL_TYPE_NOT_SPECIFIED ? + ssl_type : SSL_TYPE_NONE); + sql_user.set_ssl_cipher(ssl_cipher ? + strdup_root(&global_acl_memory, ssl_cipher) : 0); + sql_user.set_x509_issuer(x509_issuer ? + strdup_root(&global_acl_memory, x509_issuer) : 0); + sql_user.set_x509_subject(x509_subject ? + strdup_root(&global_acl_memory, x509_subject) : 0); - set_user_salt(&acl_user, password, password_len); + sql_user.set_user_salt(password, password_len); - (void) push_dynamic(&acl_users,(uchar*) &acl_user); - if (acl_user.host.check_allow_all_hosts()) + (void) push_dynamic(&sql_users,(uchar*) &sql_user); + if (sql_user.host()->check_allow_all_hosts()) allow_all_hosts=1; // Anyone can connect /* purecov: tested */ - my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&sql_users,0,Sql_user_implementation*),sql_users.elements, + sizeof(Sql_user_implementation),(qsort_cmp) sql_user_compare); - /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ + /* Rebuild 'acl_check_hosts' since 'sql_users' has been modified */ rebuild_check_host(); DBUG_VOID_RETURN; } @@ -1221,16 +1213,17 @@ static void init_check_host(void) { DBUG_ENTER("init_check_host"); (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(class ACL_HOST_AND_IP), - acl_users.elements,1); + sql_users.elements,1); (void) my_hash_init(&acl_check_hosts,system_charset_info, - acl_users.elements, 0, 0, + sql_users.elements, 0, 0, (my_hash_get_key) check_get_key, 0, 0); if (!allow_all_hosts) { - for (uint i=0 ; i < acl_users.elements ; i++) + for (uint i=0 ; i < sql_users.elements ; i++) { - ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); - if (acl_user->host.has_wildcard()) + Sql_user_implementation *sql_user=dynamic_element(&sql_users,i,Sql_user_implementation*); + ACL_HOST_AND_IP *host_ptr= sql_user->host(); + if (host_ptr->has_wildcard()) { // Has wildcard uint j; for (j=0 ; j < acl_wild_hosts.elements ; j++) @@ -1238,17 +1231,17 @@ static void init_check_host(void) ACL_HOST_AND_IP *acl=dynamic_element(&acl_wild_hosts,j, ACL_HOST_AND_IP *); if (!my_strcasecmp(system_charset_info, - acl_user->host.get_host(), acl->get_host())) + host_ptr->get_host(), acl->get_host())) break; // already stored } if (j == acl_wild_hosts.elements) // If new - (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host); + (void) push_dynamic(&acl_wild_hosts,(uchar*) host_ptr); } else if (!my_hash_search(&acl_check_hosts,(uchar*) - acl_user->host.get_host(), - strlen(acl_user->host.get_host()))) + host_ptr->get_host(), + strlen(host_ptr->get_host()))) { - if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user)) + if (my_hash_insert(&acl_check_hosts,(uchar*) sql_user)) { // End of memory allow_all_hosts=1; // Should never happen DBUG_VOID_RETURN; @@ -1267,8 +1260,9 @@ static void init_check_host(void) We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding, dropping or renaming user, since they contain pointers to elements of - 'acl_user' array, which are invalidated by drop operation, and use - ACL_USER::host::hostname as a key, which is changed by rename. + 'Sql_user_implementation' array, which are invalidated by drop operation, + and use Sql_user_implementation::m_host::hostname as a key, + which is changed by rename. */ void rebuild_check_host(void) { @@ -1392,18 +1386,18 @@ bool change_password(THD *thd, const cha thd->clear_current_stmt_binlog_format_row(); mysql_mutex_lock(&acl_cache->lock); - ACL_USER *acl_user; - if (!(acl_user= find_acl_user(host, user, TRUE))) + Sql_user_implementation *sql_user; + if (!(sql_user= find_acl_user(host, user, TRUE))) { mysql_mutex_unlock(&acl_cache->lock); my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); goto end; } - if (acl_user->plugin.length == 0) + if (sql_user->authentication_plugin()->length() == 0) { - acl_user->plugin.length= default_auth_plugin_name.length; - acl_user->plugin.str= default_auth_plugin_name.str; + sql_user->set_authentication_plugin(default_auth_plugin_name.str, + (uint32)(default_auth_plugin_name.length)); } #if defined(HAVE_OPENSSL) @@ -1412,14 +1406,15 @@ bool change_password(THD *thd, const cha TODO Should password depend on @@old_variables here? - Probably not if the user exists and have a plugin set already. */ - if (my_strcasecmp(system_charset_info, acl_user->plugin.str, + if (my_strcasecmp(system_charset_info, + sql_user->authentication_plugin()->ptr(), sha256_password_plugin_name.str) == 0) { /* Accept empty passwords */ if (new_password_len == 0) - acl_user->auth_string= empty_lex_str; + sql_user->set_authentication_string(const_cast(""), 0); /* Check if password begins with correct magic number */ @@ -1431,10 +1426,10 @@ bool change_password(THD *thd, const cha if (new_password_len < CRYPT_MAX_PASSWORD_SIZE + 1) { /* copy string including \0 */ - acl_user->auth_string.str= (char *) memdup_root(&global_acl_memory, + sql_user->set_authentication_string((char *) memdup_root(&global_acl_memory, new_password, - new_password_len + 1); - acl_user->auth_string.length= new_password_len; + new_password_len + 1), + new_password_len); } } else { @@ -1450,9 +1445,9 @@ bool change_password(THD *thd, const cha } else #endif - if (my_strcasecmp(system_charset_info, acl_user->plugin.str, + if (my_strcasecmp(system_charset_info, sql_user->authentication_plugin()->ptr(), native_password_plugin_name.str) == 0 || - my_strcasecmp(system_charset_info, acl_user->plugin.str, + my_strcasecmp(system_charset_info, sql_user->authentication_plugin()->ptr(), old_password_plugin_name.str) == 0) { password_field= MYSQL_USER_FIELD_PASSWORD; @@ -1463,7 +1458,7 @@ bool change_password(THD *thd, const cha */ if (new_password_len != 0) { - if (my_strcasecmp(system_charset_info, acl_user->plugin.str, + if (my_strcasecmp(system_charset_info, sql_user->authentication_plugin()->ptr(), native_password_plugin_name.str) == 0 && new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH) { @@ -1473,7 +1468,7 @@ bool change_password(THD *thd, const cha goto end; } else - if (my_strcasecmp(system_charset_info, acl_user->plugin.str, + if (my_strcasecmp(system_charset_info, sql_user->authentication_plugin()->ptr(), old_password_plugin_name.str) == 0 && new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { @@ -1486,12 +1481,12 @@ bool change_password(THD *thd, const cha /* Update loaded acl entry in memory. - set_user_salt() stores a binary (compact) representation of the password - in memory (acl_user->salt and salt_len). + sql_user::set_user_salt() stores a binary (compact) representation of the + password in memory (sql_user->salt and sql_user->salt_len). set_user_plugin() sets the appropriate plugin based on password length and if the length doesn't match a warning is issued. */ - set_user_salt(acl_user, new_password, new_password_len); + sql_user->set_user_salt(new_password, new_password_len); thd->security_ctx->password_expired= false; } else @@ -1506,8 +1501,8 @@ bool change_password(THD *thd, const cha } if (update_user_table(thd, table, - acl_user->host.get_host() ? acl_user->host.get_host() : "", - acl_user->user ? acl_user->user : "", + sql_user->host()->get_host() ? sql_user->host()->get_host() : "", + sql_user->user()->ptr() ? sql_user->user()->ptr() : "", new_password, new_password_len, password_field, false)) { mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ @@ -1518,8 +1513,8 @@ bool change_password(THD *thd, const cha mysql_mutex_unlock(&acl_cache->lock); result= 0; query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'", - acl_user->user ? acl_user->user : "", - acl_user->host.get_host() ? acl_user->host.get_host() : "", + sql_user->user()->ptr() ? sql_user->user()->ptr() : "", + sql_user->host()->get_host() ? sql_user->host()->get_host() : "", new_password); result= write_bin_log(thd, true, buff, query_length, table->file->has_transactions()); @@ -1567,7 +1562,7 @@ bool is_acl_user(const char *host, const Find first entry that matches the current user */ -ACL_USER * +Sql_user_implementation * find_acl_user(const char *host, const char *user, my_bool exact) { DBUG_ENTER("find_acl_user"); @@ -1575,23 +1570,25 @@ find_acl_user(const char *host, const ch mysql_mutex_assert_owner(&acl_cache->lock); - for (uint i=0 ; i < acl_users.elements ; i++) + for (uint i=0 ; i < sql_users.elements ; i++) { - ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); + Sql_user_implementation *sql_user=dynamic_element(&sql_users,i,Sql_user_implementation*); + const String *user_string= sql_user->user(); + ACL_HOST_AND_IP *host_ptr= sql_user->host(); DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", - user, acl_user->user ? acl_user->user : "", + user, user_string->ptr() ? user_string->ptr() : "", host, - acl_user->host.get_host() ? acl_user->host.get_host() : + host_ptr->get_host() ? host_ptr->get_host() : "")); - if ((!acl_user->user && !user[0]) || - (acl_user->user && !strcmp(user,acl_user->user))) + if ((!user_string->ptr() && !user[0]) || + (user_string->ptr() && !strcmp(user,user_string->ptr()))) { if (exact ? !my_strcasecmp(system_charset_info, host, - acl_user->host.get_host() ? - acl_user->host.get_host() : "") : - acl_user->host.compare_hostname(host,host)) + host_ptr->get_host() ? + host_ptr->get_host() : "") : + host_ptr->compare_hostname(host,host)) { - DBUG_RETURN(acl_user); + DBUG_RETURN(sql_user); } } } @@ -5034,13 +5031,13 @@ bool mysql_show_grants(THD *thd,LEX_USER ulong want_access; uint counter,index; int error = 0; - ACL_USER *acl_user; + Sql_user *sql_user; ACL_DB *acl_db; char buff[1024]; Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_show_grants"); - LINT_INIT(acl_user); + LINT_INIT(sql_user); if (!initialized) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); @@ -5050,8 +5047,9 @@ bool mysql_show_grants(THD *thd,LEX_USER mysql_rwlock_rdlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); - acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE); - if (!acl_user) + sql_user= (Sql_user*) find_acl_user(lex_user->host.str, + lex_user->user.str, TRUE); + if (!sql_user) { mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant); @@ -5083,7 +5081,7 @@ bool mysql_show_grants(THD *thd,LEX_USER global.length(0); global.append(STRING_WITH_LEN("GRANT ")); - want_access= acl_user->access; + want_access= sql_user->global_acl(); if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL))) global.append(STRING_WITH_LEN("ALL PRIVILEGES")); else if (!(want_access & ~GRANT_ACL)) @@ -5111,76 +5109,83 @@ bool mysql_show_grants(THD *thd,LEX_USER system_charset_info); global.append ('\''); #if defined(HAVE_OPENSSL) - if (acl_user->plugin.str == sha256_password_plugin_name.str) + if (sql_user->authentication_plugin()->ptr() == sha256_password_plugin_name.str) { global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); - global.append((const char *) &acl_user->auth_string.str[0]); + global.append((const char *) (sql_user->authentication_string()->ptr())); global.append('\''); } else #endif - if (acl_user->salt_len) + if (sql_user->salt_len()) { char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; - if (acl_user->salt_len == SCRAMBLE_LENGTH) - make_password_from_salt(passwd_buff, acl_user->salt); + if (sql_user->salt_len() == SCRAMBLE_LENGTH) + make_password_from_salt(passwd_buff, sql_user->salt()); else - make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); + make_password_from_salt_323(passwd_buff, (ulong *) sql_user->salt()); global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); global.append(passwd_buff); global.append('\''); } /* "show grants" SSL related stuff */ - if (acl_user->ssl_type == SSL_TYPE_ANY) + enum SSL_type ssl_type= sql_user->ssl_authentication_type(); + if (ssl_type == SSL_TYPE_ANY) global.append(STRING_WITH_LEN(" REQUIRE SSL")); - else if (acl_user->ssl_type == SSL_TYPE_X509) + else if (ssl_type == SSL_TYPE_X509) global.append(STRING_WITH_LEN(" REQUIRE X509")); - else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) + else if (ssl_type == SSL_TYPE_SPECIFIED) { int ssl_options = 0; global.append(STRING_WITH_LEN(" REQUIRE ")); - if (acl_user->x509_issuer) + const String *x509_issuer= sql_user->x509_issuer(); + const String *x509_subject= sql_user->x509_subject(); + const String *ssl_cipher= sql_user->ssl_cipher(); + if (x509_issuer->ptr()) { ssl_options++; global.append(STRING_WITH_LEN("ISSUER \'")); - global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + global.append(x509_issuer->ptr(),x509_issuer->length(), + system_charset_info); global.append('\''); } - if (acl_user->x509_subject) + if (x509_subject->ptr()) { if (ssl_options++) global.append(' '); global.append(STRING_WITH_LEN("SUBJECT \'")); - global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), + global.append(x509_subject->ptr(),x509_subject->length(), system_charset_info); global.append('\''); } - if (acl_user->ssl_cipher) + if (ssl_cipher->ptr()) { if (ssl_options++) global.append(' '); global.append(STRING_WITH_LEN("CIPHER '")); - global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), + global.append(ssl_cipher->ptr(),ssl_cipher->length(), system_charset_info); global.append('\''); } } + + const USER_RESOURCES *user_resource= sql_user->user_resources(); if ((want_access & GRANT_ACL) || - (acl_user->user_resource.questions || - acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn)) + (user_resource->questions || + user_resource->updates || + user_resource->conn_per_hour || + user_resource->user_conn)) { global.append(STRING_WITH_LEN(" WITH")); if (want_access & GRANT_ACL) global.append(STRING_WITH_LEN(" GRANT OPTION")); - add_user_option(&global, acl_user->user_resource.questions, + add_user_option(&global, user_resource->questions, "MAX_QUERIES_PER_HOUR"); - add_user_option(&global, acl_user->user_resource.updates, + add_user_option(&global, user_resource->updates, "MAX_UPDATES_PER_HOUR"); - add_user_option(&global, acl_user->user_resource.conn_per_hour, + add_user_option(&global, user_resource->conn_per_hour, "MAX_CONNECTIONS_PER_HOUR"); - add_user_option(&global, acl_user->user_resource.user_conn, + add_user_option(&global, user_resource->user_conn, "MAX_USER_CONNECTIONS"); } protocol->prepare_for_resend(); @@ -5522,12 +5527,15 @@ void get_privilege_desc(char *to, uint m void get_mqh(const char *user, const char *host, USER_CONN *uc) { - ACL_USER *acl_user; + Sql_user *sql_user; mysql_mutex_lock(&acl_cache->lock); - if (initialized && (acl_user= find_acl_user(host,user, FALSE))) - uc->user_resources= acl_user->user_resource; + if (initialized && (sql_user= (Sql_user*)find_acl_user(host,user, FALSE))) + { + const USER_RESOURCES *user_resources= sql_user->user_resources(); + uc->user_resources= *user_resources; + } else memset(&uc->user_resources, 0, sizeof(uc->user_resources)); @@ -5849,7 +5857,7 @@ static int handle_grant_table(TABLE_LIST Update in grant structure if drop is false and user_to is not NULL. Search in grant structure if drop is false and user_to is NULL. Structures are numbered as follows: - 0 acl_users + 0 sql_users 1 acl_dbs 2 column_priv_hash 3 proc_priv_hash @@ -5869,7 +5877,7 @@ static int handle_grant_struct(uint stru uint elements; const char *user; const char *host; - ACL_USER *acl_user= NULL; + Sql_user_implementation *sql_user= NULL; ACL_DB *acl_db= NULL; ACL_PROXY_USER *acl_proxy_user= NULL; GRANT_NAME *grant_name= NULL; @@ -5886,7 +5894,7 @@ static int handle_grant_struct(uint stru /* Get the number of elements in the in-memory structure. */ switch (struct_no) { case 0: - elements= acl_users.elements; + elements= sql_users.elements; break; case 1: elements= acl_dbs.elements; @@ -5922,9 +5930,9 @@ static int handle_grant_struct(uint stru */ switch (struct_no) { case 0: - acl_user= dynamic_element(&acl_users, idx, ACL_USER*); - user= acl_user->user; - host= acl_user->host.get_host(); + sql_user= dynamic_element(&sql_users, idx, Sql_user_implementation*); + user= sql_user->user()->ptr(); + host= sql_user->host()->get_host(); break; case 1: @@ -5968,7 +5976,7 @@ static int handle_grant_struct(uint stru { switch ( struct_no ) { case 0: - delete_dynamic_element(&acl_users, idx); + delete_dynamic_element(&sql_users, idx); break; case 1: @@ -6006,8 +6014,8 @@ static int handle_grant_struct(uint stru { switch ( struct_no ) { case 0: - acl_user->user= strdup_root(&global_acl_memory, user_to->user.str); - acl_user->host.update_hostname(strdup_root(&global_acl_memory, user_to->host.str)); + sql_user->set_user(strdup_root(&global_acl_memory, user_to->user.str)); + sql_user->update_hostname(strdup_root(&global_acl_memory, user_to->host.str)); break; case 1: @@ -6511,7 +6519,7 @@ bool mysql_drop_user(THD *thd, List lock); @@ -6612,7 +6620,7 @@ bool mysql_rename_user(THD *thd, List lock); @@ -6696,7 +6704,7 @@ bool mysql_user_password_expire(THD *thd while ((tmp_user_from= user_list++)) { - ACL_USER *acl_user; + Sql_user_implementation *sql_user; if (!(user_from= get_current_user(thd, tmp_user_from))) { @@ -6707,12 +6715,12 @@ bool mysql_user_password_expire(THD *thd } enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD; - if ((!(acl_user= find_acl_user(user_from->host.str, + if ((!(sql_user= find_acl_user(user_from->host.str, user_from->user.str, TRUE))) || update_user_table(thd, table, - acl_user->host.get_host() ? - acl_user->host.get_host() : "", - acl_user->user ? acl_user->user : "", + sql_user->host()->get_host() ? + sql_user->host()->get_host() : "", + sql_user->user()->ptr() ? sql_user->user()->ptr() : "", NULL, 0, password_field, true)) { result= true; @@ -6721,7 +6729,7 @@ bool mysql_user_password_expire(THD *thd continue; } - acl_user->password_expired= true; + sql_user->set_password_expired(); some_passwords_expired= true; } @@ -7137,7 +7145,7 @@ bool sp_grant_privileges(THD *thd, const TABLE_LIST tables[1]; List user_list; bool result; - ACL_USER *au; + Sql_user *su; Dummy_error_handler error_handler; DBUG_ENTER("sp_grant_privileges"); @@ -7148,13 +7156,13 @@ bool sp_grant_privileges(THD *thd, const mysql_mutex_lock(&acl_cache->lock); - if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) + if ((su= (Sql_user*)find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE))) + if ((su= (Sql_user*)find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE))) goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE))) + if ((su= (Sql_user*)find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE))) goto found_acl; - if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) + if((su= (Sql_user*)find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) goto found_acl; mysql_mutex_unlock(&acl_cache->lock); @@ -7360,7 +7368,7 @@ int fill_schema_user_privileges(THD *thd #ifndef NO_EMBEDDED_ACCESS_CHECKS int error= 0; uint counter; - ACL_USER *acl_user; + Sql_user *sql_user; ulong want_access; char buff[100]; TABLE *table= tables->table; @@ -7373,13 +7381,13 @@ int fill_schema_user_privileges(THD *thd DBUG_RETURN(0); mysql_mutex_lock(&acl_cache->lock); - for (counter=0 ; counter < acl_users.elements ; counter++) + for (counter=0 ; counter < sql_users.elements ; counter++) { const char *user,*host, *is_grantable="YES"; - acl_user=dynamic_element(&acl_users,counter,ACL_USER*); - if (!(user=acl_user->user)) + sql_user=dynamic_element(&sql_users,counter,Sql_user_implementation*); + if (!(user=sql_user->user()->ptr())) user= ""; - if (!(host=acl_user->host.get_host())) + if (!(host=sql_user->host()->get_host())) host= ""; if (no_global_access && @@ -7387,7 +7395,7 @@ int fill_schema_user_privileges(THD *thd my_strcasecmp(system_charset_info, curr_host, host))) continue; - want_access= acl_user->access; + want_access= sql_user->global_acl(); if (!(want_access & GRANT_ACL)) is_grantable= "NO"; === modified file 'sql/auth/sql_authentication.cc' --- a/sql/auth/sql_authentication.cc 2012-09-06 12:02:23 +0000 +++ b/sql/auth/sql_authentication.cc 2012-09-18 12:46:18 +0000 @@ -23,6 +23,7 @@ #include "sql_db.h" #include #include "auth_common.h" +#include "sql_authorization.h" #include "sql_authentication.h" static LEX_STRING validate_password_plugin_name= { @@ -57,7 +58,7 @@ acl_find_proxy_user(const char *user, co static bool find_mpvio_user(MPVIO_EXT *mpvio); static bool read_client_connect_attrs(char **ptr, size_t *max_bytes_available, const CHARSET_INFO *from_cs); -static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user); +static bool acl_check_ssl(THD *thd, const Sql_user *sql_user); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ #ifndef EMBEDDED_LIBRARY @@ -161,7 +162,7 @@ acl_find_proxy_user(const char *user, co failure if a user is not found. @note find_acl_user is not the same, because it doesn't take into - account the case when user is not empty, but acl_user->user is empty + account the case when user is not empty, but sql_user->user is empty @retval 0 found @retval 1 not found @@ -170,67 +171,76 @@ static bool find_mpvio_user(MPVIO_EXT *m { DBUG_ENTER("find_mpvio_user"); DBUG_PRINT("info", ("entry: %s", mpvio->auth_info.user_name)); - DBUG_ASSERT(mpvio->acl_user == 0); + DBUG_ASSERT(mpvio->sql_user == 0); mysql_mutex_lock(&acl_cache->lock); - for (uint i=0; i < acl_users.elements; i++) + for (uint i=0; i < sql_users.elements; i++) { - ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*); - if ((!acl_user_tmp->user || - !strcmp(mpvio->auth_info.user_name, acl_user_tmp->user)) && - acl_user_tmp->host.compare_hostname(mpvio->host, mpvio->ip)) + Sql_user_implementation *sql_user_tmp= + dynamic_element(&sql_users, i, Sql_user_implementation*); + if ((!sql_user_tmp->user()->ptr() || + !strcmp(mpvio->auth_info.user_name, sql_user_tmp->user()->ptr())) && + sql_user_tmp->host()->compare_hostname(mpvio->host, mpvio->ip)) { - mpvio->acl_user= acl_user_tmp->copy(mpvio->mem_root); + mpvio->sql_user= (Sql_user *)sql_user_tmp->copy(mpvio->mem_root); /* - When setting mpvio->acl_user_plugin we can save memory allocation if + When setting mpvio->sql_user_plugin we can save memory allocation if this is a built in plugin. */ - optimize_plugin_compare_by_pointer(&acl_user_tmp->plugin); - if (auth_plugin_is_built_in(acl_user_tmp->plugin.str)) - mpvio->acl_user_plugin= mpvio->acl_user->plugin; + LEX_STRING user_plugin; + user_plugin.str= (char *)mpvio->sql_user->authentication_plugin()->ptr(); + user_plugin.length= mpvio->sql_user->authentication_plugin()->length(); + //optimize_plugin_compare_by_pointer(&sql_user_tmp->plugin); + if (auth_plugin_is_built_in(mpvio->sql_user->authentication_plugin()->ptr())) + { + mpvio->sql_user_plugin = user_plugin; + } else make_lex_string_root(mpvio->mem_root, - &mpvio->acl_user_plugin, - acl_user_tmp->plugin.str, - acl_user_tmp->plugin.length, 0); + &mpvio->sql_user_plugin, + user_plugin.str, + user_plugin.length, 0); break; } } mysql_mutex_unlock(&acl_cache->lock); - if (!mpvio->acl_user) + if (!mpvio->sql_user) { login_failed_error(mpvio, mpvio->auth_info.password_used); DBUG_RETURN (1); } - if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str, + const String *plugin_string= mpvio->sql_user->authentication_plugin(); + const String *authentication_string= mpvio->sql_user->authentication_string(); + + if (my_strcasecmp(system_charset_info, plugin_string->ptr(), native_password_plugin_name.str) != 0 && - my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str, + my_strcasecmp(system_charset_info, plugin_string->ptr(), old_password_plugin_name.str) != 0 && !(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)) { /* user account requires non-default plugin and the client is too old */ - DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str, + DBUG_ASSERT(my_strcasecmp(system_charset_info, plugin_string->ptr(), native_password_plugin_name.str)); - DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str, + DBUG_ASSERT(my_strcasecmp(system_charset_info, plugin_string->ptr(), old_password_plugin_name.str)); my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0)); general_log_print(current_thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); DBUG_RETURN (1); } - mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str; + mpvio->auth_info.auth_string= authentication_string->ptr(); mpvio->auth_info.auth_string_length= - (unsigned long) mpvio->acl_user->auth_string.length; - strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ? - mpvio->acl_user->user : "", USERNAME_LENGTH); + (unsigned long) authentication_string->length(); + strmake(mpvio->auth_info.authenticated_as, mpvio->sql_user->user()->ptr() ? + mpvio->sql_user->user()->ptr() : "", USERNAME_LENGTH); DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s" ", plugin=%s", mpvio->auth_info.user_name, mpvio->auth_info.auth_string, mpvio->auth_info.authenticated_as, - mpvio->acl_user->plugin.str)); + plugin_string->ptr())); DBUG_RETURN(0); } @@ -271,7 +281,7 @@ read_client_connect_attrs(char **ptr, si } -static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) +static bool acl_check_ssl(THD *thd, const Sql_user *sql_user) { #if defined(HAVE_OPENSSL) Vio *vio= thd->net.vio; @@ -285,7 +295,7 @@ static bool acl_check_ssl(THD *thd, cons we check if SSL is required, if user is using SSL and if X509 certificate attributes are OK */ - switch (acl_user->ssl_type) { + switch (sql_user->ssl_authentication_type()) { case SSL_TYPE_NOT_SPECIFIED: // Impossible case SSL_TYPE_NONE: // SSL is not required return 0; @@ -313,15 +323,16 @@ static bool acl_check_ssl(THD *thd, cons if (vio_type(vio) != VIO_TYPE_SSL || SSL_get_verify_result(ssl) != X509_V_OK) return 1; - if (acl_user->ssl_cipher) + const String *ssl_cipher_string= sql_user->ssl_cipher(); + if (ssl_cipher_string->ptr()) { DBUG_PRINT("info", ("comparing ciphers: '%s' and '%s'", - acl_user->ssl_cipher, SSL_get_cipher(ssl))); - if (strcmp(acl_user->ssl_cipher, SSL_get_cipher(ssl))) + ssl_cipher_string->ptr(), SSL_get_cipher(ssl))); + if (strcmp(ssl_cipher_string->ptr(), SSL_get_cipher(ssl))) { if (log_warnings) sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'", - acl_user->ssl_cipher, SSL_get_cipher(ssl)); + ssl_cipher_string->ptr(), SSL_get_cipher(ssl)); return 1; } } @@ -329,16 +340,17 @@ static bool acl_check_ssl(THD *thd, cons if (!(cert= SSL_get_peer_certificate(ssl))) return 1; /* If X509 issuer is specified, we check it... */ - if (acl_user->x509_issuer) + const String *x509_issuer_string= sql_user->x509_issuer(); + if (x509_issuer_string->ptr()) { char *ptr= X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); DBUG_PRINT("info", ("comparing issuers: '%s' and '%s'", - acl_user->x509_issuer, ptr)); - if (strcmp(acl_user->x509_issuer, ptr)) + x509_issuer_string->ptr(), ptr)); + if (strcmp(x509_issuer_string->ptr(), ptr)) { if (log_warnings) sql_print_information("X509 issuer mismatch: should be '%s' " - "but is '%s'", acl_user->x509_issuer, ptr); + "but is '%s'", x509_issuer_string->ptr(), ptr); free(ptr); X509_free(cert); return 1; @@ -346,16 +358,17 @@ static bool acl_check_ssl(THD *thd, cons free(ptr); } /* X509 subject is specified, we check it .. */ - if (acl_user->x509_subject) + const String *x509_subject_string= sql_user->x509_subject(); + if (x509_subject_string->ptr()) { char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); DBUG_PRINT("info", ("comparing subjects: '%s' and '%s'", - acl_user->x509_subject, ptr)); - if (strcmp(acl_user->x509_subject, ptr)) + x509_subject_string->ptr(), ptr)); + if (strcmp(x509_subject_string->ptr(), ptr)) { if (log_warnings) sql_print_information("X509 subject mismatch: should be '%s' but is '%s'", - acl_user->x509_subject, ptr); + x509_subject_string->ptr(), ptr); free(ptr); X509_free(cert); return 1; @@ -884,8 +897,8 @@ static bool parse_com_change_user_packet old_password_plugin, otherwise MySQL will think that server and client plugins don't match. */ - if (mpvio->acl_user->salt_len == 0) - mpvio->acl_user_plugin= old_password_plugin_name; + if (mpvio->sql_user->salt_len() == 0) + mpvio->sql_user_plugin= old_password_plugin_name; } } @@ -1441,13 +1454,13 @@ skip_to_ssl: old_password_plugin, otherwise MySQL will think that server and client plugins don't match. */ - if (mpvio->acl_user->salt_len == 0) - mpvio->acl_user_plugin= old_password_plugin_name; + if (mpvio->sql_user->salt_len() == 0) + mpvio->sql_user_plugin= old_password_plugin_name; } } /* - if the acl_user needs a different plugin to authenticate + if the sql_user needs a different plugin to authenticate (specified in GRANT ... AUTHENTICATED VIA plugin_name ..) we need to restart the authentication in the server. But perhaps the client has already used the correct plugin - @@ -1455,7 +1468,7 @@ skip_to_ssl: restarted and a server auth plugin will read the data that the client has just send. Cache them to return in the next server_mpvio_read_packet(). */ - if (my_strcasecmp(system_charset_info, mpvio->acl_user_plugin.str, + if (my_strcasecmp(system_charset_info, mpvio->sql_user_plugin.str, plugin_name(mpvio->plugin)->str) != 0) { mpvio->cached_client_reply.pkt= passwd; @@ -1846,18 +1859,19 @@ acl_authenticate(THD *thd, uint com_chan */ if (mpvio.status == MPVIO_EXT::RESTART) { - DBUG_ASSERT(mpvio.acl_user); + DBUG_ASSERT(mpvio.sql_user); DBUG_ASSERT(command == COM_CHANGE_USER || my_strcasecmp(system_charset_info, auth_plugin_name.str, - mpvio.acl_user->plugin.str)); - auth_plugin_name= mpvio.acl_user->plugin; + mpvio.sql_user->authentication_plugin()->ptr())); + auth_plugin_name.str= (char *)(mpvio.sql_user->authentication_plugin()->ptr()); + auth_plugin_name.length= (unsigned int)mpvio.sql_user->authentication_plugin()->length(); res= do_auth_once(thd, &auth_plugin_name, &mpvio); } server_mpvio_update_thd(thd, &mpvio); Security_context *sctx= thd->security_ctx; - const ACL_USER *acl_user= mpvio.acl_user; + const Sql_user *sql_user= mpvio.sql_user; thd->password= mpvio.auth_info.password_used; // remember for error messages @@ -1916,7 +1930,7 @@ acl_authenticate(THD *thd, uint com_chan { #ifndef NO_EMBEDDED_ACCESS_CHECKS bool is_proxy_user= FALSE; - const char *auth_user = acl_user->user ? acl_user->user : ""; + const char *auth_user = sql_user->user()->ptr() ? sql_user->user()->ptr() : ""; ACL_PROXY_USER *proxy_user; /* check if the user is allowed to proxy as another user */ proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip, @@ -1924,7 +1938,7 @@ acl_authenticate(THD *thd, uint com_chan &is_proxy_user); if (is_proxy_user) { - ACL_USER *acl_proxy_user; + Sql_user_implementation *sql_proxy_user; /* we need to find the proxy user, but there was none */ if (!proxy_user) @@ -1939,14 +1953,14 @@ acl_authenticate(THD *thd, uint com_chan my_snprintf(sctx->proxy_user, sizeof(sctx->proxy_user) - 1, "'%s'@'%s'", auth_user, - acl_user->host.get_host() ? acl_user->host.get_host() : ""); + sql_user->const_host()->get_host() ? sql_user->const_host()->get_host() : ""); /* we're proxying : find the proxy user definition */ mysql_mutex_lock(&acl_cache->lock); - acl_proxy_user= find_acl_user(proxy_user->get_proxied_host() ? + sql_proxy_user= find_acl_user(proxy_user->get_proxied_host() ? proxy_user->get_proxied_host() : "", mpvio.auth_info.authenticated_as, TRUE); - if (!acl_proxy_user) + if (!sql_proxy_user) { Host_errors errors; errors.m_proxy_user_acl= 1; @@ -1956,21 +1970,21 @@ acl_authenticate(THD *thd, uint com_chan mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(1); } - acl_user= acl_proxy_user->copy(thd->mem_root); + sql_user= sql_proxy_user->copy(thd->mem_root); DBUG_PRINT("info", ("User %s is a PROXY and will assume a PROXIED" - " identity %s", auth_user, acl_user->user)); + " identity %s", auth_user, sql_user->user()->ptr())); mysql_mutex_unlock(&acl_cache->lock); } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - sctx->master_access= acl_user->access; - if (acl_user->user) - strmake(sctx->priv_user, acl_user->user, USERNAME_LENGTH - 1); + sctx->master_access= sql_user->global_acl(); + if (sql_user->user()->ptr()) + strmake(sctx->priv_user, sql_user->user()->ptr(), USERNAME_LENGTH - 1); else *sctx->priv_user= 0; - if (acl_user->host.get_host()) - strmake(sctx->priv_host, acl_user->host.get_host(), MAX_HOSTNAME - 1); + if (sql_user->const_host()->get_host()) + strmake(sctx->priv_host, sql_user->const_host()->get_host(), MAX_HOSTNAME - 1); else *sctx->priv_host= 0; @@ -1980,7 +1994,7 @@ acl_authenticate(THD *thd, uint com_chan as an additional layer, not instead of the password (in which case it would've been a plugin too). */ - if (acl_check_ssl(thd, acl_user)) + if (acl_check_ssl(thd, sql_user)) { Host_errors errors; errors.m_ssl= 1; @@ -1990,18 +2004,19 @@ acl_authenticate(THD *thd, uint com_chan DBUG_RETURN(1); } + const USER_RESOURCES *user_resource= sql_user->user_resources(); /* Don't allow the user to connect if he has done too many queries */ - if ((acl_user->user_resource.questions || acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || + if ((user_resource->questions || user_resource->updates || + user_resource->conn_per_hour || + user_resource->user_conn || global_system_variables.max_user_connections) && get_or_create_user_conn(thd, (opt_old_style_user_limits ? sctx->user : sctx->priv_user), (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), - &acl_user->user_resource)) + sql_user->user_resources())) DBUG_RETURN(1); // The error is set by get_or_create_user_conn() - sctx->password_expired= acl_user->password_expired; + sctx->password_expired= sql_user->password_expired(); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ } else @@ -2159,15 +2174,15 @@ static int native_password_authenticate( ); if (pkt_len == 0) /* no password */ - DBUG_RETURN(mpvio->acl_user->salt_len != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK); + DBUG_RETURN(mpvio->sql_user->salt_len() != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK); info->password_used= PASSWORD_USED_YES; if (pkt_len == SCRAMBLE_LENGTH) { - if (!mpvio->acl_user->salt_len) + if (!mpvio->sql_user->salt_len()) DBUG_RETURN(CR_AUTH_USER_CREDENTIALS); - DBUG_RETURN(check_scramble(pkt, mpvio->scramble, mpvio->acl_user->salt) ? + DBUG_RETURN(check_scramble(pkt, mpvio->scramble, mpvio->sql_user->salt()) ? CR_AUTH_USER_CREDENTIALS : CR_OK); } @@ -2207,7 +2222,7 @@ static int old_password_authenticate(MYS pkt_len= strnlen((char*)pkt, pkt_len); if (pkt_len == 0) /* no password */ - return mpvio->acl_user->salt_len != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK; + return mpvio->sql_user->salt_len() != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK; if (secure_auth(mpvio)) return CR_AUTH_HANDSHAKE; @@ -2216,11 +2231,11 @@ static int old_password_authenticate(MYS if (pkt_len == SCRAMBLE_LENGTH_323) { - if (!mpvio->acl_user->salt_len) + if (!mpvio->sql_user->salt_len()) return CR_AUTH_USER_CREDENTIALS; return check_scramble_323(pkt, mpvio->scramble, - (ulong *) mpvio->acl_user->salt) ? + (ulong *) mpvio->sql_user->salt()) ? CR_AUTH_USER_CREDENTIALS : CR_OK; } @@ -2508,7 +2523,7 @@ static int sha256_password_authenticate( /* After the call to read_packet() the user name will appear in - mpvio->acl_user and info will contain current data. + mpvio->sql_user and info will contain current data. */ if ((pkt_len= vio->read_packet(vio, &pkt)) == -1) DBUG_RETURN(CR_ERROR); === modified file 'sql/auth/sql_authentication.h' --- a/sql/auth/sql_authentication.h 2012-09-06 12:02:23 +0000 +++ b/sql/auth/sql_authentication.h 2012-09-18 12:46:18 +0000 @@ -2,7 +2,7 @@ #define SQL_AUTHENTICATION_INCLUDED #include // MYSQL_SERVER_AUTH_INFO -class ACL_USER; +class Sql_user; /* Defines */ /** Size of the header fields of an authentication packet. */ @@ -28,7 +28,7 @@ public: struct MPVIO_EXT :public MYSQL_PLUGIN_VIO { MYSQL_SERVER_AUTH_INFO auth_info; - const ACL_USER *acl_user; + const Sql_user *sql_user; plugin_ref plugin; ///< what plugin we're under LEX_STRING db; ///< db name from the handshake packet /** when restarting a plugin this caches the last client reply */ @@ -57,7 +57,7 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VI char *ip; char *host; Thd_charset_adapter *charset_adapter; - LEX_STRING acl_user_plugin; + LEX_STRING sql_user_plugin; int vio_is_encrypted; }; === added file 'sql/auth/sql_authorization.cc' --- a/sql/auth/sql_authorization.cc 1970-01-01 00:00:00 +0000 +++ b/sql/auth/sql_authorization.cc 2012-09-18 12:46:18 +0000 @@ -0,0 +1,255 @@ +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "my_global.h" +#include "sql_acl.h" +#include "hash_filo.h" +#include "sql_connect.h" +#include +#include "sql_common.h" +#include "hostname.h" +#include "sql_db.h" +#include +#include "auth_common.h" +#include "sql_authentication.h" +#include "sql_authorization.h" + + +Sql_user::~Sql_user() +{ +} + + +/** + Note : Destructor for Sql_user_implementation() + is kept empty because destruction of + Sql_user_implementation object is expected through + delete_dynamic() + Trying to free memory through destructor will + cause segmentation fault in delete_dynamic() +*/ +Sql_user_implementation::~Sql_user_implementation() +{ +} + +/** + @brief Wrapper around update_hostname() of ACL_HOST_AND_IP. + @param host_arg Value to be stored + */ +void Sql_user_implementation::update_hostname(const char *host_arg) +{ + m_host.update_hostname(host_arg); + uint32 length= host_arg ? (uint32)strlen(host_arg) : 0; + m_hostname.set(host_arg, length, system_charset_info); +} + +/** + Functions to set various members of Sql_user_implementation. + */ + +/** + @brief setting user name in Sql_user_implementation . + @param user Name of the user +*/ +void Sql_user_implementation::set_user(const char* user) +{ + uint32 length= user ? (uint32)strlen(user) : 0; + m_user.set(user, length, system_charset_info); +} + + +/** + @brief setting password hash for the user. + @param authentication_string Password hash value +*/ +void +Sql_user_implementation::set_authentication_string(const char* authentication_string, + uint32 length) +{ + m_authentication_string.set(authentication_string, length, + system_charset_info); +} + + +/** + @brief setting plugin details. + @param authentication_plugin Plugin details from user table +*/ +void +Sql_user_implementation::set_authentication_plugin(const char* authentication_plugin, + uint32 length) +{ + m_authentication_plugin.set(authentication_plugin, length, + system_charset_info); +} + + +/** + @brief seting cipher details. + @param ssl_cipher ssl cipher details +*/ +void Sql_user_implementation::set_ssl_cipher(const char* ssl_cipher) +{ + uint32 length= ssl_cipher ? (uint32)strlen(ssl_cipher) : 0; + m_ssl_cipher.set(ssl_cipher, length, system_charset_info); +} + + +/** + @brief setting certificate issuer details. + @param x509_issuer issuer details from the certificate +*/ +void Sql_user_implementation::set_x509_issuer(const char* x509_issuer) +{ + uint32 length= x509_issuer ? (uint32)strlen(x509_issuer) : 0; + m_x509_issuer.set(x509_issuer, length, system_charset_info); +} + + +/** + @brief setting certificate subject details. + @param x509_subject subject line of a certificate +*/ +void Sql_user_implementation::set_x509_subject(const char* x509_subject) +{ + uint32 length= x509_subject ? (uint32)strlen(x509_subject) : 0; + m_x509_subject.set(x509_subject, length, system_charset_info); +} + + +/** + @brief setting various resource contraints for the user. + @param user_resources USER_RESOURCES structure with + resource details for user +*/ +void +Sql_user_implementation::set_user_resources_selective(USER_RESOURCES *user_resources) +{ + if (user_resources->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR) + m_user_resources.questions= user_resources->questions; + if (user_resources->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR) + m_user_resources.updates= user_resources->updates; + if (user_resources->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR) + m_user_resources.conn_per_hour= user_resources->conn_per_hour; + if (user_resources->specified_limits & USER_RESOURCES::USER_CONNECTIONS) + m_user_resources.user_conn= user_resources->user_conn; +} + + +/** + @brief setting various resource contraints for the user. + @param user_resources USER_RESOURCES structure with + resource details for user +*/ +void +Sql_user_implementation::set_user_resources(USER_RESOURCES *user_resources) +{ + m_user_resources.questions= user_resources->questions; + m_user_resources.updates= user_resources->updates; + m_user_resources.conn_per_hour= user_resources->conn_per_hour; + m_user_resources.user_conn= user_resources->user_conn; + m_user_resources.specified_limits= user_resources->specified_limits; +} + + +/** + Convert scrambled password to binary form, according to scramble type, + Binary form is stored in user.salt. + + @param sql_user The object where to store the salt + @param password The password hash containing the salt + @param password_len The length of the password hash + + Despite the name of the function it is used when loading ACLs from disk + to store the password hash in the Sql_user_implementation object. +*/ + +void +Sql_user_implementation::set_user_salt(const char *password, uint password_len) +{ + /* Using old password protocol */ + if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) + { + get_salt_from_password(m_salt, password); + m_salt_len= SCRAMBLE_LENGTH; + } + else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) + { + get_salt_from_password_323((ulong *) m_salt, password); + m_salt_len= SCRAMBLE_LENGTH_323; + } + else + m_salt_len= 0; + + /* + Since we're changing the password for the user we need to reset the + expiration flag. + */ + m_password_expired= false; +} + + +/** + @brief Set salt and salt_len. Used by copy() function. + @param salt source salt value + @param salt_len length of salt +*/ +void Sql_user_implementation::set_salt(uint8 *salt, uint8 salt_len) +{ + if(salt_len != 0) + for(uint i=0; i < SCRAMBLE_LENGTH + 1; i++) + { + m_salt[i]= salt[i]; + } + + m_salt_len= salt_len; +} + + +/** + @brief Make copy of a Sql_user_implementation object + @param root MEM_ROOT pointer of memory allocation +*/ +Sql_user_implementation *Sql_user_implementation::copy(MEM_ROOT *root) +{ + Sql_user_implementation *dst= + (Sql_user_implementation *) alloc_root(root, sizeof(Sql_user_implementation)); + + dst->set_mem_root(root); + dst->set_user(safe_strdup_root(root, m_user.ptr())); + dst->update_hostname(safe_strdup_root(root, m_host.get_host())); + dst->set_authentication_string(safe_strdup_root(root, + m_authentication_string.ptr()), + m_authentication_string.length()); + dst->set_authentication_plugin(safe_strdup_root(root, + m_authentication_plugin.ptr()), + m_authentication_plugin.length()); + dst->set_ssl_cipher(safe_strdup_root(root, m_ssl_cipher.ptr())); + dst->set_x509_issuer(safe_strdup_root(root, m_x509_issuer.ptr())); + dst->set_x509_subject(safe_strdup_root(root, m_x509_subject.ptr())); + dst->set_user_resources(&m_user_resources); + dst->set_sort(m_sort); + dst->set_global_acl(m_access); + + dst->set_salt(m_salt, m_salt_len); + + dst->set_ssl_authentication_type(m_ssl_type); + + m_password_expired ? + dst->set_password_expired() : dst->reset_password_expired(); + + return dst; +} + === added file 'sql/auth/sql_authorization.h' --- a/sql/auth/sql_authorization.h 1970-01-01 00:00:00 +0000 +++ b/sql/auth/sql_authorization.h 2012-09-18 12:46:18 +0000 @@ -0,0 +1,210 @@ +#ifndef SQL_AUTHORIZATION_INCLUDED +#define SQL_AUTHORIZATION_INCLUDED + +class ACL_HOST_AND_IP; + +/** + Sql_user Interface +*/ + +class Sql_user +{ + protected: + /** + Protect the constructor for virtual class + */ + Sql_user() {} + + public: + virtual ~Sql_user(); + /** + Interfaces to extract details from user object + */ + + virtual const String *user() const= 0; + virtual const String *hostname() const= 0; + virtual const String *authentication_string() const= 0; + virtual const String * authentication_plugin() const= 0; + virtual const String *ssl_cipher() const= 0; + virtual const String *x509_issuer() const= 0; + virtual const String *x509_subject() const= 0; + + virtual const USER_RESOURCES *user_resources() const= 0; + + virtual const ACL_HOST_AND_IP *const_host() const= 0; + virtual ACL_HOST_AND_IP *host()= 0; + + virtual bool password_expired() const= 0; + virtual SSL_type ssl_authentication_type() const= 0; + virtual ulong sort() const= 0; + virtual ulong global_acl() const= 0; + + virtual const uint8 *salt() const=0; + virtual uint8 salt_len() const=0; +}; + +class Sql_user_implementation : public Sql_user +{ + private: + + String m_user; + String m_hostname; + String m_authentication_string; + String m_authentication_plugin; + String m_ssl_cipher; + String m_x509_issuer; + String m_x509_subject; + + USER_RESOURCES m_user_resources; + + ACL_HOST_AND_IP m_host; + + ulong m_access; + ulong m_sort; + + uint8 m_salt[SCRAMBLE_LENGTH + 1]; + uint8 m_salt_len; + + enum SSL_type m_ssl_type; + + bool m_password_expired; + + MEM_ROOT *m_mem_root; + + public: + /** + Functions from Sql_user + */ + const String *user() const + { + return &m_user; + } + const String *hostname() const + { + return &m_hostname; + } + const String *authentication_string() const + { + return &m_authentication_string; + } + const String * authentication_plugin() const + { + return &m_authentication_plugin; + } + const String *ssl_cipher() const + { + return &m_ssl_cipher; + } + const String *x509_issuer() const + { + return &m_x509_issuer; + } + const String *x509_subject() const + { + return &m_x509_subject; + } + + const USER_RESOURCES *user_resources() const + { + return &m_user_resources; + } + + const ACL_HOST_AND_IP *const_host() const + { + return &m_host; + } + + ACL_HOST_AND_IP *host() + { + return &m_host; + } + + virtual ulong sort() const + { + return m_sort; + } + + bool password_expired() const + { + return m_password_expired; + } + + SSL_type ssl_authentication_type() const + { + return m_ssl_type; + } + + ulong global_acl() const + { + return m_access; + } + + virtual const uint8 *salt() const + { + return m_salt; + } + + virtual uint8 salt_len() const + { + return m_salt_len; + } + + /** + Functions required by Sql_user_implementation + */ + Sql_user_implementation() {} + + Sql_user_implementation( MEM_ROOT *mem_root ) + { + memset(this, 0, sizeof(*this)); + m_mem_root= mem_root; + } + + /** + Note : Destructor for Sql_user_implementation() + is kept empty because destruction of + Sql_user_implementation object is expected through + delete_dynamic() + Trying to free memory through destructor will + cause segmentation fault in delete_dynamic() + */ + ~Sql_user_implementation(); + + Sql_user_implementation *copy(MEM_ROOT *mem_root); + + /** + Wrapper around update_hostname() of ACL_HOST_AND_IP + */ + void update_hostname(const char *host_arg); + /** + Functions to set various members of Sql_user_implementation + */ + void set_user(const char* user); + void set_authentication_string(const char* authentication_string, + uint32 length); + void set_authentication_plugin(const char* authentication_plugin, + uint32 length); + void set_ssl_cipher(const char* ssl_cipher); + void set_x509_issuer(const char* x509_issuer); + void set_x509_subject(const char* x509_subject); + + void set_user_resources_selective(USER_RESOURCES *user_resources); + void set_user_resources(USER_RESOURCES *user_resources); + + void set_password_expired() { m_password_expired= true; } + void reset_password_expired() { m_password_expired= false; } + + void set_ssl_authentication_type( enum SSL_type ssl_type ) { m_ssl_type= ssl_type; } + + void set_sort( ulong sort) { m_sort= sort; } + void set_global_acl( ulong access ) { m_access= access; } + + void set_mem_root(MEM_ROOT *mem_root) { m_mem_root= mem_root; } + + void set_user_salt(const char *password, uint password_len); + void set_salt(uint8 *salt, uint8 salt_len); + + +}; + +#endif /* SQL_AUTHORIZATION_INCLUDED */ === modified file 'sql/auth/sql_user_table.cc' --- a/sql/auth/sql_user_table.cc 2012-09-04 07:22:36 +0000 +++ b/sql/auth/sql_user_table.cc 2012-09-18 12:46:18 +0000 @@ -360,6 +360,7 @@ static my_bool acl_load(THD *thd, TABLE_ char tmp_name[NAME_LEN+1]; int password_length; sql_mode_t old_sql_mode= thd->variables.sql_mode; + ulong global_acl= 0; DBUG_ENTER("acl_load"); thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; @@ -377,24 +378,27 @@ static my_bool acl_load(THD *thd, TABLE_ NULL, 1, 1, FALSE)) goto end; table->use_all_columns(); - (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100); + (void) my_init_dynamic_array(&sql_users,sizeof(Sql_user_implementation),50,100); allow_all_hosts=0; while (!(read_record_info.read_record(&read_record_info))) { /* Reading record from mysql.user */ - ACL_USER user; - memset(&user, 0, sizeof(user)); - user.host.update_hostname(get_field(&global_acl_memory, - table->field[MYSQL_USER_FIELD_HOST])); - user.user= get_field(&global_acl_memory, - table->field[MYSQL_USER_FIELD_USER]); - if (check_no_resolve && hostname_requires_resolving(user.host.get_host())) + Sql_user_implementation user(&global_acl_memory); + user.update_hostname(get_field(&global_acl_memory, + table->field[MYSQL_USER_FIELD_HOST])); + user.set_user(get_field(&global_acl_memory, + table->field[MYSQL_USER_FIELD_USER])); + + const String *user_string= user.user(); + const String *host_string= user.hostname(); + if (check_no_resolve && + hostname_requires_resolving(user.host()->get_host())) { sql_print_warning("'user' entry '%s@%s' " "ignored in --skip-name-resolve mode.", - user.user ? user.user : "", - user.host.get_host() ? user.host.get_host() : ""); + user_string->ptr() ? user_string->ptr() : "", + host_string->ptr() ? host_string->ptr() : ""); continue; } @@ -403,95 +407,108 @@ static my_bool acl_load(THD *thd, TABLE_ char *password= get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_PASSWORD]); uint password_len= password ? strlen(password) : 0; - user.auth_string.str= password ? password : const_cast(""); - user.auth_string.length= password_len; + user.set_authentication_string(password ? + password : + const_cast(""), + (uint32)password_len); /* Transform hex to octets and adjust the format. */ - set_user_salt(&user, password, password_len); + user.set_user_salt(password, password_len); /* Set temporary plugin deduced from password length. If there are enough fields in the user table the real plugin will be read later. */ - user.plugin= native_password_plugin_name; if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) - user.plugin= old_password_plugin_name; + user.set_authentication_plugin(old_password_plugin_name.str, + (uint32)old_password_plugin_name.length); + else + user.set_authentication_plugin(native_password_plugin_name.str, + (uint32)native_password_plugin_name.length); + } { uint next_field; - user.access= get_access(table,3,&next_field) & GLOBAL_ACLS; + global_acl= get_access(table,3,&next_field) & GLOBAL_ACLS; /* if it is pre 5.0.1 privilege table then map CREATE privilege on CREATE VIEW & SHOW VIEW privileges */ - if (table->s->fields <= 31 && (user.access & CREATE_ACL)) - user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); + if (table->s->fields <= 31 && (global_acl & CREATE_ACL)) + global_acl|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); /* if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on CREATE PROCEDURE & ALTER PROCEDURE privileges */ - if (table->s->fields <= 33 && (user.access & CREATE_ACL)) - user.access|= CREATE_PROC_ACL; - if (table->s->fields <= 33 && (user.access & ALTER_ACL)) - user.access|= ALTER_PROC_ACL; + if (table->s->fields <= 33 && (global_acl & CREATE_ACL)) + global_acl|= CREATE_PROC_ACL; + if (table->s->fields <= 33 && (global_acl & ALTER_ACL)) + global_acl|= ALTER_PROC_ACL; /* pre 5.0.3 did not have CREATE_USER_ACL */ - if (table->s->fields <= 36 && (user.access & GRANT_ACL)) - user.access|= CREATE_USER_ACL; + if (table->s->fields <= 36 && (global_acl & GRANT_ACL)) + global_acl|= CREATE_USER_ACL; /* if it is pre 5.1.6 privilege table then map CREATE privilege on CREATE|ALTER|DROP|EXECUTE EVENT */ - if (table->s->fields <= 37 && (user.access & SUPER_ACL)) - user.access|= EVENT_ACL; + if (table->s->fields <= 37 && (global_acl & SUPER_ACL)) + global_acl|= EVENT_ACL; /* if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE. */ - if (table->s->fields <= 38 && (user.access & SUPER_ACL)) - user.access|= TRIGGER_ACL; + if (table->s->fields <= 38 && (global_acl & SUPER_ACL)) + global_acl|= TRIGGER_ACL; + + user.set_global_acl(global_acl); - user.sort= get_sort(2,user.host.get_host(),user.user); + user.set_sort(get_sort(2,user.host()->get_host(),user.user()->ptr())); /* Starting from 4.0.2 we have more fields */ if (table->s->fields >= 31) { char *ssl_type= get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_SSL_TYPE]); + enum SSL_type ssl_authentication_type; if (!ssl_type) - user.ssl_type=SSL_TYPE_NONE; + ssl_authentication_type= SSL_TYPE_NONE; else if (!strcmp(ssl_type, "ANY")) - user.ssl_type=SSL_TYPE_ANY; + ssl_authentication_type= SSL_TYPE_ANY; else if (!strcmp(ssl_type, "X509")) - user.ssl_type=SSL_TYPE_X509; + ssl_authentication_type= SSL_TYPE_X509; else /* !strcmp(ssl_type, "SPECIFIED") */ - user.ssl_type=SSL_TYPE_SPECIFIED; + ssl_authentication_type= SSL_TYPE_SPECIFIED; - user.ssl_cipher= - get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_SSL_CIPHER]); - user.x509_issuer= - get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_X509_ISSUER]); - user.x509_subject= - get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_X509_SUBJECT]); + user.set_ssl_authentication_type(ssl_authentication_type); + user.set_ssl_cipher(get_field(&global_acl_memory, + table->field[MYSQL_USER_FIELD_SSL_CIPHER])); + user.set_x509_issuer(get_field(&global_acl_memory, + table->field[MYSQL_USER_FIELD_X509_ISSUER])); + user.set_x509_subject(get_field(&global_acl_memory, + table->field[MYSQL_USER_FIELD_X509_SUBJECT])); + + USER_RESOURCES user_resource; char *ptr= get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_MAX_QUESTIONS]); - user.user_resource.questions=ptr ? atoi(ptr) : 0; + user_resource.questions=ptr ? atoi(ptr) : 0; ptr= get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_MAX_UPDATES]); - user.user_resource.updates=ptr ? atoi(ptr) : 0; + user_resource.updates=ptr ? atoi(ptr) : 0; ptr= get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_MAX_CONNECTIONS]); - user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0; - if (user.user_resource.questions || user.user_resource.updates || - user.user_resource.conn_per_hour) + user_resource.conn_per_hour= ptr ? atoi(ptr) : 0; + + if (user_resource.questions || user_resource.updates || + user_resource.conn_per_hour) mqh_used=1; if (table->s->fields >= 36) @@ -499,9 +516,11 @@ static my_bool acl_load(THD *thd, TABLE_ /* Starting from 5.0.3 we have max_user_connections field */ ptr= get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_MAX_USER_CONNECTIONS]); - user.user_resource.user_conn= ptr ? atoi(ptr) : 0; + user_resource.user_conn= ptr ? atoi(ptr) : 0; } + user.set_user_resources_selective(&user_resource); + if (table->s->fields >= 41) { /* We may have plugin & auth_String fields */ @@ -513,40 +532,46 @@ static my_bool acl_load(THD *thd, TABLE_ By comparing the plugin with the built in plugins it is possible to optimize the string allocation and comparision. */ + bool throw_warning= false; if (my_strcasecmp(system_charset_info, tmpstr, native_password_plugin_name.str) == 0) - user.plugin= native_password_plugin_name; + user.set_authentication_plugin(native_password_plugin_name.str, + (uint32)native_password_plugin_name.length); else if (my_strcasecmp(system_charset_info, tmpstr, old_password_plugin_name.str) == 0) - user.plugin= old_password_plugin_name; + user.set_authentication_plugin(old_password_plugin_name.str, + (uint32)old_password_plugin_name.length); #if defined(HAVE_OPENSSL) else if (my_strcasecmp(system_charset_info, tmpstr, sha256_password_plugin_name.str) == 0) - user.plugin= sha256_password_plugin_name; + { + user.set_authentication_plugin(sha256_password_plugin_name.str, + (uint32)sha256_password_plugin_name.length); + throw_warning= true; + } #endif else { - user.plugin.str= tmpstr; - user.plugin.length= strlen(tmpstr); + user.set_authentication_plugin(tmpstr,(uint32)strlen(tmpstr)); + throw_warning= true; } - if (user.auth_string.length && - user.plugin.str != native_password_plugin_name.str && - user.plugin.str != old_password_plugin_name.str) + if (user.authentication_string()->length() && throw_warning) { sql_print_warning("'user' entry '%s@%s' has both a password " "and an authentication plugin specified. The " "password will be ignored.", - user.user ? user.user : "", - user.host.get_host() ? user.host.get_host() : ""); + user_string->ptr() ? user_string->ptr() : "", + host_string->ptr() ? host_string->ptr() : ""); } - user.auth_string.str= - get_field(&global_acl_memory, + LEX_STRING authentication_string; + authentication_string.str= get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]); - if (!user.auth_string.str) - user.auth_string.str= const_cast(""); - user.auth_string.length= strlen(user.auth_string.str); + if (!authentication_string.str) + authentication_string.str= const_cast(""); + user.set_authentication_string(authentication_string.str, + (uint32)strlen(authentication_string.str)); } else /* skip auth_string if there's no plugin */ next_field++; @@ -557,36 +582,39 @@ static my_bool acl_load(THD *thd, TABLE_ char *tmpstr= get_field(&global_acl_memory, table->field[MYSQL_USER_FIELD_PASSWORD_EXPIRED]); if (tmpstr && (*tmpstr == 'Y' || *tmpstr == 'y')) - user.password_expired= true; + user.set_password_expired(); } } // end if (table->s->fields >= 31) else { - user.ssl_type=SSL_TYPE_NONE; + user.set_ssl_authentication_type(SSL_TYPE_NONE); #ifndef TO_BE_REMOVED + ulong global_acl_tbr= user.global_acl(); if (table->s->fields <= 13) { // Without grant - if (user.access & CREATE_ACL) - user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + if (global_acl_tbr & CREATE_ACL) + global_acl_tbr|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; } /* Convert old privileges */ - user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; - if (user.access & FILE_ACL) - user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; - if (user.access & PROCESS_ACL) - user.access|= SUPER_ACL | EXECUTE_ACL; + global_acl_tbr|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; + if (global_acl_tbr & FILE_ACL) + global_acl_tbr|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + if (global_acl_tbr & PROCESS_ACL) + global_acl_tbr|= SUPER_ACL | EXECUTE_ACL; + + user.set_global_acl(global_acl_tbr); #endif } - (void) push_dynamic(&acl_users,(uchar*) &user); - if (user.host.check_allow_all_hosts()) + (void) push_dynamic(&sql_users,(uchar*) &user); + if (user.host()->check_allow_all_hosts()) allow_all_hosts=1; // Anyone can connect } } // END while reading records from the mysql.user table - my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((uchar*) dynamic_element(&sql_users,0,Sql_user_implementation*),sql_users.elements, + sizeof(Sql_user_implementation),(qsort_cmp) sql_user_compare); end_read_record(&read_record_info); - freeze_size(&acl_users); + freeze_size(&sql_users); /* Legacy password integrity checks ----------------------------------------*/ { No bundle (reason: useless for push emails).