in sql/auth/sql_auth_cache.cc [1651:2207]
static bool acl_load(THD *thd, TABLE_LIST *tables)
{
TABLE *table;
READ_RECORD read_record_info;
bool return_val= TRUE;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
sql_mode_t old_sql_mode= thd->variables.sql_mode;
bool password_expired= false;
bool super_users_with_empty_plugin= false;
Acl_load_user_table_schema_factory user_table_schema_factory;
Acl_load_user_table_schema *table_schema = NULL;
bool is_old_db_layout= false;
DBUG_ENTER("acl_load");
DBUG_EXECUTE_IF("wl_9262_set_max_length_hostname",
thd->security_context()->assign_priv_host(
"oh_my_gosh_this_is_a_long_"
"hostname_look_at_it_it_has_60"
"_char", 60);
thd->security_context()->assign_host(
"oh_my_gosh_this_is_a_long_"
"hostname_look_at_it_it_has_60"
"_char", 60);
thd->security_context()->set_host_or_ip_ptr();
);
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
grant_version++; /* Privileges updated */
clear_and_init_db_cache(); // Clear locked hostname cache
init_sql_alloc(key_memory_acl_mem,
&global_acl_memory, ACL_ALLOC_BLOCK_SIZE, 0);
/*
Prepare reading from the mysql.user table
*/
if (init_read_record(&read_record_info, thd, table=tables[0].table,
NULL, 1, 1, FALSE))
goto end;
table->use_all_columns();
acl_users->clear();
/*
We need to check whether we are working with old database layout. This
might be the case for instance when we are running mysql_upgrade.
*/
table_schema= user_table_schema_factory.get_user_table_schema(table);
is_old_db_layout= user_table_schema_factory.is_old_user_table_schema(table);
allow_all_hosts=0;
int read_rec_errcode;
while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
{
password_expired= false;
/* Reading record from mysql.user */
ACL_USER user;
memset(&user, 0, sizeof(user));
/*
All accounts can authenticate per default. This will change when
we add a new field to the user table.
Currently this flag is only set to false when authentication is attempted
using an unknown user name.
*/
user.can_authenticate= true;
/*
Account is unlocked by default.
*/
user.account_locked= false;
/*
The authorization id isn't a part of the role-graph per default.
This is true even if CREATE ROLE is used.
*/
user.is_role= false;
user.host.update_hostname(get_field(&global_acl_memory,
table->field[table_schema->host_idx()]));
user.user= get_field(&global_acl_memory,
table->field[table_schema->user_idx()]);
if (check_no_resolve && hostname_requires_resolving(user.host.get_host()))
{
LogErr(WARNING_LEVEL, ER_AUTHCACHE_USER_SKIPPED_NEEDS_RESOLVE,
user.user ? user.user : "",
user.host.get_host() ? user.host.get_host() : "");
}
/* Read password from authentication_string field */
if (table->s->fields > table_schema->authentication_string_idx())
user.auth_string.str=
get_field(&global_acl_memory,
table->field[table_schema->authentication_string_idx()]);
else
{
LogErr(ERROR_LEVEL, ER_AUTHCACHE_USER_TABLE_DODGY);
end_read_record(&read_record_info);
goto end;
}
if(user.auth_string.str)
user.auth_string.length= strlen(user.auth_string.str);
else
user.auth_string= EMPTY_STR;
{
uint next_field;
user.access= get_access(table, table_schema->select_priv_idx(),
&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 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;
/*
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 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 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;
user.sort= get_sort(2,user.host.get_host(),user.user);
/* Starting from 4.0.2 we have more fields */
if (table->s->fields >= 31)
{
char *ssl_type=
get_field(thd->mem_root, table->field[table_schema->ssl_type_idx()]);
if (!ssl_type)
user.ssl_type=SSL_TYPE_NONE;
else if (!strcmp(ssl_type, "ANY"))
user.ssl_type=SSL_TYPE_ANY;
else if (!strcmp(ssl_type, "X509"))
user.ssl_type=SSL_TYPE_X509;
else /* !strcmp(ssl_type, "SPECIFIED") */
user.ssl_type=SSL_TYPE_SPECIFIED;
user.ssl_cipher=
get_field(&global_acl_memory,
table->field[table_schema->ssl_cipher_idx()]);
user.x509_issuer=
get_field(&global_acl_memory,
table->field[table_schema->x509_issuer_idx()]);
user.x509_subject=
get_field(&global_acl_memory,
table->field[table_schema->x509_subject_idx()]);
char *ptr= get_field(thd->mem_root,
table->field[table_schema->max_questions_idx()]);
user.user_resource.questions=ptr ? atoi(ptr) : 0;
ptr= get_field(thd->mem_root,
table->field[table_schema->max_updates_idx()]);
user.user_resource.updates=ptr ? atoi(ptr) : 0;
ptr= get_field(thd->mem_root,
table->field[table_schema->max_connections_idx()]);
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)
mqh_used=1;
if (table->s->fields > table_schema->max_user_connections_idx())
{
/* Starting from 5.0.3 we have max_user_connections field */
ptr= get_field(thd->mem_root,
table->field[table_schema->max_user_connections_idx()]);
user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
}
if (table->s->fields >= 41)
{
/* We may have plugin & auth_String fields */
const char *tmpstr=
get_field(&global_acl_memory,
table->field[table_schema->plugin_idx()]);
/* In case we are working with 5.6 db layout we need to make server
aware of Password field and that the plugin column can be null.
In case when plugin column is null we use native password plugin
if we can.
*/
if (is_old_db_layout && (tmpstr == NULL || strlen(tmpstr) == 0 ||
my_strcasecmp(system_charset_info, tmpstr,
native_password_plugin_name.str) == 0))
{
char *password= get_field(&global_acl_memory,
table->field[table_schema->password_idx()]);
//We only support native hash, we do not support pre 4.1 hashes
plugin_ref native_plugin= NULL;
native_plugin= my_plugin_lock_by_name(0,
native_password_plugin_name,
MYSQL_AUTHENTICATION_PLUGIN);
if (native_plugin)
{
uint password_len= password ? strlen(password) : 0;
st_mysql_auth *auth=
(st_mysql_auth *) plugin_decl(native_plugin)->info;
if (auth->validate_authentication_string(password,
password_len) == 0)
{
//auth_string takes precedence over password
if (user.auth_string.length == 0)
{
user.auth_string.str= password;
user.auth_string.length= password_len;
}
if (tmpstr == NULL || strlen(tmpstr) == 0)
tmpstr= native_password_plugin_name.str;
}
else
{
if ((user.access & SUPER_ACL) && !super_users_with_empty_plugin
&& (tmpstr == NULL || strlen(tmpstr) == 0))
super_users_with_empty_plugin= true;
LogErr(WARNING_LEVEL,
ER_AUTHCACHE_USER_IGNORED_DEPRECATED_PASSWORD,
user.user ? user.user : "",
user.host.get_host() ? user.host.get_host() : "");
plugin_unlock(0, native_plugin);
continue;
}
plugin_unlock(0, native_plugin);
}
}
/*
Check if the plugin string is blank or null.
If it is, the user will be skipped.
*/
if(tmpstr == NULL || strlen(tmpstr) == 0)
{
if ((user.access & SUPER_ACL) && !super_users_with_empty_plugin)
super_users_with_empty_plugin= true;
LogErr(WARNING_LEVEL, ER_AUTHCACHE_USER_IGNORED_NEEDS_PLUGIN,
user.user ? user.user : "",
user.host.get_host() ? user.host.get_host() : "");
continue;
}
/*
By comparing the plugin with the built in plugins it is possible
to optimize the string allocation and comparision.
*/
if (my_strcasecmp(system_charset_info, tmpstr,
native_password_plugin_name.str) == 0)
user.plugin= native_password_plugin_name;
#if defined(HAVE_OPENSSL)
else
if (my_strcasecmp(system_charset_info, tmpstr,
sha256_password_plugin_name.str) == 0)
user.plugin= sha256_password_plugin_name;
#endif
else
{
user.plugin.str= tmpstr;
user.plugin.length= strlen(tmpstr);
}
}
/* Validate the hash string. */
plugin_ref plugin= NULL;
plugin= my_plugin_lock_by_name(0, user.plugin,
MYSQL_AUTHENTICATION_PLUGIN);
if (plugin)
{
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
if (auth->validate_authentication_string(user.auth_string.str,
user.auth_string.length))
{
LogErr(WARNING_LEVEL, ER_AUTHCACHE_USER_IGNORED_INVALID_PASSWORD,
user.user ? user.user : "",
user.host.get_host() ? user.host.get_host() : "");
plugin_unlock(0, plugin);
continue;
}
plugin_unlock(0, plugin);
}
if (table->s->fields > table_schema->password_expired_idx())
{
char *tmpstr= get_field(&global_acl_memory,
table->field[table_schema->password_expired_idx()]);
if (tmpstr && (*tmpstr == 'Y' || *tmpstr == 'y'))
{
user.password_expired= true;
if (!auth_plugin_supports_expiration(user.plugin.str))
{
LogErr(WARNING_LEVEL,
ER_AUTHCACHE_EXPIRED_PASSWORD_UNSUPPORTED,
user.user ? user.user : "",
user.host.get_host() ? user.host.get_host() : "");
continue;
}
password_expired= true;
}
}
if (table->s->fields > table_schema->account_locked_idx())
{
char *locked = get_field(&global_acl_memory,
table->field[table_schema->account_locked_idx()]);
if (locked && (*locked == 'Y' || *locked == 'y'))
{
user.account_locked= true;
}
}
if (table->s->fields > table_schema->drop_role_priv_idx())
{
char *priv=
get_field(&global_acl_memory,
table->field[table_schema->create_role_priv_idx()]);
if (priv && (*priv == 'Y' || *priv == 'y'))
{
user.access |= CREATE_ROLE_ACL;
}
priv= get_field(&global_acl_memory,
table->field[table_schema->drop_role_priv_idx()]);
if (priv && (*priv == 'Y' || *priv == 'y'))
{
user.access |= DROP_ROLE_ACL;
}
}
/*
Initalize the values of timestamp and expire after day
to error and true respectively.
*/
user.password_last_changed.time_type= MYSQL_TIMESTAMP_ERROR;
user.use_default_password_lifetime= true;
user.password_lifetime= 0;
if (table->s->fields > table_schema->password_last_changed_idx())
{
if (!table->field[table_schema->password_last_changed_idx()]->is_null())
{
char *password_last_changed= get_field(&global_acl_memory,
table->field[table_schema->password_last_changed_idx()]);
if (password_last_changed &&
memcmp(password_last_changed, INVALID_DATE, sizeof(INVALID_DATE)))
{
String str(password_last_changed, &my_charset_bin);
str_to_time_with_warn(&str,&(user.password_last_changed));
}
}
}
if (table->s->fields > table_schema->password_lifetime_idx())
{
if (!table->
field[table_schema->password_lifetime_idx()]->is_null())
{
char *ptr= get_field(&global_acl_memory,
table->field[table_schema->password_lifetime_idx()]);
user.password_lifetime= ptr ? atoi(ptr) : 0;
user.use_default_password_lifetime= false;
}
}
} // end if (table->s->fields >= 31)
else
{
user.ssl_type=SSL_TYPE_NONE;
if (table->s->fields <= 13)
{ // Without grant
if (user.access & CREATE_ACL)
user.access|=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;
}
set_user_salt(&user);
user.password_expired= password_expired;
acl_users->push_back(user);
if (user.host.check_allow_all_hosts())
allow_all_hosts=1; // Anyone can connect
}
} // END while reading records from the mysql.user table
end_read_record(&read_record_info);
if (read_rec_errcode > 0)
goto end;
std::sort(acl_users->begin(), acl_users->end(), ACL_compare());
acl_users->shrink_to_fit();
if (super_users_with_empty_plugin)
{
LogErr(WARNING_LEVEL, ER_NO_SUPER_WITHOUT_USER_PLUGIN);
}
/*
Prepare reading from the mysql.db table
*/
if (init_read_record(&read_record_info, thd, table=tables[1].table,
NULL, 1, 1, FALSE))
goto end;
table->use_all_columns();
acl_dbs->clear();
while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
{
/* Reading record in mysql.db */
ACL_DB db;
db.host.update_hostname(get_field(&global_acl_memory,
table->field[MYSQL_DB_FIELD_HOST]));
db.db=get_field(&global_acl_memory, table->field[MYSQL_DB_FIELD_DB]);
if (!db.db)
{
LogErr(WARNING_LEVEL, ER_AUTHCACHE_DB_IGNORED_EMPTY_NAME);
continue;
}
db.user=get_field(&global_acl_memory, table->field[MYSQL_DB_FIELD_USER]);
if (check_no_resolve && hostname_requires_resolving(db.host.get_host()))
{
LogErr(WARNING_LEVEL, ER_AUTHCACHE_DB_SKIPPED_NEEDS_RESOLVE,
db.db,
db.user ? db.user : "",
db.host.get_host() ? db.host.get_host() : "");
}
db.access=get_access(table,3,0);
db.access=fix_rights_for_db(db.access);
if (lower_case_table_names)
{
/*
convert db to lower case and give a warning if the db wasn't
already in lower case
*/
(void)my_stpcpy(tmp_name, db.db);
my_casedn_str(files_charset_info, db.db);
if (strcmp(db.db, tmp_name) != 0)
{
LogErr(WARNING_LEVEL,
ER_AUTHCACHE_DB_ENTRY_LOWERCASED_REVOKE_WILL_FAIL,
db.db,
db.user ? db.user : "",
db.host.get_host() ? db.host.get_host() : "");
}
}
db.sort=get_sort(3,db.host.get_host(),db.db,db.user);
if (table->s->fields <= 9)
{ // Without grant
if (db.access & CREATE_ACL)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
acl_dbs->push_back(db);
} // END reading records from mysql.db tables
end_read_record(&read_record_info);
if (read_rec_errcode > 0)
goto end;
std::sort(acl_dbs->begin(), acl_dbs->end(), ACL_compare());
acl_dbs->shrink_to_fit();
/* Prepare to read records from the mysql.proxies_priv table */
acl_proxy_users->clear();
if (tables[2].table)
{
if (init_read_record(&read_record_info, thd, table= tables[2].table,
NULL, 1, 1, FALSE))
goto end;
table->use_all_columns();
while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
{
/* Reading record in mysql.proxies_priv */
ACL_PROXY_USER proxy;
proxy.init(table, &global_acl_memory);
if (proxy.check_validity(check_no_resolve))
continue;
if (acl_proxy_users->push_back(proxy))
{
end_read_record(&read_record_info);
goto end;
}
} // END reading records from the mysql.proxies_priv table
end_read_record(&read_record_info);
if (read_rec_errcode > 0)
goto end;
std::sort(acl_proxy_users->begin(), acl_proxy_users->end(), ACL_compare());
}
else
{
LogErr(ERROR_LEVEL, ER_AUTHCACHE_TABLE_PROXIES_PRIV_MISSING);
}
acl_proxy_users->shrink_to_fit();
validate_user_plugin_records();
init_check_host();
/* Load dynamic privileges */
if (tables[3].table)
{
if (populate_dynamic_privilege_caches(thd, &tables[3]))
{
return_val= TRUE;
goto end;
}
}
else
{
sql_print_error("Missing system table mysql.global_grants; "
"please run mysql_upgrade to create it");
}
initialized=1;
return_val= FALSE;
end:
thd->variables.sql_mode= old_sql_mode;
if (table_schema)
delete table_schema;
DBUG_EXECUTE_IF("induce_acl_load_failure",
return_val= TRUE;);
DBUG_RETURN(return_val);
}