00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* 00019 The privileges are saved in the following tables: 00020 mysql/user ; super user who are allowed to do almost anything 00021 mysql/host ; host privileges. This is used if host is empty in mysql/db. 00022 mysql/db ; database privileges / user 00023 00024 data in tables is sorted according to how many not-wild-cards there is 00025 in the relevant fields. Empty strings comes last. 00026 */ 00027 00028 #include "mysql_priv.h" 00029 #include "hash_filo.h" 00030 #include <m_ctype.h> 00031 #include <stdarg.h> 00032 #include "sp_head.h" 00033 #include "sp.h" 00034 00035 time_t mysql_db_table_last_check= 0L; 00036 00037 TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = { 00038 { 00039 { C_STRING_WITH_LEN("Host") }, 00040 { C_STRING_WITH_LEN("char(60)") }, 00041 {NULL, 0} 00042 }, 00043 { 00044 { C_STRING_WITH_LEN("Db") }, 00045 { C_STRING_WITH_LEN("char(64)") }, 00046 {NULL, 0} 00047 }, 00048 { 00049 { C_STRING_WITH_LEN("User") }, 00050 { C_STRING_WITH_LEN("char(16)") }, 00051 {NULL, 0} 00052 }, 00053 { 00054 { C_STRING_WITH_LEN("Select_priv") }, 00055 { C_STRING_WITH_LEN("enum('N','Y')") }, 00056 { C_STRING_WITH_LEN("utf8") } 00057 }, 00058 { 00059 { C_STRING_WITH_LEN("Insert_priv") }, 00060 { C_STRING_WITH_LEN("enum('N','Y')") }, 00061 { C_STRING_WITH_LEN("utf8") } 00062 }, 00063 { 00064 { C_STRING_WITH_LEN("Update_priv") }, 00065 { C_STRING_WITH_LEN("enum('N','Y')") }, 00066 { C_STRING_WITH_LEN("utf8") } 00067 }, 00068 { 00069 { C_STRING_WITH_LEN("Delete_priv") }, 00070 { C_STRING_WITH_LEN("enum('N','Y')") }, 00071 { C_STRING_WITH_LEN("utf8") } 00072 }, 00073 { 00074 { C_STRING_WITH_LEN("Create_priv") }, 00075 { C_STRING_WITH_LEN("enum('N','Y')") }, 00076 { C_STRING_WITH_LEN("utf8") } 00077 }, 00078 { 00079 { C_STRING_WITH_LEN("Drop_priv") }, 00080 { C_STRING_WITH_LEN("enum('N','Y')") }, 00081 { C_STRING_WITH_LEN("utf8") } 00082 }, 00083 { 00084 { C_STRING_WITH_LEN("Grant_priv") }, 00085 { C_STRING_WITH_LEN("enum('N','Y')") }, 00086 { C_STRING_WITH_LEN("utf8") } 00087 }, 00088 { 00089 { C_STRING_WITH_LEN("References_priv") }, 00090 { C_STRING_WITH_LEN("enum('N','Y')") }, 00091 { C_STRING_WITH_LEN("utf8") } 00092 }, 00093 { 00094 { C_STRING_WITH_LEN("Index_priv") }, 00095 { C_STRING_WITH_LEN("enum('N','Y')") }, 00096 { C_STRING_WITH_LEN("utf8") } 00097 }, 00098 { 00099 { C_STRING_WITH_LEN("Alter_priv") }, 00100 { C_STRING_WITH_LEN("enum('N','Y')") }, 00101 { C_STRING_WITH_LEN("utf8") } 00102 }, 00103 { 00104 { C_STRING_WITH_LEN("Create_tmp_table_priv") }, 00105 { C_STRING_WITH_LEN("enum('N','Y')") }, 00106 { C_STRING_WITH_LEN("utf8") } 00107 }, 00108 { 00109 { C_STRING_WITH_LEN("Lock_tables_priv") }, 00110 { C_STRING_WITH_LEN("enum('N','Y')") }, 00111 { C_STRING_WITH_LEN("utf8") } 00112 }, 00113 { 00114 { C_STRING_WITH_LEN("Create_view_priv") }, 00115 { C_STRING_WITH_LEN("enum('N','Y')") }, 00116 { C_STRING_WITH_LEN("utf8") } 00117 }, 00118 { 00119 { C_STRING_WITH_LEN("Show_view_priv") }, 00120 { C_STRING_WITH_LEN("enum('N','Y')") }, 00121 { C_STRING_WITH_LEN("utf8") } 00122 }, 00123 { 00124 { C_STRING_WITH_LEN("Create_routine_priv") }, 00125 { C_STRING_WITH_LEN("enum('N','Y')") }, 00126 { C_STRING_WITH_LEN("utf8") } 00127 }, 00128 { 00129 { C_STRING_WITH_LEN("Alter_routine_priv") }, 00130 { C_STRING_WITH_LEN("enum('N','Y')") }, 00131 { C_STRING_WITH_LEN("utf8") } 00132 }, 00133 { 00134 { C_STRING_WITH_LEN("Execute_priv") }, 00135 { C_STRING_WITH_LEN("enum('N','Y')") }, 00136 { C_STRING_WITH_LEN("utf8") } 00137 }, 00138 { 00139 { C_STRING_WITH_LEN("Event_priv") }, 00140 { C_STRING_WITH_LEN("enum('N','Y')") }, 00141 { C_STRING_WITH_LEN("utf8") } 00142 }, 00143 { 00144 { C_STRING_WITH_LEN("Trigger_priv") }, 00145 { C_STRING_WITH_LEN("enum('N','Y')") }, 00146 { C_STRING_WITH_LEN("utf8") } 00147 } 00148 }; 00149 00150 00151 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00152 00153 #define FIRST_NON_YN_FIELD 26 00154 00155 class acl_entry :public hash_filo_element 00156 { 00157 public: 00158 ulong access; 00159 uint16 length; 00160 char key[1]; // Key will be stored here 00161 }; 00162 00163 00164 static byte* acl_entry_get_key(acl_entry *entry,uint *length, 00165 my_bool not_used __attribute__((unused))) 00166 { 00167 *length=(uint) entry->length; 00168 return (byte*) entry->key; 00169 } 00170 00171 #define IP_ADDR_STRLEN (3+1+3+1+3+1+3) 00172 #define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1) 00173 00174 static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs; 00175 static MEM_ROOT mem, memex; 00176 static bool initialized=0; 00177 static bool allow_all_hosts=1; 00178 static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash; 00179 static DYNAMIC_ARRAY acl_wild_hosts; 00180 static hash_filo *acl_cache; 00181 static uint grant_version=0; /* Version of priv tables. incremented by acl_load */ 00182 static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); 00183 static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); 00184 static ulong get_sort(uint count,...); 00185 static void init_check_host(void); 00186 static void rebuild_check_host(void); 00187 static ACL_USER *find_acl_user(const char *host, const char *user, 00188 my_bool exact); 00189 static bool update_user_table(THD *thd, TABLE *table, 00190 const char *host, const char *user, 00191 const char *new_password, uint new_password_len); 00192 static void update_hostname(acl_host_and_ip *host, const char *hostname); 00193 static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, 00194 const char *ip); 00195 static my_bool acl_load(THD *thd, TABLE_LIST *tables); 00196 static my_bool grant_load(TABLE_LIST *tables); 00197 00198 /* 00199 Convert scrambled password to binary form, according to scramble type, 00200 Binary form is stored in user.salt. 00201 */ 00202 00203 static 00204 void 00205 set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) 00206 { 00207 if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) 00208 { 00209 get_salt_from_password(acl_user->salt, password); 00210 acl_user->salt_len= SCRAMBLE_LENGTH; 00211 } 00212 else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) 00213 { 00214 get_salt_from_password_323((ulong *) acl_user->salt, password); 00215 acl_user->salt_len= SCRAMBLE_LENGTH_323; 00216 } 00217 else 00218 acl_user->salt_len= 0; 00219 } 00220 00221 /* 00222 This after_update function is used when user.password is less than 00223 SCRAMBLE_LENGTH bytes. 00224 */ 00225 00226 static void restrict_update_of_old_passwords_var(THD *thd, 00227 enum_var_type var_type) 00228 { 00229 if (var_type == OPT_GLOBAL) 00230 { 00231 pthread_mutex_lock(&LOCK_global_system_variables); 00232 global_system_variables.old_passwords= 1; 00233 pthread_mutex_unlock(&LOCK_global_system_variables); 00234 } 00235 else 00236 thd->variables.old_passwords= 1; 00237 } 00238 00239 00240 /* 00241 Initialize structures responsible for user/db-level privilege checking and 00242 load privilege information for them from tables in the 'mysql' database. 00243 00244 SYNOPSIS 00245 acl_init() 00246 dont_read_acl_tables TRUE if we want to skip loading data from 00247 privilege tables and disable privilege checking. 00248 00249 NOTES 00250 This function is mostly responsible for preparatory steps, main work 00251 on initialization and grants loading is done in acl_reload(). 00252 00253 RETURN VALUES 00254 0 ok 00255 1 Could not initialize grant's 00256 */ 00257 00258 my_bool acl_init(bool dont_read_acl_tables) 00259 { 00260 THD *thd; 00261 my_bool return_val; 00262 DBUG_ENTER("acl_init"); 00263 00264 acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, 00265 (hash_get_key) acl_entry_get_key, 00266 (hash_free_key) free, 00267 lower_case_file_system ? 00268 system_charset_info : &my_charset_bin); 00269 if (dont_read_acl_tables) 00270 { 00271 DBUG_RETURN(0); /* purecov: tested */ 00272 } 00273 00274 /* 00275 To be able to run this from boot, we allocate a temporary THD 00276 */ 00277 if (!(thd=new THD)) 00278 DBUG_RETURN(1); /* purecov: inspected */ 00279 thd->thread_stack= (char*) &thd; 00280 thd->store_globals(); 00281 /* 00282 It is safe to call acl_reload() since acl_* arrays and hashes which 00283 will be freed there are global static objects and thus are initialized 00284 by zeros at startup. 00285 */ 00286 return_val= acl_reload(thd); 00287 delete thd; 00288 /* Remember that we don't have a THD */ 00289 my_pthread_setspecific_ptr(THR_THD, 0); 00290 DBUG_RETURN(return_val); 00291 } 00292 00293 00294 /* 00295 Initialize structures responsible for user/db-level privilege checking 00296 and load information about grants from open privilege tables. 00297 00298 SYNOPSIS 00299 acl_load() 00300 thd Current thread 00301 tables List containing open "mysql.host", "mysql.user" and 00302 "mysql.db" tables. 00303 00304 RETURN VALUES 00305 FALSE Success 00306 TRUE Error 00307 */ 00308 00309 static my_bool acl_load(THD *thd, TABLE_LIST *tables) 00310 { 00311 TABLE *table; 00312 READ_RECORD read_record_info; 00313 my_bool return_val= 1; 00314 bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; 00315 char tmp_name[NAME_LEN+1]; 00316 int password_length; 00317 DBUG_ENTER("acl_load"); 00318 00319 grant_version++; /* Privileges updated */ 00320 mysql_proc_table_exists= 1; // Assume mysql.proc exists 00321 00322 acl_cache->clear(1); // Clear locked hostname cache 00323 00324 init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); 00325 init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); 00326 table->use_all_columns(); 00327 VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); 00328 while (!(read_record_info.read_record(&read_record_info))) 00329 { 00330 ACL_HOST host; 00331 update_hostname(&host.host,get_field(&mem, table->field[0])); 00332 host.db= get_field(&mem, table->field[1]); 00333 if (lower_case_table_names && host.db) 00334 { 00335 /* 00336 convert db to lower case and give a warning if the db wasn't 00337 already in lower case 00338 */ 00339 (void) strmov(tmp_name, host.db); 00340 my_casedn_str(files_charset_info, host.db); 00341 if (strcmp(host.db, tmp_name) != 0) 00342 sql_print_warning("'host' entry '%s|%s' had database in mixed " 00343 "case that has been forced to lowercase because " 00344 "lower_case_table_names is set. It will not be " 00345 "possible to remove this privilege using REVOKE.", 00346 host.host.hostname ? host.host.hostname : "", 00347 host.db ? host.db : ""); 00348 } 00349 host.access= get_access(table,2); 00350 host.access= fix_rights_for_db(host.access); 00351 host.sort= get_sort(2,host.host.hostname,host.db); 00352 if (check_no_resolve && hostname_requires_resolving(host.host.hostname)) 00353 { 00354 sql_print_warning("'host' entry '%s|%s' " 00355 "ignored in --skip-name-resolve mode.", 00356 host.host.hostname ? host.host.hostname : "", 00357 host.db ? host.db : ""); 00358 continue; 00359 } 00360 #ifndef TO_BE_REMOVED 00361 if (table->s->fields == 8) 00362 { // Without grant 00363 if (host.access & CREATE_ACL) 00364 host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL; 00365 } 00366 #endif 00367 VOID(push_dynamic(&acl_hosts,(gptr) &host)); 00368 } 00369 qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, 00370 sizeof(ACL_HOST),(qsort_cmp) acl_compare); 00371 end_read_record(&read_record_info); 00372 freeze_size(&acl_hosts); 00373 00374 init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); 00375 table->use_all_columns(); 00376 VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); 00377 password_length= table->field[2]->field_length / 00378 table->field[2]->charset()->mbmaxlen; 00379 if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) 00380 { 00381 sql_print_error("Fatal error: mysql.user table is damaged or in " 00382 "unsupported 3.20 format."); 00383 goto end; 00384 } 00385 00386 DBUG_PRINT("info",("user table fields: %d, password length: %d", 00387 table->s->fields, password_length)); 00388 00389 pthread_mutex_lock(&LOCK_global_system_variables); 00390 if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) 00391 { 00392 if (opt_secure_auth) 00393 { 00394 pthread_mutex_unlock(&LOCK_global_system_variables); 00395 sql_print_error("Fatal error: mysql.user table is in old format, " 00396 "but server started with --secure-auth option."); 00397 goto end; 00398 } 00399 sys_old_passwords.after_update= restrict_update_of_old_passwords_var; 00400 if (global_system_variables.old_passwords) 00401 pthread_mutex_unlock(&LOCK_global_system_variables); 00402 else 00403 { 00404 global_system_variables.old_passwords= 1; 00405 pthread_mutex_unlock(&LOCK_global_system_variables); 00406 sql_print_warning("mysql.user table is not updated to new password format; " 00407 "Disabling new password usage until " 00408 "mysql_fix_privilege_tables is run"); 00409 } 00410 thd->variables.old_passwords= 1; 00411 } 00412 else 00413 { 00414 sys_old_passwords.after_update= 0; 00415 pthread_mutex_unlock(&LOCK_global_system_variables); 00416 } 00417 00418 allow_all_hosts=0; 00419 while (!(read_record_info.read_record(&read_record_info))) 00420 { 00421 ACL_USER user; 00422 update_hostname(&user.host, get_field(&mem, table->field[0])); 00423 user.user= get_field(&mem, table->field[1]); 00424 if (check_no_resolve && hostname_requires_resolving(user.host.hostname)) 00425 { 00426 sql_print_warning("'user' entry '%s@%s' " 00427 "ignored in --skip-name-resolve mode.", 00428 user.user ? user.user : "", 00429 user.host.hostname ? user.host.hostname : ""); 00430 continue; 00431 } 00432 00433 const char *password= get_field(&mem, table->field[2]); 00434 uint password_len= password ? strlen(password) : 0; 00435 set_user_salt(&user, password, password_len); 00436 if (user.salt_len == 0 && password_len != 0) 00437 { 00438 switch (password_len) { 00439 case 45: /* 4.1: to be removed */ 00440 sql_print_warning("Found 4.1 style password for user '%s@%s'. " 00441 "Ignoring user. " 00442 "You should change password for this user.", 00443 user.user ? user.user : "", 00444 user.host.hostname ? user.host.hostname : ""); 00445 break; 00446 default: 00447 sql_print_warning("Found invalid password for user: '%s@%s'; " 00448 "Ignoring user", user.user ? user.user : "", 00449 user.host.hostname ? user.host.hostname : ""); 00450 break; 00451 } 00452 } 00453 else // password is correct 00454 { 00455 uint next_field; 00456 user.access= get_access(table,3,&next_field) & GLOBAL_ACLS; 00457 /* 00458 if it is pre 5.0.1 privilege table then map CREATE privilege on 00459 CREATE VIEW & SHOW VIEW privileges 00460 */ 00461 if (table->s->fields <= 31 && (user.access & CREATE_ACL)) 00462 user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); 00463 00464 /* 00465 if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on 00466 CREATE PROCEDURE & ALTER PROCEDURE privileges 00467 */ 00468 if (table->s->fields <= 33 && (user.access & CREATE_ACL)) 00469 user.access|= CREATE_PROC_ACL; 00470 if (table->s->fields <= 33 && (user.access & ALTER_ACL)) 00471 user.access|= ALTER_PROC_ACL; 00472 00473 /* 00474 pre 5.0.3 did not have CREATE_USER_ACL 00475 */ 00476 if (table->s->fields <= 36 && (user.access & GRANT_ACL)) 00477 user.access|= CREATE_USER_ACL; 00478 00479 00480 /* 00481 if it is pre 5.1.6 privilege table then map CREATE privilege on 00482 CREATE|ALTER|DROP|EXECUTE EVENT 00483 */ 00484 if (table->s->fields <= 37 && (user.access & SUPER_ACL)) 00485 user.access|= EVENT_ACL; 00486 00487 /* 00488 if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE. 00489 */ 00490 if (table->s->fields <= 38 && (user.access & SUPER_ACL)) 00491 user.access|= TRIGGER_ACL; 00492 00493 user.sort= get_sort(2,user.host.hostname,user.user); 00494 user.hostname_length= (user.host.hostname ? 00495 (uint) strlen(user.host.hostname) : 0); 00496 00497 /* Starting from 4.0.2 we have more fields */ 00498 if (table->s->fields >= 31) 00499 { 00500 char *ssl_type=get_field(&mem, table->field[next_field++]); 00501 if (!ssl_type) 00502 user.ssl_type=SSL_TYPE_NONE; 00503 else if (!strcmp(ssl_type, "ANY")) 00504 user.ssl_type=SSL_TYPE_ANY; 00505 else if (!strcmp(ssl_type, "X509")) 00506 user.ssl_type=SSL_TYPE_X509; 00507 else /* !strcmp(ssl_type, "SPECIFIED") */ 00508 user.ssl_type=SSL_TYPE_SPECIFIED; 00509 00510 user.ssl_cipher= get_field(&mem, table->field[next_field++]); 00511 user.x509_issuer= get_field(&mem, table->field[next_field++]); 00512 user.x509_subject= get_field(&mem, table->field[next_field++]); 00513 00514 char *ptr = get_field(&mem, table->field[next_field++]); 00515 user.user_resource.questions=ptr ? atoi(ptr) : 0; 00516 ptr = get_field(&mem, table->field[next_field++]); 00517 user.user_resource.updates=ptr ? atoi(ptr) : 0; 00518 ptr = get_field(&mem, table->field[next_field++]); 00519 user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0; 00520 if (user.user_resource.questions || user.user_resource.updates || 00521 user.user_resource.conn_per_hour) 00522 mqh_used=1; 00523 00524 if (table->s->fields >= 36) 00525 { 00526 /* Starting from 5.0.3 we have max_user_connections field */ 00527 ptr= get_field(&mem, table->field[next_field++]); 00528 user.user_resource.user_conn= ptr ? atoi(ptr) : 0; 00529 } 00530 else 00531 user.user_resource.user_conn= 0; 00532 } 00533 else 00534 { 00535 user.ssl_type=SSL_TYPE_NONE; 00536 bzero((char *)&(user.user_resource),sizeof(user.user_resource)); 00537 #ifndef TO_BE_REMOVED 00538 if (table->s->fields <= 13) 00539 { // Without grant 00540 if (user.access & CREATE_ACL) 00541 user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; 00542 } 00543 /* Convert old privileges */ 00544 user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; 00545 if (user.access & FILE_ACL) 00546 user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; 00547 if (user.access & PROCESS_ACL) 00548 user.access|= SUPER_ACL | EXECUTE_ACL; 00549 #endif 00550 } 00551 VOID(push_dynamic(&acl_users,(gptr) &user)); 00552 if (!user.host.hostname || 00553 (user.host.hostname[0] == wild_many && !user.host.hostname[1])) 00554 allow_all_hosts=1; // Anyone can connect 00555 } 00556 } 00557 qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, 00558 sizeof(ACL_USER),(qsort_cmp) acl_compare); 00559 end_read_record(&read_record_info); 00560 freeze_size(&acl_users); 00561 00562 init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0); 00563 table->use_all_columns(); 00564 VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100)); 00565 while (!(read_record_info.read_record(&read_record_info))) 00566 { 00567 ACL_DB db; 00568 update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST])); 00569 db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]); 00570 if (!db.db) 00571 { 00572 sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped"); 00573 continue; 00574 } 00575 db.user=get_field(&mem, table->field[MYSQL_DB_FIELD_USER]); 00576 if (check_no_resolve && hostname_requires_resolving(db.host.hostname)) 00577 { 00578 sql_print_warning("'db' entry '%s %s@%s' " 00579 "ignored in --skip-name-resolve mode.", 00580 db.db, 00581 db.user ? db.user : "", 00582 db.host.hostname ? db.host.hostname : ""); 00583 continue; 00584 } 00585 db.access=get_access(table,3); 00586 db.access=fix_rights_for_db(db.access); 00587 if (lower_case_table_names) 00588 { 00589 /* 00590 convert db to lower case and give a warning if the db wasn't 00591 already in lower case 00592 */ 00593 (void)strmov(tmp_name, db.db); 00594 my_casedn_str(files_charset_info, db.db); 00595 if (strcmp(db.db, tmp_name) != 0) 00596 { 00597 sql_print_warning("'db' entry '%s %s@%s' had database in mixed " 00598 "case that has been forced to lowercase because " 00599 "lower_case_table_names is set. It will not be " 00600 "possible to remove this privilege using REVOKE.", 00601 db.db, 00602 db.user ? db.user : "", 00603 db.host.hostname ? db.host.hostname : ""); 00604 } 00605 } 00606 db.sort=get_sort(3,db.host.hostname,db.db,db.user); 00607 #ifndef TO_BE_REMOVED 00608 if (table->s->fields <= 9) 00609 { // Without grant 00610 if (db.access & CREATE_ACL) 00611 db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; 00612 } 00613 #endif 00614 VOID(push_dynamic(&acl_dbs,(gptr) &db)); 00615 } 00616 qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, 00617 sizeof(ACL_DB),(qsort_cmp) acl_compare); 00618 end_read_record(&read_record_info); 00619 freeze_size(&acl_dbs); 00620 init_check_host(); 00621 00622 initialized=1; 00623 return_val=0; 00624 00625 end: 00626 DBUG_RETURN(return_val); 00627 } 00628 00629 00630 void acl_free(bool end) 00631 { 00632 free_root(&mem,MYF(0)); 00633 delete_dynamic(&acl_hosts); 00634 delete_dynamic(&acl_users); 00635 delete_dynamic(&acl_dbs); 00636 delete_dynamic(&acl_wild_hosts); 00637 hash_free(&acl_check_hosts); 00638 if (!end) 00639 acl_cache->clear(1); /* purecov: inspected */ 00640 else 00641 { 00642 delete acl_cache; 00643 acl_cache=0; 00644 } 00645 } 00646 00647 00648 /* 00649 Forget current user/db-level privileges and read new privileges 00650 from the privilege tables. 00651 00652 SYNOPSIS 00653 acl_reload() 00654 thd Current thread 00655 00656 NOTE 00657 All tables of calling thread which were open and locked by LOCK TABLES 00658 statement will be unlocked and closed. 00659 This function is also used for initialization of structures responsible 00660 for user/db-level privilege checking. 00661 00662 RETURN VALUE 00663 FALSE Success 00664 TRUE Failure 00665 */ 00666 00667 my_bool acl_reload(THD *thd) 00668 { 00669 TABLE_LIST tables[3]; 00670 DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs; 00671 MEM_ROOT old_mem; 00672 bool old_initialized; 00673 my_bool return_val= 1; 00674 DBUG_ENTER("acl_reload"); 00675 00676 if (thd->locked_tables) 00677 { // Can't have locked tables here 00678 thd->lock=thd->locked_tables; 00679 thd->locked_tables=0; 00680 close_thread_tables(thd); 00681 } 00682 00683 /* 00684 To avoid deadlocks we should obtain table locks before 00685 obtaining acl_cache->lock mutex. 00686 */ 00687 bzero((char*) tables, sizeof(tables)); 00688 tables[0].alias= tables[0].table_name= (char*) "host"; 00689 tables[1].alias= tables[1].table_name= (char*) "user"; 00690 tables[2].alias= tables[2].table_name= (char*) "db"; 00691 tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; 00692 tables[0].next_local= tables[0].next_global= tables+1; 00693 tables[1].next_local= tables[1].next_global= tables+2; 00694 tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; 00695 00696 if (simple_open_n_lock_tables(thd, tables)) 00697 { 00698 sql_print_error("Fatal error: Can't open and lock privilege tables: %s", 00699 thd->net.last_error); 00700 goto end; 00701 } 00702 00703 if ((old_initialized=initialized)) 00704 VOID(pthread_mutex_lock(&acl_cache->lock)); 00705 00706 old_acl_hosts=acl_hosts; 00707 old_acl_users=acl_users; 00708 old_acl_dbs=acl_dbs; 00709 old_mem=mem; 00710 delete_dynamic(&acl_wild_hosts); 00711 hash_free(&acl_check_hosts); 00712 00713 if ((return_val= acl_load(thd, tables))) 00714 { // Error. Revert to old list 00715 DBUG_PRINT("error",("Reverting to old privileges")); 00716 acl_free(); /* purecov: inspected */ 00717 acl_hosts=old_acl_hosts; 00718 acl_users=old_acl_users; 00719 acl_dbs=old_acl_dbs; 00720 mem=old_mem; 00721 init_check_host(); 00722 } 00723 else 00724 { 00725 free_root(&old_mem,MYF(0)); 00726 delete_dynamic(&old_acl_hosts); 00727 delete_dynamic(&old_acl_users); 00728 delete_dynamic(&old_acl_dbs); 00729 } 00730 if (old_initialized) 00731 VOID(pthread_mutex_unlock(&acl_cache->lock)); 00732 end: 00733 close_thread_tables(thd); 00734 DBUG_RETURN(return_val); 00735 } 00736 00737 00738 /* 00739 Get all access bits from table after fieldnr 00740 00741 IMPLEMENTATION 00742 We know that the access privileges ends when there is no more fields 00743 or the field is not an enum with two elements. 00744 00745 SYNOPSIS 00746 get_access() 00747 form an open table to read privileges from. 00748 The record should be already read in table->record[0] 00749 fieldnr number of the first privilege (that is ENUM('N','Y') field 00750 next_field on return - number of the field next to the last ENUM 00751 (unless next_field == 0) 00752 00753 RETURN VALUE 00754 privilege mask 00755 */ 00756 00757 static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) 00758 { 00759 ulong access_bits=0,bit; 00760 char buff[2]; 00761 String res(buff,sizeof(buff),&my_charset_latin1); 00762 Field **pos; 00763 00764 for (pos=form->field+fieldnr, bit=1; 00765 *pos && (*pos)->real_type() == FIELD_TYPE_ENUM && 00766 ((Field_enum*) (*pos))->typelib->count == 2 ; 00767 pos++, fieldnr++, bit<<=1) 00768 { 00769 (*pos)->val_str(&res); 00770 if (my_toupper(&my_charset_latin1, res[0]) == 'Y') 00771 access_bits|= bit; 00772 } 00773 if (next_field) 00774 *next_field=fieldnr; 00775 return access_bits; 00776 } 00777 00778 00779 /* 00780 Return a number which, if sorted 'desc', puts strings in this order: 00781 no wildcards 00782 wildcards 00783 empty string 00784 */ 00785 00786 static ulong get_sort(uint count,...) 00787 { 00788 va_list args; 00789 va_start(args,count); 00790 ulong sort=0; 00791 00792 /* Should not use this function with more than 4 arguments for compare. */ 00793 DBUG_ASSERT(count <= 4); 00794 00795 while (count--) 00796 { 00797 char *start, *str= va_arg(args,char*); 00798 uint chars= 0; 00799 uint wild_pos= 0; /* first wildcard position */ 00800 00801 if ((start= str)) 00802 { 00803 for (; *str ; str++) 00804 { 00805 if (*str == wild_many || *str == wild_one || *str == wild_prefix) 00806 { 00807 wild_pos= (uint) (str - start) + 1; 00808 break; 00809 } 00810 chars= 128; // Marker that chars existed 00811 } 00812 } 00813 sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars); 00814 } 00815 va_end(args); 00816 return sort; 00817 } 00818 00819 00820 static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) 00821 { 00822 if (a->sort > b->sort) 00823 return -1; 00824 if (a->sort < b->sort) 00825 return 1; 00826 return 0; 00827 } 00828 00829 00830 /* 00831 Seek ACL entry for a user, check password, SSL cypher, and if 00832 everything is OK, update THD user data and USER_RESOURCES struct. 00833 00834 IMPLEMENTATION 00835 This function does not check if the user has any sensible privileges: 00836 only user's existence and validity is checked. 00837 Note, that entire operation is protected by acl_cache_lock. 00838 00839 SYNOPSIS 00840 acl_getroot() 00841 thd thread handle. If all checks are OK, 00842 thd->security_ctx->priv_user/master_access are updated. 00843 thd->security_ctx->host/ip/user are used for checks. 00844 mqh user resources; on success mqh is reset, else 00845 unchanged 00846 passwd scrambled & crypted password, received from client 00847 (to check): thd->scramble or thd->scramble_323 is 00848 used to decrypt passwd, so they must contain 00849 original random string, 00850 passwd_len length of passwd, must be one of 0, 8, 00851 SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH 00852 'thd' and 'mqh' are updated on success; other params are IN. 00853 00854 RETURN VALUE 00855 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are 00856 updated 00857 1 user not found or authentication failure 00858 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format. 00859 -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format. 00860 */ 00861 00862 int acl_getroot(THD *thd, USER_RESOURCES *mqh, 00863 const char *passwd, uint passwd_len) 00864 { 00865 ulong user_access= NO_ACCESS; 00866 int res= 1; 00867 ACL_USER *acl_user= 0; 00868 Security_context *sctx= thd->security_ctx; 00869 DBUG_ENTER("acl_getroot"); 00870 00871 if (!initialized) 00872 { 00873 /* 00874 here if mysqld's been started with --skip-grant-tables option. 00875 */ 00876 sctx->skip_grants(); 00877 bzero((char*) mqh, sizeof(*mqh)); 00878 DBUG_RETURN(0); 00879 } 00880 00881 VOID(pthread_mutex_lock(&acl_cache->lock)); 00882 00883 /* 00884 Find acl entry in user database. Note, that find_acl_user is not the same, 00885 because it doesn't take into account the case when user is not empty, 00886 but acl_user->user is empty 00887 */ 00888 00889 for (uint i=0 ; i < acl_users.elements ; i++) 00890 { 00891 ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*); 00892 if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user)) 00893 { 00894 if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)) 00895 { 00896 /* check password: it should be empty or valid */ 00897 if (passwd_len == acl_user_tmp->salt_len) 00898 { 00899 if (acl_user_tmp->salt_len == 0 || 00900 (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ? 00901 check_scramble(passwd, thd->scramble, acl_user_tmp->salt) : 00902 check_scramble_323(passwd, thd->scramble, 00903 (ulong *) acl_user_tmp->salt)) == 0) 00904 { 00905 acl_user= acl_user_tmp; 00906 res= 0; 00907 } 00908 } 00909 else if (passwd_len == SCRAMBLE_LENGTH && 00910 acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323) 00911 res= -1; 00912 else if (passwd_len == SCRAMBLE_LENGTH_323 && 00913 acl_user_tmp->salt_len == SCRAMBLE_LENGTH) 00914 res= 2; 00915 /* linear search complete: */ 00916 break; 00917 } 00918 } 00919 } 00920 /* 00921 This was moved to separate tree because of heavy HAVE_OPENSSL case. 00922 If acl_user is not null, res is 0. 00923 */ 00924 00925 if (acl_user) 00926 { 00927 /* OK. User found and password checked continue validation */ 00928 #ifdef HAVE_OPENSSL 00929 Vio *vio=thd->net.vio; 00930 SSL *ssl= (SSL*) vio->ssl_arg; 00931 #endif 00932 00933 /* 00934 At this point we know that user is allowed to connect 00935 from given host by given username/password pair. Now 00936 we check if SSL is required, if user is using SSL and 00937 if X509 certificate attributes are OK 00938 */ 00939 switch (acl_user->ssl_type) { 00940 case SSL_TYPE_NOT_SPECIFIED: // Impossible 00941 case SSL_TYPE_NONE: // SSL is not required 00942 user_access= acl_user->access; 00943 break; 00944 #ifdef HAVE_OPENSSL 00945 case SSL_TYPE_ANY: // Any kind of SSL is ok 00946 if (vio_type(vio) == VIO_TYPE_SSL) 00947 user_access= acl_user->access; 00948 break; 00949 case SSL_TYPE_X509: /* Client should have any valid certificate. */ 00950 /* 00951 Connections with non-valid certificates are dropped already 00952 in sslaccept() anyway, so we do not check validity here. 00953 00954 We need to check for absence of SSL because without SSL 00955 we should reject connection. 00956 */ 00957 if (vio_type(vio) == VIO_TYPE_SSL && 00958 SSL_get_verify_result(ssl) == X509_V_OK && 00959 SSL_get_peer_certificate(ssl)) 00960 user_access= acl_user->access; 00961 break; 00962 case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ 00963 /* 00964 We do not check for absence of SSL because without SSL it does 00965 not pass all checks here anyway. 00966 If cipher name is specified, we compare it to actual cipher in 00967 use. 00968 */ 00969 X509 *cert; 00970 if (vio_type(vio) != VIO_TYPE_SSL || 00971 SSL_get_verify_result(ssl) != X509_V_OK) 00972 break; 00973 if (acl_user->ssl_cipher) 00974 { 00975 DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", 00976 acl_user->ssl_cipher,SSL_get_cipher(ssl))); 00977 if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl))) 00978 user_access= acl_user->access; 00979 else 00980 { 00981 if (global_system_variables.log_warnings) 00982 sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'", 00983 acl_user->ssl_cipher, 00984 SSL_get_cipher(ssl)); 00985 break; 00986 } 00987 } 00988 /* Prepare certificate (if exists) */ 00989 DBUG_PRINT("info",("checkpoint 1")); 00990 if (!(cert= SSL_get_peer_certificate(ssl))) 00991 { 00992 user_access=NO_ACCESS; 00993 break; 00994 } 00995 DBUG_PRINT("info",("checkpoint 2")); 00996 /* If X509 issuer is specified, we check it... */ 00997 if (acl_user->x509_issuer) 00998 { 00999 DBUG_PRINT("info",("checkpoint 3")); 01000 char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 01001 DBUG_PRINT("info",("comparing issuers: '%s' and '%s'", 01002 acl_user->x509_issuer, ptr)); 01003 if (strcmp(acl_user->x509_issuer, ptr)) 01004 { 01005 if (global_system_variables.log_warnings) 01006 sql_print_information("X509 issuer mismatch: should be '%s' " 01007 "but is '%s'", acl_user->x509_issuer, ptr); 01008 free(ptr); 01009 break; 01010 } 01011 user_access= acl_user->access; 01012 free(ptr); 01013 } 01014 DBUG_PRINT("info",("checkpoint 4")); 01015 /* X509 subject is specified, we check it .. */ 01016 if (acl_user->x509_subject) 01017 { 01018 char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 01019 DBUG_PRINT("info",("comparing subjects: '%s' and '%s'", 01020 acl_user->x509_subject, ptr)); 01021 if (strcmp(acl_user->x509_subject,ptr)) 01022 { 01023 if (global_system_variables.log_warnings) 01024 sql_print_information("X509 subject mismatch: '%s' vs '%s'", 01025 acl_user->x509_subject, ptr); 01026 } 01027 else 01028 user_access= acl_user->access; 01029 free(ptr); 01030 } 01031 break; 01032 #else /* HAVE_OPENSSL */ 01033 default: 01034 /* 01035 If we don't have SSL but SSL is required for this user the 01036 authentication should fail. 01037 */ 01038 break; 01039 #endif /* HAVE_OPENSSL */ 01040 } 01041 sctx->master_access= user_access; 01042 sctx->priv_user= acl_user->user ? sctx->user : (char *) ""; 01043 *mqh= acl_user->user_resource; 01044 01045 if (acl_user->host.hostname) 01046 strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); 01047 else 01048 *sctx->priv_host= 0; 01049 } 01050 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01051 DBUG_RETURN(res); 01052 } 01053 01054 01055 /* 01056 This is like acl_getroot() above, but it doesn't check password, 01057 and we don't care about the user resources. 01058 01059 SYNOPSIS 01060 acl_getroot_no_password() 01061 sctx Context which should be initialized 01062 user user name 01063 host host name 01064 ip IP 01065 db current data base name 01066 01067 RETURN 01068 FALSE OK 01069 TRUE Error 01070 */ 01071 01072 bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, 01073 char *ip, char *db) 01074 { 01075 int res= 1; 01076 uint i; 01077 ACL_USER *acl_user= 0; 01078 DBUG_ENTER("acl_getroot_no_password"); 01079 01080 DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'", 01081 (host ? host : "(NULL)"), (ip ? ip : "(NULL)"), 01082 user, (db ? db : "(NULL)"))); 01083 sctx->user= user; 01084 sctx->host= host; 01085 sctx->ip= ip; 01086 sctx->host_or_ip= host ? host : (ip ? ip : ""); 01087 01088 if (!initialized) 01089 { 01090 /* 01091 here if mysqld's been started with --skip-grant-tables option. 01092 */ 01093 sctx->skip_grants(); 01094 DBUG_RETURN(FALSE); 01095 } 01096 01097 VOID(pthread_mutex_lock(&acl_cache->lock)); 01098 01099 sctx->master_access= 0; 01100 sctx->db_access= 0; 01101 sctx->priv_user= (char *) ""; 01102 *sctx->priv_host= 0; 01103 01104 /* 01105 Find acl entry in user database. 01106 This is specially tailored to suit the check we do for CALL of 01107 a stored procedure; user is set to what is actually a 01108 priv_user, which can be ''. 01109 */ 01110 for (i=0 ; i < acl_users.elements ; i++) 01111 { 01112 acl_user= dynamic_element(&acl_users,i,ACL_USER*); 01113 if ((!acl_user->user && !user[0]) || 01114 (acl_user->user && strcmp(user, acl_user->user) == 0)) 01115 { 01116 if (compare_hostname(&acl_user->host, host, ip)) 01117 { 01118 res= 0; 01119 break; 01120 } 01121 } 01122 } 01123 01124 if (acl_user) 01125 { 01126 for (i=0 ; i < acl_dbs.elements ; i++) 01127 { 01128 ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); 01129 if (!acl_db->user || 01130 (user && user[0] && !strcmp(user, acl_db->user))) 01131 { 01132 if (compare_hostname(&acl_db->host, host, ip)) 01133 { 01134 if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0))) 01135 { 01136 sctx->db_access= acl_db->access; 01137 break; 01138 } 01139 } 01140 } 01141 } 01142 sctx->master_access= acl_user->access; 01143 sctx->priv_user= acl_user->user ? user : (char *) ""; 01144 01145 if (acl_user->host.hostname) 01146 strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME); 01147 else 01148 *sctx->priv_host= 0; 01149 } 01150 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01151 DBUG_RETURN(res); 01152 } 01153 01154 static byte* check_get_key(ACL_USER *buff,uint *length, 01155 my_bool not_used __attribute__((unused))) 01156 { 01157 *length=buff->hostname_length; 01158 return (byte*) buff->host.hostname; 01159 } 01160 01161 01162 static void acl_update_user(const char *user, const char *host, 01163 const char *password, uint password_len, 01164 enum SSL_type ssl_type, 01165 const char *ssl_cipher, 01166 const char *x509_issuer, 01167 const char *x509_subject, 01168 USER_RESOURCES *mqh, 01169 ulong privileges) 01170 { 01171 safe_mutex_assert_owner(&acl_cache->lock); 01172 01173 for (uint i=0 ; i < acl_users.elements ; i++) 01174 { 01175 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); 01176 if (!acl_user->user && !user[0] || 01177 acl_user->user && !strcmp(user,acl_user->user)) 01178 { 01179 if (!acl_user->host.hostname && !host[0] || 01180 acl_user->host.hostname && 01181 !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)) 01182 { 01183 acl_user->access=privileges; 01184 if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR) 01185 acl_user->user_resource.questions=mqh->questions; 01186 if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR) 01187 acl_user->user_resource.updates=mqh->updates; 01188 if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR) 01189 acl_user->user_resource.conn_per_hour= mqh->conn_per_hour; 01190 if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS) 01191 acl_user->user_resource.user_conn= mqh->user_conn; 01192 if (ssl_type != SSL_TYPE_NOT_SPECIFIED) 01193 { 01194 acl_user->ssl_type= ssl_type; 01195 acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&mem,ssl_cipher) : 01196 0); 01197 acl_user->x509_issuer= (x509_issuer ? strdup_root(&mem,x509_issuer) : 01198 0); 01199 acl_user->x509_subject= (x509_subject ? 01200 strdup_root(&mem,x509_subject) : 0); 01201 } 01202 if (password) 01203 set_user_salt(acl_user, password, password_len); 01204 /* search complete: */ 01205 break; 01206 } 01207 } 01208 } 01209 } 01210 01211 01212 static void acl_insert_user(const char *user, const char *host, 01213 const char *password, uint password_len, 01214 enum SSL_type ssl_type, 01215 const char *ssl_cipher, 01216 const char *x509_issuer, 01217 const char *x509_subject, 01218 USER_RESOURCES *mqh, 01219 ulong privileges) 01220 { 01221 ACL_USER acl_user; 01222 01223 safe_mutex_assert_owner(&acl_cache->lock); 01224 01225 acl_user.user=*user ? strdup_root(&mem,user) : 0; 01226 update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0); 01227 acl_user.access=privileges; 01228 acl_user.user_resource = *mqh; 01229 acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user); 01230 acl_user.hostname_length=(uint) strlen(host); 01231 acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ? 01232 ssl_type : SSL_TYPE_NONE); 01233 acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0; 01234 acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0; 01235 acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0; 01236 01237 set_user_salt(&acl_user, password, password_len); 01238 01239 VOID(push_dynamic(&acl_users,(gptr) &acl_user)); 01240 if (!acl_user.host.hostname || 01241 (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1])) 01242 allow_all_hosts=1; // Anyone can connect /* purecov: tested */ 01243 qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, 01244 sizeof(ACL_USER),(qsort_cmp) acl_compare); 01245 01246 /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ 01247 rebuild_check_host(); 01248 } 01249 01250 01251 static void acl_update_db(const char *user, const char *host, const char *db, 01252 ulong privileges) 01253 { 01254 safe_mutex_assert_owner(&acl_cache->lock); 01255 01256 for (uint i=0 ; i < acl_dbs.elements ; i++) 01257 { 01258 ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*); 01259 if (!acl_db->user && !user[0] || 01260 acl_db->user && 01261 !strcmp(user,acl_db->user)) 01262 { 01263 if (!acl_db->host.hostname && !host[0] || 01264 acl_db->host.hostname && 01265 !my_strcasecmp(system_charset_info, host, acl_db->host.hostname)) 01266 { 01267 if (!acl_db->db && !db[0] || 01268 acl_db->db && !strcmp(db,acl_db->db)) 01269 { 01270 if (privileges) 01271 acl_db->access=privileges; 01272 else 01273 delete_dynamic_element(&acl_dbs,i); 01274 } 01275 } 01276 } 01277 } 01278 } 01279 01280 01281 /* 01282 Insert a user/db/host combination into the global acl_cache 01283 01284 SYNOPSIS 01285 acl_insert_db() 01286 user User name 01287 host Host name 01288 db Database name 01289 privileges Bitmap of privileges 01290 01291 NOTES 01292 acl_cache->lock must be locked when calling this 01293 */ 01294 01295 static void acl_insert_db(const char *user, const char *host, const char *db, 01296 ulong privileges) 01297 { 01298 ACL_DB acl_db; 01299 safe_mutex_assert_owner(&acl_cache->lock); 01300 acl_db.user=strdup_root(&mem,user); 01301 update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0); 01302 acl_db.db=strdup_root(&mem,db); 01303 acl_db.access=privileges; 01304 acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user); 01305 VOID(push_dynamic(&acl_dbs,(gptr) &acl_db)); 01306 qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, 01307 sizeof(ACL_DB),(qsort_cmp) acl_compare); 01308 } 01309 01310 01311 01312 /* 01313 Get privilege for a host, user and db combination 01314 01315 as db_is_pattern changes the semantics of comparison, 01316 acl_cache is not used if db_is_pattern is set. 01317 */ 01318 01319 ulong acl_get(const char *host, const char *ip, 01320 const char *user, const char *db, my_bool db_is_pattern) 01321 { 01322 ulong host_access= ~(ulong)0, db_access= 0; 01323 uint i,key_length; 01324 char key[ACL_KEY_LENGTH],*tmp_db,*end; 01325 acl_entry *entry; 01326 DBUG_ENTER("acl_get"); 01327 01328 VOID(pthread_mutex_lock(&acl_cache->lock)); 01329 end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db); 01330 if (lower_case_table_names) 01331 { 01332 my_casedn_str(files_charset_info, tmp_db); 01333 db=tmp_db; 01334 } 01335 key_length=(uint) (end-key); 01336 if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search(key,key_length))) 01337 { 01338 db_access=entry->access; 01339 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01340 DBUG_PRINT("exit", ("access: 0x%lx", db_access)); 01341 DBUG_RETURN(db_access); 01342 } 01343 01344 /* 01345 Check if there are some access rights for database and user 01346 */ 01347 for (i=0 ; i < acl_dbs.elements ; i++) 01348 { 01349 ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*); 01350 if (!acl_db->user || !strcmp(user,acl_db->user)) 01351 { 01352 if (compare_hostname(&acl_db->host,host,ip)) 01353 { 01354 if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern)) 01355 { 01356 db_access=acl_db->access; 01357 if (acl_db->host.hostname) 01358 goto exit; // Fully specified. Take it 01359 break; /* purecov: tested */ 01360 } 01361 } 01362 } 01363 } 01364 if (!db_access) 01365 goto exit; // Can't be better 01366 01367 /* 01368 No host specified for user. Get hostdata from host table 01369 */ 01370 host_access=0; // Host must be found 01371 for (i=0 ; i < acl_hosts.elements ; i++) 01372 { 01373 ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*); 01374 if (compare_hostname(&acl_host->host,host,ip)) 01375 { 01376 if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern)) 01377 { 01378 host_access=acl_host->access; // Fully specified. Take it 01379 break; 01380 } 01381 } 01382 } 01383 exit: 01384 /* Save entry in cache for quick retrieval */ 01385 if (!db_is_pattern && 01386 (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length))) 01387 { 01388 entry->access=(db_access & host_access); 01389 entry->length=key_length; 01390 memcpy((gptr) entry->key,key,key_length); 01391 acl_cache->add(entry); 01392 } 01393 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01394 DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access)); 01395 DBUG_RETURN(db_access & host_access); 01396 } 01397 01398 /* 01399 Check if there are any possible matching entries for this host 01400 01401 NOTES 01402 All host names without wild cards are stored in a hash table, 01403 entries with wildcards are stored in a dynamic array 01404 */ 01405 01406 static void init_check_host(void) 01407 { 01408 DBUG_ENTER("init_check_host"); 01409 VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip), 01410 acl_users.elements,1)); 01411 VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0, 01412 (hash_get_key) check_get_key,0,0)); 01413 if (!allow_all_hosts) 01414 { 01415 for (uint i=0 ; i < acl_users.elements ; i++) 01416 { 01417 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); 01418 if (strchr(acl_user->host.hostname,wild_many) || 01419 strchr(acl_user->host.hostname,wild_one) || 01420 acl_user->host.ip_mask) 01421 { // Has wildcard 01422 uint j; 01423 for (j=0 ; j < acl_wild_hosts.elements ; j++) 01424 { // Check if host already exists 01425 acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j, 01426 acl_host_and_ip *); 01427 if (!my_strcasecmp(system_charset_info, 01428 acl_user->host.hostname, acl->hostname)) 01429 break; // already stored 01430 } 01431 if (j == acl_wild_hosts.elements) // If new 01432 (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host); 01433 } 01434 else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname, 01435 (uint) strlen(acl_user->host.hostname))) 01436 { 01437 if (my_hash_insert(&acl_check_hosts,(byte*) acl_user)) 01438 { // End of memory 01439 allow_all_hosts=1; // Should never happen 01440 DBUG_VOID_RETURN; 01441 } 01442 } 01443 } 01444 } 01445 freeze_size(&acl_wild_hosts); 01446 freeze_size(&acl_check_hosts.array); 01447 DBUG_VOID_RETURN; 01448 } 01449 01450 01451 /* 01452 Rebuild lists used for checking of allowed hosts 01453 01454 We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding, 01455 dropping or renaming user, since they contain pointers to elements of 01456 'acl_user' array, which are invalidated by drop operation, and use 01457 ACL_USER::host::hostname as a key, which is changed by rename. 01458 */ 01459 void rebuild_check_host(void) 01460 { 01461 delete_dynamic(&acl_wild_hosts); 01462 hash_free(&acl_check_hosts); 01463 init_check_host(); 01464 } 01465 01466 01467 /* Return true if there is no users that can match the given host */ 01468 01469 bool acl_check_host(const char *host, const char *ip) 01470 { 01471 if (allow_all_hosts) 01472 return 0; 01473 VOID(pthread_mutex_lock(&acl_cache->lock)); 01474 01475 if (host && hash_search(&acl_check_hosts,(byte*) host,(uint) strlen(host)) || 01476 ip && hash_search(&acl_check_hosts,(byte*) ip,(uint) strlen(ip))) 01477 { 01478 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01479 return 0; // Found host 01480 } 01481 for (uint i=0 ; i < acl_wild_hosts.elements ; i++) 01482 { 01483 acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*); 01484 if (compare_hostname(acl, host, ip)) 01485 { 01486 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01487 return 0; // Host ok 01488 } 01489 } 01490 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01491 return 1; // Host is not allowed 01492 } 01493 01494 01495 /* 01496 Check if the user is allowed to change password 01497 01498 SYNOPSIS: 01499 check_change_password() 01500 thd THD 01501 host hostname for the user 01502 user user name 01503 new_password new password 01504 01505 NOTE: 01506 new_password cannot be NULL 01507 01508 RETURN VALUE 01509 0 OK 01510 1 ERROR ; In this case the error is sent to the client. 01511 */ 01512 01513 bool check_change_password(THD *thd, const char *host, const char *user, 01514 char *new_password, uint new_password_len) 01515 { 01516 if (!initialized) 01517 { 01518 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); 01519 return(1); 01520 } 01521 if (!thd->slave_thread && 01522 (strcmp(thd->security_ctx->user, user) || 01523 my_strcasecmp(system_charset_info, host, 01524 thd->security_ctx->priv_host))) 01525 { 01526 if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0)) 01527 return(1); 01528 } 01529 if (!thd->slave_thread && !thd->security_ctx->user[0]) 01530 { 01531 my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), 01532 MYF(0)); 01533 return(1); 01534 } 01535 uint len=strlen(new_password); 01536 if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH && 01537 len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) 01538 { 01539 my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); 01540 return -1; 01541 } 01542 return(0); 01543 } 01544 01545 01546 /* 01547 Change a password for a user 01548 01549 SYNOPSIS 01550 change_password() 01551 thd Thread handle 01552 host Hostname 01553 user User name 01554 new_password New password for host@user 01555 01556 RETURN VALUES 01557 0 ok 01558 1 ERROR; In this case the error is sent to the client. 01559 */ 01560 01561 bool change_password(THD *thd, const char *host, const char *user, 01562 char *new_password) 01563 { 01564 TABLE_LIST tables; 01565 TABLE *table; 01566 /* Buffer should be extended when password length is extended. */ 01567 char buff[512]; 01568 ulong query_length; 01569 uint new_password_len= strlen(new_password); 01570 bool result= 1; 01571 DBUG_ENTER("change_password"); 01572 DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", 01573 host,user,new_password)); 01574 DBUG_ASSERT(host != 0); // Ensured by parent 01575 01576 if (check_change_password(thd, host, user, new_password, new_password_len)) 01577 DBUG_RETURN(1); 01578 01579 bzero((char*) &tables, sizeof(tables)); 01580 tables.alias= tables.table_name= (char*) "user"; 01581 tables.db= (char*) "mysql"; 01582 01583 #ifdef HAVE_REPLICATION 01584 /* 01585 GRANT and REVOKE are applied the slave in/exclusion rules as they are 01586 some kind of updates to the mysql.% tables. 01587 */ 01588 if (thd->slave_thread && rpl_filter->is_on()) 01589 { 01590 /* 01591 The tables must be marked "updating" so that tables_ok() takes them into 01592 account in tests. It's ok to leave 'updating' set after tables_ok. 01593 */ 01594 tables.updating= 1; 01595 /* Thanks to bzero, tables.next==0 */ 01596 if (!(thd->spcont || rpl_filter->tables_ok(0, &tables))) 01597 DBUG_RETURN(0); 01598 } 01599 #endif 01600 01601 if (!(table= open_ltable(thd, &tables, TL_WRITE))) 01602 DBUG_RETURN(1); 01603 01604 VOID(pthread_mutex_lock(&acl_cache->lock)); 01605 ACL_USER *acl_user; 01606 if (!(acl_user= find_acl_user(host, user, TRUE))) 01607 { 01608 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01609 my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); 01610 goto end; 01611 } 01612 /* update loaded acl entry: */ 01613 set_user_salt(acl_user, new_password, new_password_len); 01614 01615 if (update_user_table(thd, table, 01616 acl_user->host.hostname ? acl_user->host.hostname : "", 01617 acl_user->user ? acl_user->user : "", 01618 new_password, new_password_len)) 01619 { 01620 VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ 01621 goto end; 01622 } 01623 01624 acl_cache->clear(1); // Clear locked hostname cache 01625 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01626 result= 0; 01627 if (mysql_bin_log.is_open()) 01628 { 01629 query_length= 01630 my_sprintf(buff, 01631 (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", 01632 acl_user->user ? acl_user->user : "", 01633 acl_user->host.hostname ? acl_user->host.hostname : "", 01634 new_password)); 01635 thd->clear_error(); 01636 thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length, FALSE, FALSE); 01637 } 01638 end: 01639 close_thread_tables(thd); 01640 DBUG_RETURN(result); 01641 } 01642 01643 01644 /* 01645 Find user in ACL 01646 01647 SYNOPSIS 01648 is_acl_user() 01649 host host name 01650 user user name 01651 01652 RETURN 01653 FALSE user not fond 01654 TRUE there are such user 01655 */ 01656 01657 bool is_acl_user(const char *host, const char *user) 01658 { 01659 bool res; 01660 01661 /* --skip-grants */ 01662 if (!initialized) 01663 return TRUE; 01664 01665 VOID(pthread_mutex_lock(&acl_cache->lock)); 01666 res= find_acl_user(host, user, TRUE) != NULL; 01667 VOID(pthread_mutex_unlock(&acl_cache->lock)); 01668 return res; 01669 } 01670 01671 01672 /* 01673 Find first entry that matches the current user 01674 */ 01675 01676 static ACL_USER * 01677 find_acl_user(const char *host, const char *user, my_bool exact) 01678 { 01679 DBUG_ENTER("find_acl_user"); 01680 DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user)); 01681 01682 safe_mutex_assert_owner(&acl_cache->lock); 01683 01684 for (uint i=0 ; i < acl_users.elements ; i++) 01685 { 01686 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); 01687 DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", 01688 user, acl_user->user ? acl_user->user : "", 01689 host, 01690 acl_user->host.hostname ? acl_user->host.hostname : 01691 "")); 01692 if (!acl_user->user && !user[0] || 01693 acl_user->user && !strcmp(user,acl_user->user)) 01694 { 01695 if (exact ? !my_strcasecmp(system_charset_info, host, 01696 acl_user->host.hostname ? 01697 acl_user->host.hostname : "") : 01698 compare_hostname(&acl_user->host,host,host)) 01699 { 01700 DBUG_RETURN(acl_user); 01701 } 01702 } 01703 } 01704 DBUG_RETURN(0); 01705 } 01706 01707 01708 /* 01709 Comparing of hostnames 01710 01711 NOTES 01712 A hostname may be of type: 01713 hostname (May include wildcards); monty.pp.sci.fi 01714 ip (May include wildcards); 192.168.0.0 01715 ip/netmask 192.168.0.0/255.255.255.0 01716 01717 A net mask of 0.0.0.0 is not allowed. 01718 */ 01719 01720 static const char *calc_ip(const char *ip, long *val, char end) 01721 { 01722 long ip_val,tmp; 01723 if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.') 01724 return 0; 01725 ip_val<<=24; 01726 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.') 01727 return 0; 01728 ip_val+=tmp<<16; 01729 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.') 01730 return 0; 01731 ip_val+=tmp<<8; 01732 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end) 01733 return 0; 01734 *val=ip_val+tmp; 01735 return ip; 01736 } 01737 01738 01739 static void update_hostname(acl_host_and_ip *host, const char *hostname) 01740 { 01741 host->hostname=(char*) hostname; // This will not be modified! 01742 if (!hostname || 01743 (!(hostname=calc_ip(hostname,&host->ip,'/')) || 01744 !(hostname=calc_ip(hostname+1,&host->ip_mask,'\0')))) 01745 { 01746 host->ip= host->ip_mask=0; // Not a masked ip 01747 } 01748 } 01749 01750 01751 static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, 01752 const char *ip) 01753 { 01754 long tmp; 01755 if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0')) 01756 { 01757 return (tmp & host->ip_mask) == host->ip; 01758 } 01759 return (!host->hostname || 01760 (hostname && !wild_case_compare(system_charset_info, 01761 hostname, host->hostname)) || 01762 (ip && !wild_compare(ip, host->hostname, 0))); 01763 } 01764 01765 bool hostname_requires_resolving(const char *hostname) 01766 { 01767 char cur; 01768 if (!hostname) 01769 return FALSE; 01770 int namelen= strlen(hostname); 01771 int lhlen= strlen(my_localhost); 01772 if ((namelen == lhlen) && 01773 !my_strnncoll(system_charset_info, (const uchar *)hostname, namelen, 01774 (const uchar *)my_localhost, strlen(my_localhost))) 01775 return FALSE; 01776 for (; (cur=*hostname); hostname++) 01777 { 01778 if ((cur != '%') && (cur != '_') && (cur != '.') && (cur != '/') && 01779 ((cur < '0') || (cur > '9'))) 01780 return TRUE; 01781 } 01782 return FALSE; 01783 } 01784 01785 01786 /* 01787 Update record for user in mysql.user privilege table with new password. 01788 01789 SYNOPSIS 01790 update_user_table() 01791 thd Thread handle 01792 table Pointer to TABLE object for open mysql.user table 01793 host/user Hostname/username pair identifying user for which 01794 new password should be set 01795 new_password New password 01796 new_password_len Length of new password 01797 */ 01798 01799 static bool update_user_table(THD *thd, TABLE *table, 01800 const char *host, const char *user, 01801 const char *new_password, uint new_password_len) 01802 { 01803 char user_key[MAX_KEY_LENGTH]; 01804 int error; 01805 DBUG_ENTER("update_user_table"); 01806 DBUG_PRINT("enter",("user: %s host: %s",user,host)); 01807 01808 table->use_all_columns(); 01809 table->field[0]->store(host,(uint) strlen(host), system_charset_info); 01810 table->field[1]->store(user,(uint) strlen(user), system_charset_info); 01811 key_copy((byte *) user_key, table->record[0], table->key_info, 01812 table->key_info->key_length); 01813 01814 if (table->file->index_read_idx(table->record[0], 0, 01815 (byte *) user_key, 01816 table->key_info->key_length, 01817 HA_READ_KEY_EXACT)) 01818 { 01819 my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), 01820 MYF(0)); /* purecov: deadcode */ 01821 DBUG_RETURN(1); /* purecov: deadcode */ 01822 } 01823 store_record(table,record[1]); 01824 table->field[2]->store(new_password, new_password_len, system_charset_info); 01825 if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) 01826 { 01827 table->file->print_error(error,MYF(0)); /* purecov: deadcode */ 01828 DBUG_RETURN(1); 01829 } 01830 DBUG_RETURN(0); 01831 } 01832 01833 01834 /* 01835 Return 1 if we are allowed to create new users 01836 the logic here is: INSERT_ACL is sufficient. 01837 It's also a requirement in opt_safe_user_create, 01838 otherwise CREATE_USER_ACL is enough. 01839 */ 01840 01841 static bool test_if_create_new_users(THD *thd) 01842 { 01843 Security_context *sctx= thd->security_ctx; 01844 bool create_new_users= test(sctx->master_access & INSERT_ACL) || 01845 (!opt_safe_user_create && 01846 test(sctx->master_access & CREATE_USER_ACL)); 01847 if (!create_new_users) 01848 { 01849 TABLE_LIST tl; 01850 ulong db_access; 01851 bzero((char*) &tl,sizeof(tl)); 01852 tl.db= (char*) "mysql"; 01853 tl.table_name= (char*) "user"; 01854 create_new_users= 1; 01855 01856 db_access=acl_get(sctx->host, sctx->ip, 01857 sctx->priv_user, tl.db, 0); 01858 if (!(db_access & INSERT_ACL)) 01859 { 01860 if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1)) 01861 create_new_users=0; 01862 } 01863 } 01864 return create_new_users; 01865 } 01866 01867 01868 /**************************************************************************** 01869 Handle GRANT commands 01870 ****************************************************************************/ 01871 01872 static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, 01873 ulong rights, bool revoke_grant, 01874 bool can_create_user, bool no_auto_create) 01875 { 01876 int error = -1; 01877 bool old_row_exists=0; 01878 const char *password= ""; 01879 uint password_len= 0; 01880 char what= (revoke_grant) ? 'N' : 'Y'; 01881 byte user_key[MAX_KEY_LENGTH]; 01882 LEX *lex= thd->lex; 01883 DBUG_ENTER("replace_user_table"); 01884 01885 safe_mutex_assert_owner(&acl_cache->lock); 01886 01887 if (combo.password.str && combo.password.str[0]) 01888 { 01889 if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH && 01890 combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) 01891 { 01892 my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); 01893 DBUG_RETURN(-1); 01894 } 01895 password_len= combo.password.length; 01896 password=combo.password.str; 01897 } 01898 01899 table->use_all_columns(); 01900 table->field[0]->store(combo.host.str,combo.host.length, 01901 system_charset_info); 01902 table->field[1]->store(combo.user.str,combo.user.length, 01903 system_charset_info); 01904 key_copy(user_key, table->record[0], table->key_info, 01905 table->key_info->key_length); 01906 01907 if (table->file->index_read_idx(table->record[0], 0, 01908 user_key, table->key_info->key_length, 01909 HA_READ_KEY_EXACT)) 01910 { 01911 /* what == 'N' means revoke */ 01912 if (what == 'N') 01913 { 01914 my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str); 01915 goto end; 01916 } 01917 /* 01918 There are four options which affect the process of creation of 01919 a new user (mysqld option --safe-create-user, 'insert' privilege 01920 on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and 01921 SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule 01922 how it should work. 01923 if (safe-user-create && ! INSERT_priv) => reject 01924 else if (identified_by) => create 01925 else if (no_auto_create_user) => reject 01926 else create 01927 01928 see also test_if_create_new_users() 01929 */ 01930 else if (!password_len && no_auto_create) 01931 { 01932 my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str); 01933 goto end; 01934 } 01935 else if (!can_create_user) 01936 { 01937 my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0), 01938 thd->security_ctx->user, thd->security_ctx->host_or_ip); 01939 goto end; 01940 } 01941 old_row_exists = 0; 01942 restore_record(table,s->default_values); 01943 table->field[0]->store(combo.host.str,combo.host.length, 01944 system_charset_info); 01945 table->field[1]->store(combo.user.str,combo.user.length, 01946 system_charset_info); 01947 table->field[2]->store(password, password_len, 01948 system_charset_info); 01949 } 01950 else 01951 { 01952 old_row_exists = 1; 01953 store_record(table,record[1]); // Save copy for update 01954 if (combo.password.str) // If password given 01955 table->field[2]->store(password, password_len, system_charset_info); 01956 else if (!rights && !revoke_grant && 01957 lex->ssl_type == SSL_TYPE_NOT_SPECIFIED && 01958 !lex->mqh.specified_limits) 01959 { 01960 DBUG_RETURN(0); 01961 } 01962 } 01963 01964 /* Update table columns with new privileges */ 01965 01966 Field **tmp_field; 01967 ulong priv; 01968 uint next_field; 01969 for (tmp_field= table->field+3, priv = SELECT_ACL; 01970 *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM && 01971 ((Field_enum*) (*tmp_field))->typelib->count == 2 ; 01972 tmp_field++, priv <<= 1) 01973 { 01974 if (priv & rights) // set requested privileges 01975 (*tmp_field)->store(&what, 1, &my_charset_latin1); 01976 } 01977 rights= get_access(table, 3, &next_field); 01978 DBUG_PRINT("info",("table fields: %d",table->s->fields)); 01979 if (table->s->fields >= 31) /* From 4.0.0 we have more fields */ 01980 { 01981 /* We write down SSL related ACL stuff */ 01982 switch (lex->ssl_type) { 01983 case SSL_TYPE_ANY: 01984 table->field[next_field]->store(STRING_WITH_LEN("ANY"), 01985 &my_charset_latin1); 01986 table->field[next_field+1]->store("", 0, &my_charset_latin1); 01987 table->field[next_field+2]->store("", 0, &my_charset_latin1); 01988 table->field[next_field+3]->store("", 0, &my_charset_latin1); 01989 break; 01990 case SSL_TYPE_X509: 01991 table->field[next_field]->store(STRING_WITH_LEN("X509"), 01992 &my_charset_latin1); 01993 table->field[next_field+1]->store("", 0, &my_charset_latin1); 01994 table->field[next_field+2]->store("", 0, &my_charset_latin1); 01995 table->field[next_field+3]->store("", 0, &my_charset_latin1); 01996 break; 01997 case SSL_TYPE_SPECIFIED: 01998 table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"), 01999 &my_charset_latin1); 02000 table->field[next_field+1]->store("", 0, &my_charset_latin1); 02001 table->field[next_field+2]->store("", 0, &my_charset_latin1); 02002 table->field[next_field+3]->store("", 0, &my_charset_latin1); 02003 if (lex->ssl_cipher) 02004 table->field[next_field+1]->store(lex->ssl_cipher, 02005 strlen(lex->ssl_cipher), system_charset_info); 02006 if (lex->x509_issuer) 02007 table->field[next_field+2]->store(lex->x509_issuer, 02008 strlen(lex->x509_issuer), system_charset_info); 02009 if (lex->x509_subject) 02010 table->field[next_field+3]->store(lex->x509_subject, 02011 strlen(lex->x509_subject), system_charset_info); 02012 break; 02013 case SSL_TYPE_NOT_SPECIFIED: 02014 break; 02015 case SSL_TYPE_NONE: 02016 table->field[next_field]->store("", 0, &my_charset_latin1); 02017 table->field[next_field+1]->store("", 0, &my_charset_latin1); 02018 table->field[next_field+2]->store("", 0, &my_charset_latin1); 02019 table->field[next_field+3]->store("", 0, &my_charset_latin1); 02020 break; 02021 } 02022 next_field+=4; 02023 02024 USER_RESOURCES mqh= lex->mqh; 02025 if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR) 02026 table->field[next_field]->store((longlong) mqh.questions, TRUE); 02027 if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR) 02028 table->field[next_field+1]->store((longlong) mqh.updates, TRUE); 02029 if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR) 02030 table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE); 02031 if (table->s->fields >= 36 && 02032 (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS)) 02033 table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE); 02034 mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour; 02035 } 02036 if (old_row_exists) 02037 { 02038 /* 02039 We should NEVER delete from the user table, as a uses can still 02040 use mysqld even if he doesn't have any privileges in the user table! 02041 */ 02042 if (cmp_record(table,record[1]) && 02043 (error=table->file->ha_update_row(table->record[1],table->record[0]))) 02044 { // This should never happen 02045 table->file->print_error(error,MYF(0)); /* purecov: deadcode */ 02046 error= -1; /* purecov: deadcode */ 02047 goto end; /* purecov: deadcode */ 02048 } 02049 } 02050 else if ((error=table->file->ha_write_row(table->record[0]))) // insert 02051 { // This should never happen 02052 if (table->file->is_fatal_error(error, HA_CHECK_DUP)) 02053 { 02054 table->file->print_error(error,MYF(0)); /* purecov: deadcode */ 02055 error= -1; /* purecov: deadcode */ 02056 goto end; /* purecov: deadcode */ 02057 } 02058 } 02059 error=0; // Privileges granted / revoked 02060 02061 end: 02062 if (!error) 02063 { 02064 acl_cache->clear(1); // Clear privilege cache 02065 if (old_row_exists) 02066 acl_update_user(combo.user.str, combo.host.str, 02067 combo.password.str, password_len, 02068 lex->ssl_type, 02069 lex->ssl_cipher, 02070 lex->x509_issuer, 02071 lex->x509_subject, 02072 &lex->mqh, 02073 rights); 02074 else 02075 acl_insert_user(combo.user.str, combo.host.str, password, password_len, 02076 lex->ssl_type, 02077 lex->ssl_cipher, 02078 lex->x509_issuer, 02079 lex->x509_subject, 02080 &lex->mqh, 02081 rights); 02082 } 02083 DBUG_RETURN(error); 02084 } 02085 02086 02087 /* 02088 change grants in the mysql.db table 02089 */ 02090 02091 static int replace_db_table(TABLE *table, const char *db, 02092 const LEX_USER &combo, 02093 ulong rights, bool revoke_grant) 02094 { 02095 uint i; 02096 ulong priv,store_rights; 02097 bool old_row_exists=0; 02098 int error; 02099 char what= (revoke_grant) ? 'N' : 'Y'; 02100 byte user_key[MAX_KEY_LENGTH]; 02101 DBUG_ENTER("replace_db_table"); 02102 02103 if (!initialized) 02104 { 02105 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); 02106 DBUG_RETURN(-1); 02107 } 02108 02109 /* Check if there is such a user in user table in memory? */ 02110 if (!find_acl_user(combo.host.str,combo.user.str, FALSE)) 02111 { 02112 my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); 02113 DBUG_RETURN(-1); 02114 } 02115 02116 table->use_all_columns(); 02117 table->field[0]->store(combo.host.str,combo.host.length, 02118 system_charset_info); 02119 table->field[1]->store(db,(uint) strlen(db), system_charset_info); 02120 table->field[2]->store(combo.user.str,combo.user.length, 02121 system_charset_info); 02122 key_copy(user_key, table->record[0], table->key_info, 02123 table->key_info->key_length); 02124 02125 if (table->file->index_read_idx(table->record[0],0, 02126 user_key, table->key_info->key_length, 02127 HA_READ_KEY_EXACT)) 02128 { 02129 if (what == 'N') 02130 { // no row, no revoke 02131 my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str); 02132 goto abort; 02133 } 02134 old_row_exists = 0; 02135 restore_record(table, s->default_values); 02136 table->field[0]->store(combo.host.str,combo.host.length, 02137 system_charset_info); 02138 table->field[1]->store(db,(uint) strlen(db), system_charset_info); 02139 table->field[2]->store(combo.user.str,combo.user.length, 02140 system_charset_info); 02141 } 02142 else 02143 { 02144 old_row_exists = 1; 02145 store_record(table,record[1]); 02146 } 02147 02148 store_rights=get_rights_for_db(rights); 02149 for (i= 3, priv= 1; i < table->s->fields; i++, priv <<= 1) 02150 { 02151 if (priv & store_rights) // do it if priv is chosen 02152 table->field [i]->store(&what,1, &my_charset_latin1);// set requested privileges 02153 } 02154 rights=get_access(table,3); 02155 rights=fix_rights_for_db(rights); 02156 02157 if (old_row_exists) 02158 { 02159 /* update old existing row */ 02160 if (rights) 02161 { 02162 if ((error= table->file->ha_update_row(table->record[1], 02163 table->record[0]))) 02164 goto table_error; /* purecov: deadcode */ 02165 } 02166 else /* must have been a revoke of all privileges */ 02167 { 02168 if ((error= table->file->ha_delete_row(table->record[1]))) 02169 goto table_error; /* purecov: deadcode */ 02170 } 02171 } 02172 else if (rights && (error= table->file->ha_write_row(table->record[0]))) 02173 { 02174 if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) 02175 goto table_error; /* purecov: deadcode */ 02176 } 02177 02178 acl_cache->clear(1); // Clear privilege cache 02179 if (old_row_exists) 02180 acl_update_db(combo.user.str,combo.host.str,db,rights); 02181 else 02182 if (rights) 02183 acl_insert_db(combo.user.str,combo.host.str,db,rights); 02184 DBUG_RETURN(0); 02185 02186 /* This could only happen if the grant tables got corrupted */ 02187 table_error: 02188 table->file->print_error(error,MYF(0)); /* purecov: deadcode */ 02189 02190 abort: 02191 DBUG_RETURN(-1); 02192 } 02193 02194 02195 class GRANT_COLUMN :public Sql_alloc 02196 { 02197 public: 02198 char *column; 02199 ulong rights; 02200 uint key_length; 02201 GRANT_COLUMN(String &c, ulong y) :rights (y) 02202 { 02203 column= memdup_root(&memex,c.ptr(), key_length=c.length()); 02204 } 02205 }; 02206 02207 02208 static byte* get_key_column(GRANT_COLUMN *buff,uint *length, 02209 my_bool not_used __attribute__((unused))) 02210 { 02211 *length=buff->key_length; 02212 return (byte*) buff->column; 02213 } 02214 02215 02216 class GRANT_NAME :public Sql_alloc 02217 { 02218 public: 02219 acl_host_and_ip host; 02220 char *db, *user, *tname, *hash_key; 02221 ulong privs; 02222 ulong sort; 02223 uint key_length; 02224 GRANT_NAME(const char *h, const char *d,const char *u, 02225 const char *t, ulong p); 02226 GRANT_NAME (TABLE *form); 02227 virtual ~GRANT_NAME() {}; 02228 virtual bool ok() { return privs != 0; } 02229 }; 02230 02231 02232 class GRANT_TABLE :public GRANT_NAME 02233 { 02234 public: 02235 ulong cols; 02236 HASH hash_columns; 02237 02238 GRANT_TABLE(const char *h, const char *d,const char *u, 02239 const char *t, ulong p, ulong c); 02240 GRANT_TABLE (TABLE *form, TABLE *col_privs); 02241 ~GRANT_TABLE(); 02242 bool ok() { return privs != 0 || cols != 0; } 02243 }; 02244 02245 02246 02247 GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, 02248 const char *t, ulong p) 02249 :privs(p) 02250 { 02251 /* Host given by user */ 02252 update_hostname(&host, strdup_root(&memex, h)); 02253 db = strdup_root(&memex,d); 02254 user = strdup_root(&memex,u); 02255 sort= get_sort(3,host.hostname,db,user); 02256 tname= strdup_root(&memex,t); 02257 if (lower_case_table_names) 02258 { 02259 my_casedn_str(files_charset_info, db); 02260 my_casedn_str(files_charset_info, tname); 02261 } 02262 key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3; 02263 hash_key = (char*) alloc_root(&memex,key_length); 02264 strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); 02265 } 02266 02267 02268 GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, 02269 const char *t, ulong p, ulong c) 02270 :GRANT_NAME(h,d,u,t,p), cols(c) 02271 { 02272 (void) hash_init(&hash_columns,system_charset_info, 02273 0,0,0, (hash_get_key) get_key_column,0,0); 02274 } 02275 02276 02277 GRANT_NAME::GRANT_NAME(TABLE *form) 02278 { 02279 update_hostname(&host, get_field(&memex, form->field[0])); 02280 db= get_field(&memex,form->field[1]); 02281 user= get_field(&memex,form->field[2]); 02282 if (!user) 02283 user= (char*) ""; 02284 sort= get_sort(3, host.hostname, db, user); 02285 tname= get_field(&memex,form->field[3]); 02286 if (!db || !tname) 02287 { 02288 /* Wrong table row; Ignore it */ 02289 privs= 0; 02290 return; /* purecov: inspected */ 02291 } 02292 if (lower_case_table_names) 02293 { 02294 my_casedn_str(files_charset_info, db); 02295 my_casedn_str(files_charset_info, tname); 02296 } 02297 key_length = ((uint) strlen(db) + (uint) strlen(user) + 02298 (uint) strlen(tname) + 3); 02299 hash_key = (char*) alloc_root(&memex,key_length); 02300 strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); 02301 privs = (ulong) form->field[6]->val_int(); 02302 privs = fix_rights_for_table(privs); 02303 } 02304 02305 02306 GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) 02307 :GRANT_NAME(form) 02308 { 02309 byte key[MAX_KEY_LENGTH]; 02310 02311 if (!db || !tname) 02312 { 02313 /* Wrong table row; Ignore it */ 02314 hash_clear(&hash_columns); /* allow for destruction */ 02315 cols= 0; 02316 return; 02317 } 02318 cols= (ulong) form->field[7]->val_int(); 02319 cols = fix_rights_for_column(cols); 02320 02321 (void) hash_init(&hash_columns,system_charset_info, 02322 0,0,0, (hash_get_key) get_key_column,0,0); 02323 if (cols) 02324 { 02325 uint key_prefix_len; 02326 KEY_PART_INFO *key_part= col_privs->key_info->key_part; 02327 col_privs->field[0]->store(host.hostname, 02328 host.hostname ? (uint) strlen(host.hostname) : 02329 0, 02330 system_charset_info); 02331 col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info); 02332 col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info); 02333 col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info); 02334 02335 key_prefix_len= (key_part[0].store_length + 02336 key_part[1].store_length + 02337 key_part[2].store_length + 02338 key_part[3].store_length); 02339 key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len); 02340 col_privs->field[4]->store("",0, &my_charset_latin1); 02341 02342 col_privs->file->ha_index_init(0, 1); 02343 if (col_privs->file->index_read(col_privs->record[0], 02344 (byte*) key, 02345 key_prefix_len, HA_READ_KEY_EXACT)) 02346 { 02347 cols = 0; /* purecov: deadcode */ 02348 col_privs->file->ha_index_end(); 02349 return; 02350 } 02351 do 02352 { 02353 String *res,column_name; 02354 GRANT_COLUMN *mem_check; 02355 /* As column name is a string, we don't have to supply a buffer */ 02356 res=col_privs->field[4]->val_str(&column_name); 02357 ulong priv= (ulong) col_privs->field[6]->val_int(); 02358 if (!(mem_check = new GRANT_COLUMN(*res, 02359 fix_rights_for_column(priv)))) 02360 { 02361 /* Don't use this entry */ 02362 privs = cols = 0; /* purecov: deadcode */ 02363 return; /* purecov: deadcode */ 02364 } 02365 my_hash_insert(&hash_columns, (byte *) mem_check); 02366 } while (!col_privs->file->index_next(col_privs->record[0]) && 02367 !key_cmp_if_same(col_privs,key,0,key_prefix_len)); 02368 col_privs->file->ha_index_end(); 02369 } 02370 } 02371 02372 02373 GRANT_TABLE::~GRANT_TABLE() 02374 { 02375 hash_free(&hash_columns); 02376 } 02377 02378 02379 static byte* get_grant_table(GRANT_NAME *buff,uint *length, 02380 my_bool not_used __attribute__((unused))) 02381 { 02382 *length=buff->key_length; 02383 return (byte*) buff->hash_key; 02384 } 02385 02386 02387 void free_grant_table(GRANT_TABLE *grant_table) 02388 { 02389 hash_free(&grant_table->hash_columns); 02390 } 02391 02392 02393 /* Search after a matching grant. Prefer exact grants before not exact ones */ 02394 02395 static GRANT_NAME *name_hash_search(HASH *name_hash, 02396 const char *host,const char* ip, 02397 const char *db, 02398 const char *user, const char *tname, 02399 bool exact) 02400 { 02401 char helping [NAME_LEN*2+USERNAME_LENGTH+3]; 02402 uint len; 02403 GRANT_NAME *grant_name,*found=0; 02404 HASH_SEARCH_STATE state; 02405 02406 len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; 02407 for (grant_name= (GRANT_NAME*) hash_first(name_hash, (byte*) helping, 02408 len, &state); 02409 grant_name ; 02410 grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping, 02411 len, &state)) 02412 { 02413 if (exact) 02414 { 02415 if (!grant_name->host.hostname || 02416 (host && 02417 !my_strcasecmp(system_charset_info, host, 02418 grant_name->host.hostname)) || 02419 (ip && !strcmp(ip, grant_name->host.hostname))) 02420 return grant_name; 02421 } 02422 else 02423 { 02424 if (compare_hostname(&grant_name->host, host, ip) && 02425 (!found || found->sort < grant_name->sort)) 02426 found=grant_name; // Host ok 02427 } 02428 } 02429 return found; 02430 } 02431 02432 02433 inline GRANT_NAME * 02434 routine_hash_search(const char *host, const char *ip, const char *db, 02435 const char *user, const char *tname, bool proc, bool exact) 02436 { 02437 return (GRANT_TABLE*) 02438 name_hash_search(proc ? &proc_priv_hash : &func_priv_hash, 02439 host, ip, db, user, tname, exact); 02440 } 02441 02442 02443 inline GRANT_TABLE * 02444 table_hash_search(const char *host, const char *ip, const char *db, 02445 const char *user, const char *tname, bool exact) 02446 { 02447 return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db, 02448 user, tname, exact); 02449 } 02450 02451 02452 inline GRANT_COLUMN * 02453 column_hash_search(GRANT_TABLE *t, const char *cname, uint length) 02454 { 02455 return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length); 02456 } 02457 02458 02459 static int replace_column_table(GRANT_TABLE *g_t, 02460 TABLE *table, const LEX_USER &combo, 02461 List <LEX_COLUMN> &columns, 02462 const char *db, const char *table_name, 02463 ulong rights, bool revoke_grant) 02464 { 02465 int error=0,result=0; 02466 byte key[MAX_KEY_LENGTH]; 02467 uint key_prefix_length; 02468 KEY_PART_INFO *key_part= table->key_info->key_part; 02469 DBUG_ENTER("replace_column_table"); 02470 02471 table->use_all_columns(); 02472 table->field[0]->store(combo.host.str,combo.host.length, 02473 system_charset_info); 02474 table->field[1]->store(db,(uint) strlen(db), 02475 system_charset_info); 02476 table->field[2]->store(combo.user.str,combo.user.length, 02477 system_charset_info); 02478 table->field[3]->store(table_name,(uint) strlen(table_name), 02479 system_charset_info); 02480 02481 /* Get length of 3 first key parts */ 02482 key_prefix_length= (key_part[0].store_length + key_part[1].store_length + 02483 key_part[2].store_length + key_part[3].store_length); 02484 key_copy(key, table->record[0], table->key_info, key_prefix_length); 02485 02486 rights&= COL_ACLS; // Only ACL for columns 02487 02488 /* first fix privileges for all columns in column list */ 02489 02490 List_iterator <LEX_COLUMN> iter(columns); 02491 class LEX_COLUMN *column; 02492 table->file->ha_index_init(0, 1); 02493 while ((column= iter++)) 02494 { 02495 ulong privileges= column->rights; 02496 bool old_row_exists=0; 02497 byte user_key[MAX_KEY_LENGTH]; 02498 02499 key_restore(table->record[0],key,table->key_info, 02500 key_prefix_length); 02501 table->field[4]->store(column->column.ptr(), column->column.length(), 02502 system_charset_info); 02503 /* Get key for the first 4 columns */ 02504 key_copy(user_key, table->record[0], table->key_info, 02505 table->key_info->key_length); 02506 02507 if (table->file->index_read(table->record[0], user_key, 02508 table->key_info->key_length, 02509 HA_READ_KEY_EXACT)) 02510 { 02511 if (revoke_grant) 02512 { 02513 my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0), 02514 combo.user.str, combo.host.str, 02515 table_name); /* purecov: inspected */ 02516 result= -1; /* purecov: inspected */ 02517 continue; /* purecov: inspected */ 02518 } 02519 old_row_exists = 0; 02520 restore_record(table, s->default_values); // Get empty record 02521 key_restore(table->record[0],key,table->key_info, 02522 key_prefix_length); 02523 table->field[4]->store(column->column.ptr(),column->column.length(), 02524 system_charset_info); 02525 } 02526 else 02527 { 02528 ulong tmp= (ulong) table->field[6]->val_int(); 02529 tmp=fix_rights_for_column(tmp); 02530 02531 if (revoke_grant) 02532 privileges = tmp & ~(privileges | rights); 02533 else 02534 privileges |= tmp; 02535 old_row_exists = 1; 02536 store_record(table,record[1]); // copy original row 02537 } 02538 02539 table->field[6]->store((longlong) get_rights_for_column(privileges), TRUE); 02540 02541 if (old_row_exists) 02542 { 02543 GRANT_COLUMN *grant_column; 02544 if (privileges) 02545 error=table->file->ha_update_row(table->record[1],table->record[0]); 02546 else 02547 error=table->file->ha_delete_row(table->record[1]); 02548 if (error) 02549 { 02550 table->file->print_error(error,MYF(0)); /* purecov: inspected */ 02551 result= -1; /* purecov: inspected */ 02552 goto end; /* purecov: inspected */ 02553 } 02554 grant_column= column_hash_search(g_t, column->column.ptr(), 02555 column->column.length()); 02556 if (grant_column) // Should always be true 02557 grant_column->rights= privileges; // Update hash 02558 } 02559 else // new grant 02560 { 02561 GRANT_COLUMN *grant_column; 02562 if ((error=table->file->ha_write_row(table->record[0]))) 02563 { 02564 table->file->print_error(error,MYF(0)); /* purecov: inspected */ 02565 result= -1; /* purecov: inspected */ 02566 goto end; /* purecov: inspected */ 02567 } 02568 grant_column= new GRANT_COLUMN(column->column,privileges); 02569 my_hash_insert(&g_t->hash_columns,(byte*) grant_column); 02570 } 02571 } 02572 02573 /* 02574 If revoke of privileges on the table level, remove all such privileges 02575 for all columns 02576 */ 02577 02578 if (revoke_grant) 02579 { 02580 byte user_key[MAX_KEY_LENGTH]; 02581 key_copy(user_key, table->record[0], table->key_info, 02582 key_prefix_length); 02583 02584 if (table->file->index_read(table->record[0], user_key, 02585 key_prefix_length, 02586 HA_READ_KEY_EXACT)) 02587 goto end; 02588 02589 /* Scan through all rows with the same host,db,user and table */ 02590 do 02591 { 02592 ulong privileges = (ulong) table->field[6]->val_int(); 02593 privileges=fix_rights_for_column(privileges); 02594 store_record(table,record[1]); 02595 02596 if (privileges & rights) // is in this record the priv to be revoked ?? 02597 { 02598 GRANT_COLUMN *grant_column = NULL; 02599 char colum_name_buf[HOSTNAME_LENGTH+1]; 02600 String column_name(colum_name_buf,sizeof(colum_name_buf), 02601 system_charset_info); 02602 02603 privileges&= ~rights; 02604 table->field[6]->store((longlong) 02605 get_rights_for_column(privileges), TRUE); 02606 table->field[4]->val_str(&column_name); 02607 grant_column = column_hash_search(g_t, 02608 column_name.ptr(), 02609 column_name.length()); 02610 if (privileges) 02611 { 02612 int tmp_error; 02613 if ((tmp_error=table->file->ha_update_row(table->record[1], 02614 table->record[0]))) 02615 { /* purecov: deadcode */ 02616 table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */ 02617 result= -1; /* purecov: deadcode */ 02618 goto end; /* purecov: deadcode */ 02619 } 02620 if (grant_column) 02621 grant_column->rights = privileges; // Update hash 02622 } 02623 else 02624 { 02625 int tmp_error; 02626 if ((tmp_error = table->file->ha_delete_row(table->record[1]))) 02627 { /* purecov: deadcode */ 02628 table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */ 02629 result= -1; /* purecov: deadcode */ 02630 goto end; /* purecov: deadcode */ 02631 } 02632 if (grant_column) 02633 hash_delete(&g_t->hash_columns,(byte*) grant_column); 02634 } 02635 } 02636 } while (!table->file->index_next(table->record[0]) && 02637 !key_cmp_if_same(table, key, 0, key_prefix_length)); 02638 } 02639 02640 end: 02641 table->file->ha_index_end(); 02642 DBUG_RETURN(result); 02643 } 02644 02645 02646 static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, 02647 TABLE *table, const LEX_USER &combo, 02648 const char *db, const char *table_name, 02649 ulong rights, ulong col_rights, 02650 bool revoke_grant) 02651 { 02652 char grantor[USER_HOST_BUFF_SIZE]; 02653 int old_row_exists = 1; 02654 int error=0; 02655 ulong store_table_rights, store_col_rights; 02656 byte user_key[MAX_KEY_LENGTH]; 02657 DBUG_ENTER("replace_table_table"); 02658 02659 strxmov(grantor, thd->security_ctx->user, "@", 02660 thd->security_ctx->host_or_ip, NullS); 02661 02662 /* 02663 The following should always succeed as new users are created before 02664 this function is called! 02665 */ 02666 if (!find_acl_user(combo.host.str,combo.user.str, FALSE)) 02667 { 02668 my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), 02669 MYF(0)); /* purecov: deadcode */ 02670 DBUG_RETURN(-1); /* purecov: deadcode */ 02671 } 02672 02673 table->use_all_columns(); 02674 restore_record(table, s->default_values); // Get empty record 02675 table->field[0]->store(combo.host.str,combo.host.length, 02676 system_charset_info); 02677 table->field[1]->store(db,(uint) strlen(db), system_charset_info); 02678 table->field[2]->store(combo.user.str,combo.user.length, 02679 system_charset_info); 02680 table->field[3]->store(table_name,(uint) strlen(table_name), 02681 system_charset_info); 02682 store_record(table,record[1]); // store at pos 1 02683 key_copy(user_key, table->record[0], table->key_info, 02684 table->key_info->key_length); 02685 02686 if (table->file->index_read_idx(table->record[0], 0, 02687 user_key, table->key_info->key_length, 02688 HA_READ_KEY_EXACT)) 02689 { 02690 /* 02691 The following should never happen as we first check the in memory 02692 grant tables for the user. There is however always a small change that 02693 the user has modified the grant tables directly. 02694 */ 02695 if (revoke_grant) 02696 { // no row, no revoke 02697 my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0), 02698 combo.user.str, combo.host.str, 02699 table_name); /* purecov: deadcode */ 02700 DBUG_RETURN(-1); /* purecov: deadcode */ 02701 } 02702 old_row_exists = 0; 02703 restore_record(table,record[1]); // Get saved record 02704 } 02705 02706 store_table_rights= get_rights_for_table(rights); 02707 store_col_rights= get_rights_for_column(col_rights); 02708 if (old_row_exists) 02709 { 02710 ulong j,k; 02711 store_record(table,record[1]); 02712 j = (ulong) table->field[6]->val_int(); 02713 k = (ulong) table->field[7]->val_int(); 02714 02715 if (revoke_grant) 02716 { 02717 /* column rights are already fixed in mysql_table_grant */ 02718 store_table_rights=j & ~store_table_rights; 02719 } 02720 else 02721 { 02722 store_table_rights|= j; 02723 store_col_rights|= k; 02724 } 02725 } 02726 02727 table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info); 02728 table->field[6]->store((longlong) store_table_rights, TRUE); 02729 table->field[7]->store((longlong) store_col_rights, TRUE); 02730 rights=fix_rights_for_table(store_table_rights); 02731 col_rights=fix_rights_for_column(store_col_rights); 02732 02733 if (old_row_exists) 02734 { 02735 if (store_table_rights || store_col_rights) 02736 { 02737 if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) 02738 goto table_error; /* purecov: deadcode */ 02739 } 02740 else if ((error = table->file->ha_delete_row(table->record[1]))) 02741 goto table_error; /* purecov: deadcode */ 02742 } 02743 else 02744 { 02745 error=table->file->ha_write_row(table->record[0]); 02746 if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) 02747 goto table_error; /* purecov: deadcode */ 02748 } 02749 02750 if (rights | col_rights) 02751 { 02752 grant_table->privs= rights; 02753 grant_table->cols= col_rights; 02754 } 02755 else 02756 { 02757 hash_delete(&column_priv_hash,(byte*) grant_table); 02758 } 02759 DBUG_RETURN(0); 02760 02761 /* This should never happen */ 02762 table_error: 02763 table->file->print_error(error,MYF(0)); /* purecov: deadcode */ 02764 DBUG_RETURN(-1); /* purecov: deadcode */ 02765 } 02766 02767 02768 static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, 02769 TABLE *table, const LEX_USER &combo, 02770 const char *db, const char *routine_name, 02771 bool is_proc, ulong rights, bool revoke_grant) 02772 { 02773 char grantor[USER_HOST_BUFF_SIZE]; 02774 int old_row_exists= 1; 02775 int error=0; 02776 ulong store_proc_rights; 02777 DBUG_ENTER("replace_routine_table"); 02778 02779 if (!initialized) 02780 { 02781 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); 02782 DBUG_RETURN(-1); 02783 } 02784 02785 strxmov(grantor, thd->security_ctx->user, "@", 02786 thd->security_ctx->host_or_ip, NullS); 02787 02788 /* 02789 The following should always succeed as new users are created before 02790 this function is called! 02791 */ 02792 if (!find_acl_user(combo.host.str, combo.user.str, FALSE)) 02793 { 02794 my_error(ER_PASSWORD_NO_MATCH,MYF(0)); 02795 DBUG_RETURN(-1); 02796 } 02797 02798 table->use_all_columns(); 02799 restore_record(table, s->default_values); // Get empty record 02800 table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); 02801 table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1); 02802 table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); 02803 table->field[3]->store(routine_name,(uint) strlen(routine_name), 02804 &my_charset_latin1); 02805 table->field[4]->store((longlong)(is_proc ? 02806 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION), 02807 TRUE); 02808 store_record(table,record[1]); // store at pos 1 02809 02810 if (table->file->index_read_idx(table->record[0],0, 02811 (byte*) table->field[0]->ptr,0, 02812 HA_READ_KEY_EXACT)) 02813 { 02814 /* 02815 The following should never happen as we first check the in memory 02816 grant tables for the user. There is however always a small change that 02817 the user has modified the grant tables directly. 02818 */ 02819 if (revoke_grant) 02820 { // no row, no revoke 02821 my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), 02822 combo.user.str, combo.host.str, routine_name); 02823 DBUG_RETURN(-1); 02824 } 02825 old_row_exists= 0; 02826 restore_record(table,record[1]); // Get saved record 02827 } 02828 02829 store_proc_rights= get_rights_for_procedure(rights); 02830 if (old_row_exists) 02831 { 02832 ulong j; 02833 store_record(table,record[1]); 02834 j= (ulong) table->field[6]->val_int(); 02835 02836 if (revoke_grant) 02837 { 02838 /* column rights are already fixed in mysql_table_grant */ 02839 store_proc_rights=j & ~store_proc_rights; 02840 } 02841 else 02842 { 02843 store_proc_rights|= j; 02844 } 02845 } 02846 02847 table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1); 02848 table->field[6]->store((longlong) store_proc_rights, TRUE); 02849 rights=fix_rights_for_procedure(store_proc_rights); 02850 02851 if (old_row_exists) 02852 { 02853 if (store_proc_rights) 02854 { 02855 if ((error=table->file->ha_update_row(table->record[1],table->record[0]))) 02856 goto table_error; 02857 } 02858 else if ((error= table->file->ha_delete_row(table->record[1]))) 02859 goto table_error; 02860 } 02861 else 02862 { 02863 error=table->file->ha_write_row(table->record[0]); 02864 if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) 02865 goto table_error; 02866 } 02867 02868 if (rights) 02869 { 02870 grant_name->privs= rights; 02871 } 02872 else 02873 { 02874 hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name); 02875 } 02876 DBUG_RETURN(0); 02877 02878 /* This should never happen */ 02879 table_error: 02880 table->file->print_error(error,MYF(0)); 02881 DBUG_RETURN(-1); 02882 } 02883 02884 02885 /* 02886 Store table level and column level grants in the privilege tables 02887 02888 SYNOPSIS 02889 mysql_table_grant() 02890 thd Thread handle 02891 table_list List of tables to give grant 02892 user_list List of users to give grant 02893 columns List of columns to give grant 02894 rights Table level grant 02895 revoke_grant Set to 1 if this is a REVOKE command 02896 02897 RETURN 02898 FALSE ok 02899 TRUE error 02900 */ 02901 02902 bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, 02903 List <LEX_USER> &user_list, 02904 List <LEX_COLUMN> &columns, ulong rights, 02905 bool revoke_grant) 02906 { 02907 ulong column_priv= 0; 02908 List_iterator <LEX_USER> str_list (user_list); 02909 LEX_USER *Str, *tmp_Str; 02910 TABLE_LIST tables[3]; 02911 bool create_new_users=0; 02912 char *db_name, *table_name; 02913 DBUG_ENTER("mysql_table_grant"); 02914 02915 if (!initialized) 02916 { 02917 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), 02918 "--skip-grant-tables"); /* purecov: inspected */ 02919 DBUG_RETURN(TRUE); /* purecov: inspected */ 02920 } 02921 if (rights & ~TABLE_ACLS) 02922 { 02923 my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), 02924 MYF(0)); 02925 DBUG_RETURN(TRUE); 02926 } 02927 02928 if (!revoke_grant) 02929 { 02930 if (columns.elements) 02931 { 02932 class LEX_COLUMN *column; 02933 List_iterator <LEX_COLUMN> column_iter(columns); 02934 02935 if (open_and_lock_tables(thd, table_list)) 02936 DBUG_RETURN(TRUE); 02937 02938 while ((column = column_iter++)) 02939 { 02940 uint unused_field_idx= NO_CACHED_FIELD_INDEX; 02941 TABLE_LIST *dummy; 02942 Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(), 02943 column->column.length(), 02944 column->column.ptr(), NULL, NULL, 02945 NULL, TRUE, FALSE, 02946 &unused_field_idx, FALSE, &dummy); 02947 if (f == (Field*)0) 02948 { 02949 my_error(ER_BAD_FIELD_ERROR, MYF(0), 02950 column->column.c_ptr(), table_list->alias); 02951 DBUG_RETURN(TRUE); 02952 } 02953 if (f == (Field *)-1) 02954 DBUG_RETURN(TRUE); 02955 column_priv|= column->rights; 02956 } 02957 close_thread_tables(thd); 02958 } 02959 else 02960 { 02961 if (!(rights & CREATE_ACL)) 02962 { 02963 char buf[FN_REFLEN]; 02964 build_table_filename(buf, sizeof(buf), table_list->db, 02965 table_list->table_name, reg_ext, 0); 02966 fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS | 02967 MY_RETURN_REAL_PATH | MY_APPEND_EXT); 02968 if (access(buf,F_OK)) 02969 { 02970 my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias); 02971 DBUG_RETURN(TRUE); 02972 } 02973 } 02974 if (table_list->grant.want_privilege) 02975 { 02976 char command[128]; 02977 get_privilege_desc(command, sizeof(command), 02978 table_list->grant.want_privilege); 02979 my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), 02980 command, thd->security_ctx->priv_user, 02981 thd->security_ctx->host_or_ip, table_list->alias); 02982 DBUG_RETURN(-1); 02983 } 02984 } 02985 } 02986 02987 /* open the mysql.tables_priv and mysql.columns_priv tables */ 02988 02989 bzero((char*) &tables,sizeof(tables)); 02990 tables[0].alias=tables[0].table_name= (char*) "user"; 02991 tables[1].alias=tables[1].table_name= (char*) "tables_priv"; 02992 tables[2].alias=tables[2].table_name= (char*) "columns_priv"; 02993 tables[0].next_local= tables[0].next_global= tables+1; 02994 /* Don't open column table if we don't need it ! */ 02995 tables[1].next_local= 02996 tables[1].next_global= ((column_priv || 02997 (revoke_grant && 02998 ((rights & COL_ACLS) || columns.elements))) 02999 ? tables+2 : 0); 03000 tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE; 03001 tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; 03002 03003 #ifdef HAVE_REPLICATION 03004 /* 03005 GRANT and REVOKE are applied the slave in/exclusion rules as they are 03006 some kind of updates to the mysql.% tables. 03007 */ 03008 if (thd->slave_thread && rpl_filter->is_on()) 03009 { 03010 /* 03011 The tables must be marked "updating" so that tables_ok() takes them into 03012 account in tests. 03013 */ 03014 tables[0].updating= tables[1].updating= tables[2].updating= 1; 03015 if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) 03016 DBUG_RETURN(FALSE); 03017 } 03018 #endif 03019 03020 if (simple_open_n_lock_tables(thd,tables)) 03021 { // Should never happen 03022 close_thread_tables(thd); /* purecov: deadcode */ 03023 DBUG_RETURN(TRUE); /* purecov: deadcode */ 03024 } 03025 03026 if (!revoke_grant) 03027 create_new_users= test_if_create_new_users(thd); 03028 bool result= FALSE; 03029 rw_wrlock(&LOCK_grant); 03030 pthread_mutex_lock(&acl_cache->lock); 03031 MEM_ROOT *old_root= thd->mem_root; 03032 thd->mem_root= &memex; 03033 grant_version++; 03034 03035 while ((tmp_Str = str_list++)) 03036 { 03037 int error; 03038 GRANT_TABLE *grant_table; 03039 if (!(Str= get_current_user(thd, tmp_Str))) 03040 { 03041 result= TRUE; 03042 continue; 03043 } 03044 if (Str->host.length > HOSTNAME_LENGTH || 03045 Str->user.length > USERNAME_LENGTH) 03046 { 03047 my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER), 03048 MYF(0)); 03049 result= TRUE; 03050 continue; 03051 } 03052 /* Create user if needed */ 03053 error=replace_user_table(thd, tables[0].table, *Str, 03054 0, revoke_grant, create_new_users, 03055 test(thd->variables.sql_mode & 03056 MODE_NO_AUTO_CREATE_USER)); 03057 if (error) 03058 { 03059 result= TRUE; // Remember error 03060 continue; // Add next user 03061 } 03062 03063 db_name= (table_list->view_db.length ? 03064 table_list->view_db.str : 03065 table_list->db); 03066 table_name= (table_list->view_name.length ? 03067 table_list->view_name.str : 03068 table_list->table_name); 03069 03070 /* Find/create cached table grant */ 03071 grant_table= table_hash_search(Str->host.str, NullS, db_name, 03072 Str->user.str, table_name, 1); 03073 if (!grant_table) 03074 { 03075 if (revoke_grant) 03076 { 03077 my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0), 03078 Str->user.str, Str->host.str, table_list->table_name); 03079 result= TRUE; 03080 continue; 03081 } 03082 grant_table = new GRANT_TABLE (Str->host.str, db_name, 03083 Str->user.str, table_name, 03084 rights, 03085 column_priv); 03086 if (!grant_table) // end of memory 03087 { 03088 result= TRUE; /* purecov: deadcode */ 03089 continue; /* purecov: deadcode */ 03090 } 03091 my_hash_insert(&column_priv_hash,(byte*) grant_table); 03092 } 03093 03094 /* If revoke_grant, calculate the new column privilege for tables_priv */ 03095 if (revoke_grant) 03096 { 03097 class LEX_COLUMN *column; 03098 List_iterator <LEX_COLUMN> column_iter(columns); 03099 GRANT_COLUMN *grant_column; 03100 03101 /* Fix old grants */ 03102 while ((column = column_iter++)) 03103 { 03104 grant_column = column_hash_search(grant_table, 03105 column->column.ptr(), 03106 column->column.length()); 03107 if (grant_column) 03108 grant_column->rights&= ~(column->rights | rights); 03109 } 03110 /* scan trough all columns to get new column grant */ 03111 column_priv= 0; 03112 for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) 03113 { 03114 grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns, 03115 idx); 03116 grant_column->rights&= ~rights; // Fix other columns 03117 column_priv|= grant_column->rights; 03118 } 03119 } 03120 else 03121 { 03122 column_priv|= grant_table->cols; 03123 } 03124 03125 03126 /* update table and columns */ 03127 03128 if (replace_table_table(thd, grant_table, tables[1].table, *Str, 03129 db_name, table_name, 03130 rights, column_priv, revoke_grant)) 03131 { 03132 /* Should only happen if table is crashed */ 03133 result= TRUE; /* purecov: deadcode */ 03134 } 03135 else if (tables[2].table) 03136 { 03137 if ((replace_column_table(grant_table, tables[2].table, *Str, 03138 columns, 03139 db_name, table_name, 03140 rights, revoke_grant))) 03141 { 03142 result= TRUE; 03143 } 03144 } 03145 } 03146 grant_option=TRUE; 03147 thd->mem_root= old_root; 03148 pthread_mutex_unlock(&acl_cache->lock); 03149 rw_unlock(&LOCK_grant); 03150 if (!result) 03151 send_ok(thd); 03152 /* Tables are automatically closed */ 03153 DBUG_RETURN(result); 03154 } 03155 03156 03157 /* 03158 Store routine level grants in the privilege tables 03159 03160 SYNOPSIS 03161 mysql_routine_grant() 03162 thd Thread handle 03163 table_list List of routines to give grant 03164 is_proc true indicates routine list are procedures 03165 user_list List of users to give grant 03166 rights Table level grant 03167 revoke_grant Set to 1 if this is a REVOKE command 03168 03169 RETURN 03170 0 ok 03171 1 error 03172 */ 03173 03174 bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, 03175 List <LEX_USER> &user_list, ulong rights, 03176 bool revoke_grant, bool no_error) 03177 { 03178 List_iterator <LEX_USER> str_list (user_list); 03179 LEX_USER *Str, *tmp_Str; 03180 TABLE_LIST tables[2]; 03181 bool create_new_users=0, result=0; 03182 char *db_name, *table_name; 03183 DBUG_ENTER("mysql_routine_grant"); 03184 03185 if (!initialized) 03186 { 03187 if (!no_error) 03188 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), 03189 "--skip-grant-tables"); 03190 DBUG_RETURN(TRUE); 03191 } 03192 if (rights & ~PROC_ACLS) 03193 { 03194 if (!no_error) 03195 my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), 03196 MYF(0)); 03197 DBUG_RETURN(TRUE); 03198 } 03199 03200 if (!revoke_grant) 03201 { 03202 if (sp_exist_routines(thd, table_list, is_proc, no_error)<0) 03203 DBUG_RETURN(TRUE); 03204 } 03205 03206 /* open the mysql.user and mysql.procs_priv tables */ 03207 03208 bzero((char*) &tables,sizeof(tables)); 03209 tables[0].alias=tables[0].table_name= (char*) "user"; 03210 tables[1].alias=tables[1].table_name= (char*) "procs_priv"; 03211 tables[0].next_local= tables[0].next_global= tables+1; 03212 tables[0].lock_type=tables[1].lock_type=TL_WRITE; 03213 tables[0].db=tables[1].db=(char*) "mysql"; 03214 03215 #ifdef HAVE_REPLICATION 03216 /* 03217 GRANT and REVOKE are applied the slave in/exclusion rules as they are 03218 some kind of updates to the mysql.% tables. 03219 */ 03220 if (thd->slave_thread && rpl_filter->is_on()) 03221 { 03222 /* 03223 The tables must be marked "updating" so that tables_ok() takes them into 03224 account in tests. 03225 */ 03226 tables[0].updating= tables[1].updating= 1; 03227 if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) 03228 DBUG_RETURN(FALSE); 03229 } 03230 #endif 03231 03232 if (simple_open_n_lock_tables(thd,tables)) 03233 { // Should never happen 03234 close_thread_tables(thd); 03235 DBUG_RETURN(TRUE); 03236 } 03237 03238 if (!revoke_grant) 03239 create_new_users= test_if_create_new_users(thd); 03240 rw_wrlock(&LOCK_grant); 03241 pthread_mutex_lock(&acl_cache->lock); 03242 MEM_ROOT *old_root= thd->mem_root; 03243 thd->mem_root= &memex; 03244 03245 DBUG_PRINT("info",("now time to iterate and add users")); 03246 03247 while ((tmp_Str= str_list++)) 03248 { 03249 int error; 03250 GRANT_NAME *grant_name; 03251 if (!(Str= get_current_user(thd, tmp_Str))) 03252 { 03253 result= TRUE; 03254 continue; 03255 } 03256 if (Str->host.length > HOSTNAME_LENGTH || 03257 Str->user.length > USERNAME_LENGTH) 03258 { 03259 if (!no_error) 03260 my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER), 03261 MYF(0)); 03262 result= TRUE; 03263 continue; 03264 } 03265 /* Create user if needed */ 03266 error=replace_user_table(thd, tables[0].table, *Str, 03267 0, revoke_grant, create_new_users, 03268 test(thd->variables.sql_mode & 03269 MODE_NO_AUTO_CREATE_USER)); 03270 if (error) 03271 { 03272 result= TRUE; // Remember error 03273 continue; // Add next user 03274 } 03275 03276 db_name= table_list->db; 03277 table_name= table_list->table_name; 03278 03279 grant_name= routine_hash_search(Str->host.str, NullS, db_name, 03280 Str->user.str, table_name, is_proc, 1); 03281 if (!grant_name) 03282 { 03283 if (revoke_grant) 03284 { 03285 if (!no_error) 03286 my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), 03287 Str->user.str, Str->host.str, table_name); 03288 result= TRUE; 03289 continue; 03290 } 03291 grant_name= new GRANT_NAME(Str->host.str, db_name, 03292 Str->user.str, table_name, 03293 rights); 03294 if (!grant_name) 03295 { 03296 result= TRUE; 03297 continue; 03298 } 03299 my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name); 03300 } 03301 03302 if (replace_routine_table(thd, grant_name, tables[1].table, *Str, 03303 db_name, table_name, is_proc, rights, revoke_grant)) 03304 { 03305 result= TRUE; 03306 continue; 03307 } 03308 } 03309 grant_option=TRUE; 03310 thd->mem_root= old_root; 03311 pthread_mutex_unlock(&acl_cache->lock); 03312 rw_unlock(&LOCK_grant); 03313 if (!result && !no_error) 03314 send_ok(thd); 03315 /* Tables are automatically closed */ 03316 DBUG_RETURN(result); 03317 } 03318 03319 03320 bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, 03321 ulong rights, bool revoke_grant) 03322 { 03323 List_iterator <LEX_USER> str_list (list); 03324 LEX_USER *Str, *tmp_Str; 03325 char tmp_db[NAME_LEN+1]; 03326 bool create_new_users=0; 03327 TABLE_LIST tables[2]; 03328 DBUG_ENTER("mysql_grant"); 03329 if (!initialized) 03330 { 03331 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), 03332 "--skip-grant-tables"); /* purecov: tested */ 03333 DBUG_RETURN(TRUE); /* purecov: tested */ 03334 } 03335 03336 if (lower_case_table_names && db) 03337 { 03338 strmov(tmp_db,db); 03339 my_casedn_str(files_charset_info, tmp_db); 03340 db=tmp_db; 03341 } 03342 03343 /* open the mysql.user and mysql.db tables */ 03344 bzero((char*) &tables,sizeof(tables)); 03345 tables[0].alias=tables[0].table_name=(char*) "user"; 03346 tables[1].alias=tables[1].table_name=(char*) "db"; 03347 tables[0].next_local= tables[0].next_global= tables+1; 03348 tables[0].lock_type=tables[1].lock_type=TL_WRITE; 03349 tables[0].db=tables[1].db=(char*) "mysql"; 03350 03351 #ifdef HAVE_REPLICATION 03352 /* 03353 GRANT and REVOKE are applied the slave in/exclusion rules as they are 03354 some kind of updates to the mysql.% tables. 03355 */ 03356 if (thd->slave_thread && rpl_filter->is_on()) 03357 { 03358 /* 03359 The tables must be marked "updating" so that tables_ok() takes them into 03360 account in tests. 03361 */ 03362 tables[0].updating= tables[1].updating= 1; 03363 if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) 03364 DBUG_RETURN(FALSE); 03365 } 03366 #endif 03367 03368 if (simple_open_n_lock_tables(thd,tables)) 03369 { // This should never happen 03370 close_thread_tables(thd); /* purecov: deadcode */ 03371 DBUG_RETURN(TRUE); /* purecov: deadcode */ 03372 } 03373 03374 if (!revoke_grant) 03375 create_new_users= test_if_create_new_users(thd); 03376 03377 /* go through users in user_list */ 03378 rw_wrlock(&LOCK_grant); 03379 VOID(pthread_mutex_lock(&acl_cache->lock)); 03380 grant_version++; 03381 03382 int result=0; 03383 while ((tmp_Str = str_list++)) 03384 { 03385 if (!(Str= get_current_user(thd, tmp_Str))) 03386 { 03387 result= TRUE; 03388 continue; 03389 } 03390 if (Str->host.length > HOSTNAME_LENGTH || 03391 Str->user.length > USERNAME_LENGTH) 03392 { 03393 my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER), 03394 MYF(0)); 03395 result= -1; 03396 continue; 03397 } 03398 if (replace_user_table(thd, tables[0].table, *Str, 03399 (!db ? rights : 0), revoke_grant, create_new_users, 03400 test(thd->variables.sql_mode & 03401 MODE_NO_AUTO_CREATE_USER))) 03402 result= -1; 03403 else if (db) 03404 { 03405 ulong db_rights= rights & DB_ACLS; 03406 if (db_rights == rights) 03407 { 03408 if (replace_db_table(tables[1].table, db, *Str, db_rights, 03409 revoke_grant)) 03410 result= -1; 03411 } 03412 else 03413 { 03414 my_error(ER_WRONG_USAGE, MYF(0), "DB GRANT", "GLOBAL PRIVILEGES"); 03415 result= -1; 03416 } 03417 } 03418 } 03419 VOID(pthread_mutex_unlock(&acl_cache->lock)); 03420 rw_unlock(&LOCK_grant); 03421 close_thread_tables(thd); 03422 03423 if (!result) 03424 send_ok(thd); 03425 DBUG_RETURN(result); 03426 } 03427 03428 03429 /* Free grant array if possible */ 03430 03431 void grant_free(void) 03432 { 03433 DBUG_ENTER("grant_free"); 03434 grant_option = FALSE; 03435 hash_free(&column_priv_hash); 03436 hash_free(&proc_priv_hash); 03437 hash_free(&func_priv_hash); 03438 free_root(&memex,MYF(0)); 03439 DBUG_VOID_RETURN; 03440 } 03441 03442 03443 /* 03444 Initialize structures responsible for table/column-level privilege checking 03445 and load information for them from tables in the 'mysql' database. 03446 03447 SYNOPSIS 03448 grant_init() 03449 03450 RETURN VALUES 03451 0 ok 03452 1 Could not initialize grant's 03453 */ 03454 03455 my_bool grant_init() 03456 { 03457 THD *thd; 03458 my_bool return_val; 03459 DBUG_ENTER("grant_init"); 03460 03461 if (!(thd= new THD)) 03462 DBUG_RETURN(1); /* purecov: deadcode */ 03463 thd->thread_stack= (char*) &thd; 03464 thd->store_globals(); 03465 return_val= grant_reload(thd); 03466 delete thd; 03467 /* Remember that we don't have a THD */ 03468 my_pthread_setspecific_ptr(THR_THD, 0); 03469 DBUG_RETURN(return_val); 03470 } 03471 03472 03473 /* 03474 Initialize structures responsible for table/column-level privilege 03475 checking and load information about grants from open privilege tables. 03476 03477 SYNOPSIS 03478 grant_load() 03479 thd Current thread 03480 tables List containing open "mysql.tables_priv" and 03481 "mysql.columns_priv" tables. 03482 03483 RETURN VALUES 03484 FALSE - success 03485 TRUE - error 03486 */ 03487 03488 static my_bool grant_load(TABLE_LIST *tables) 03489 { 03490 MEM_ROOT *memex_ptr; 03491 my_bool return_val= 1; 03492 TABLE *t_table, *c_table, *p_table; 03493 bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; 03494 MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, 03495 THR_MALLOC); 03496 DBUG_ENTER("grant_load"); 03497 03498 grant_option = FALSE; 03499 (void) hash_init(&column_priv_hash,system_charset_info, 03500 0,0,0, (hash_get_key) get_grant_table, 03501 (hash_free_key) free_grant_table,0); 03502 (void) hash_init(&proc_priv_hash,system_charset_info, 03503 0,0,0, (hash_get_key) get_grant_table, 03504 0,0); 03505 (void) hash_init(&func_priv_hash,system_charset_info, 03506 0,0,0, (hash_get_key) get_grant_table, 03507 0,0); 03508 init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); 03509 03510 t_table = tables[0].table; 03511 c_table = tables[1].table; 03512 p_table= tables[2].table; 03513 t_table->file->ha_index_init(0, 1); 03514 p_table->file->ha_index_init(0, 1); 03515 t_table->use_all_columns(); 03516 c_table->use_all_columns(); 03517 p_table->use_all_columns(); 03518 if (!t_table->file->index_first(t_table->record[0])) 03519 { 03520 memex_ptr= &memex; 03521 my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); 03522 do 03523 { 03524 GRANT_TABLE *mem_check; 03525 if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table))) 03526 { 03527 /* This could only happen if we are out memory */ 03528 grant_option= FALSE; 03529 goto end_unlock; 03530 } 03531 03532 if (check_no_resolve) 03533 { 03534 if (hostname_requires_resolving(mem_check->host.hostname)) 03535 { 03536 sql_print_warning("'tables_priv' entry '%s %s@%s' " 03537 "ignored in --skip-name-resolve mode.", 03538 mem_check->tname, 03539 mem_check->user ? mem_check->user : "", 03540 mem_check->host.hostname ? 03541 mem_check->host.hostname : ""); 03542 continue; 03543 } 03544 } 03545 03546 if (! mem_check->ok()) 03547 delete mem_check; 03548 else if (my_hash_insert(&column_priv_hash,(byte*) mem_check)) 03549 { 03550 delete mem_check; 03551 grant_option= FALSE; 03552 goto end_unlock; 03553 } 03554 } 03555 while (!t_table->file->index_next(t_table->record[0])); 03556 } 03557 if (!p_table->file->index_first(p_table->record[0])) 03558 { 03559 memex_ptr= &memex; 03560 my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr); 03561 do 03562 { 03563 GRANT_NAME *mem_check; 03564 HASH *hash; 03565 if (!(mem_check=new (&memex) GRANT_NAME(p_table))) 03566 { 03567 /* This could only happen if we are out memory */ 03568 grant_option= FALSE; 03569 goto end_unlock; 03570 } 03571 03572 if (check_no_resolve) 03573 { 03574 if (hostname_requires_resolving(mem_check->host.hostname)) 03575 { 03576 sql_print_warning("'procs_priv' entry '%s %s@%s' " 03577 "ignored in --skip-name-resolve mode.", 03578 mem_check->tname, mem_check->user, 03579 mem_check->host.hostname ? 03580 mem_check->host.hostname : ""); 03581 continue; 03582 } 03583 } 03584 if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE) 03585 { 03586 hash= &proc_priv_hash; 03587 } 03588 else 03589 if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION) 03590 { 03591 hash= &func_priv_hash; 03592 } 03593 else 03594 { 03595 sql_print_warning("'procs_priv' entry '%s' " 03596 "ignored, bad routine type", 03597 mem_check->tname); 03598 continue; 03599 } 03600 03601 mem_check->privs= fix_rights_for_procedure(mem_check->privs); 03602 if (! mem_check->ok()) 03603 delete mem_check; 03604 else if (my_hash_insert(hash, (byte*) mem_check)) 03605 { 03606 delete mem_check; 03607 grant_option= FALSE; 03608 goto end_unlock; 03609 } 03610 } 03611 while (!p_table->file->index_next(p_table->record[0])); 03612 } 03613 grant_option= TRUE; 03614 return_val=0; // Return ok 03615 03616 end_unlock: 03617 t_table->file->ha_index_end(); 03618 p_table->file->ha_index_end(); 03619 my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); 03620 DBUG_RETURN(return_val); 03621 } 03622 03623 03624 /* 03625 Reload information about table and column level privileges if possible. 03626 03627 SYNOPSIS 03628 grant_reload() 03629 thd Current thread 03630 03631 NOTES 03632 Locked tables are checked by acl_reload() and doesn't have to be checked 03633 in this call. 03634 This function is also used for initialization of structures responsible 03635 for table/column-level privilege checking. 03636 03637 RETURN VALUE 03638 FALSE Success 03639 TRUE Error 03640 */ 03641 03642 my_bool grant_reload(THD *thd) 03643 { 03644 TABLE_LIST tables[3]; 03645 HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash; 03646 bool old_grant_option; 03647 MEM_ROOT old_mem; 03648 my_bool return_val= 1; 03649 DBUG_ENTER("grant_reload"); 03650 03651 /* Don't do anything if running with --skip-grant-tables */ 03652 if (!initialized) 03653 DBUG_RETURN(0); 03654 03655 bzero((char*) tables, sizeof(tables)); 03656 tables[0].alias= tables[0].table_name= (char*) "tables_priv"; 03657 tables[1].alias= tables[1].table_name= (char*) "columns_priv"; 03658 tables[2].alias= tables[2].table_name= (char*) "procs_priv"; 03659 tables[0].db= tables[1].db= tables[2].db= (char *) "mysql"; 03660 tables[0].next_local= tables[0].next_global= tables+1; 03661 tables[1].next_local= tables[1].next_global= tables+2; 03662 tables[0].lock_type= tables[1].lock_type= tables[2].lock_type= TL_READ; 03663 03664 /* 03665 To avoid deadlocks we should obtain table locks before 03666 obtaining LOCK_grant rwlock. 03667 */ 03668 if (simple_open_n_lock_tables(thd, tables)) 03669 goto end; 03670 03671 rw_wrlock(&LOCK_grant); 03672 grant_version++; 03673 old_column_priv_hash= column_priv_hash; 03674 old_proc_priv_hash= proc_priv_hash; 03675 old_func_priv_hash= func_priv_hash; 03676 old_grant_option= grant_option; 03677 old_mem= memex; 03678 03679 if ((return_val= grant_load(tables))) 03680 { // Error. Revert to old hash 03681 DBUG_PRINT("error",("Reverting to old privileges")); 03682 grant_free(); /* purecov: deadcode */ 03683 column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ 03684 proc_priv_hash= old_proc_priv_hash; 03685 func_priv_hash= old_func_priv_hash; 03686 grant_option= old_grant_option; /* purecov: deadcode */ 03687 memex= old_mem; /* purecov: deadcode */ 03688 } 03689 else 03690 { 03691 hash_free(&old_column_priv_hash); 03692 hash_free(&old_proc_priv_hash); 03693 hash_free(&old_func_priv_hash); 03694 free_root(&old_mem,MYF(0)); 03695 } 03696 rw_unlock(&LOCK_grant); 03697 end: 03698 close_thread_tables(thd); 03699 DBUG_RETURN(return_val); 03700 } 03701 03702 03703 /**************************************************************************** 03704 Check table level grants 03705 03706 SYNOPSIS 03707 bool check_grant() 03708 thd Thread handler 03709 want_access Bits of privileges user needs to have 03710 tables List of tables to check. The user should have 'want_access' 03711 to all tables in list. 03712 show_table <> 0 if we are in show table. In this case it's enough to have 03713 any privilege for the table 03714 number Check at most this number of tables. 03715 no_errors If 0 then we write an error. The error is sent directly to 03716 the client 03717 03718 RETURN 03719 0 ok 03720 1 Error: User did not have the requested privileges 03721 03722 NOTE 03723 This functions assumes that either number of tables to be inspected 03724 by it is limited explicitly (i.e. is is not UINT_MAX) or table list 03725 used and thd->lex->query_tables_own_last value correspond to each 03726 other (the latter should be either 0 or point to next_global member 03727 of one of elements of this table list). 03728 ****************************************************************************/ 03729 03730 bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, 03731 uint show_table, uint number, bool no_errors) 03732 { 03733 TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table(); 03734 Security_context *sctx= thd->security_ctx; 03735 uint i; 03736 ulong orig_want_access= want_access; 03737 DBUG_ENTER("check_grant"); 03738 DBUG_ASSERT(number > 0); 03739 03740 /* 03741 Walk through the list of tables that belong to the query and save the 03742 requested access (orig_want_privilege) to be able to use it when 03743 checking access rights to the underlying tables of a view. Our grant 03744 system gradually eliminates checked bits from want_privilege and thus 03745 after all checks are done we can no longer use it. 03746 The check that first_not_own_table is not reached is for the case when 03747 the given table list refers to the list for prelocking (contains tables 03748 of other queries). For simple queries first_not_own_table is 0. 03749 */ 03750 for (i= 0, table= tables; 03751 table != first_not_own_table && i < number; 03752 table= table->next_global, i++) 03753 { 03754 /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ 03755 table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); 03756 } 03757 03758 rw_rdlock(&LOCK_grant); 03759 for (table= tables; 03760 table && number-- && table != first_not_own_table; 03761 table= table->next_global) 03762 { 03763 GRANT_TABLE *grant_table; 03764 sctx = test(table->security_ctx) ? 03765 table->security_ctx : thd->security_ctx; 03766 03767 want_access= orig_want_access; 03768 want_access&= ~sctx->master_access; 03769 if (!want_access) 03770 continue; // ok 03771 03772 if (!(~table->grant.privilege & want_access) || 03773 table->derived || table->schema_table) 03774 { 03775 /* 03776 It is subquery in the FROM clause. VIEW set table->derived after 03777 table opening, but this function always called before table opening. 03778 */ 03779 if (!table->referencing_view) 03780 { 03781 /* 03782 If it's a temporary table created for a subquery in the FROM 03783 clause, or an INFORMATION_SCHEMA table, drop the request for 03784 a privilege. 03785 */ 03786 table->grant.want_privilege= 0; 03787 } 03788 continue; 03789 } 03790 if (!(grant_table= table_hash_search(sctx->host, sctx->ip, 03791 table->db, sctx->priv_user, 03792 table->table_name,0))) 03793 { 03794 want_access &= ~table->grant.privilege; 03795 goto err; // No grants 03796 } 03797 if (show_table) 03798 continue; // We have some priv on this 03799 03800 table->grant.grant_table=grant_table; // Remember for column test 03801 table->grant.version=grant_version; 03802 table->grant.privilege|= grant_table->privs; 03803 table->grant.want_privilege= ((want_access & COL_ACLS) 03804 & ~table->grant.privilege); 03805 03806 if (!(~table->grant.privilege & want_access)) 03807 continue; 03808 03809 if (want_access & ~(grant_table->cols | table->grant.privilege)) 03810 { 03811 want_access &= ~(grant_table->cols | table->grant.privilege); 03812 goto err; // impossible 03813 } 03814 } 03815 rw_unlock(&LOCK_grant); 03816 DBUG_RETURN(0); 03817 03818 err: 03819 rw_unlock(&LOCK_grant); 03820 if (!no_errors) // Not a silent skip of table 03821 { 03822 char command[128]; 03823 get_privilege_desc(command, sizeof(command), want_access); 03824 my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), 03825 command, 03826 sctx->priv_user, 03827 sctx->host_or_ip, 03828 table ? table->table_name : "unknown"); 03829 } 03830 DBUG_RETURN(1); 03831 } 03832 03833 03834 /* 03835 Check column rights in given security context 03836 03837 SYNOPSIS 03838 check_grant_column() 03839 thd thread handler 03840 grant grant information structure 03841 db_name db name 03842 table_name table name 03843 name column name 03844 length column name length 03845 sctx security context 03846 03847 RETURN 03848 FALSE OK 03849 TRUE access denied 03850 */ 03851 03852 bool check_grant_column(THD *thd, GRANT_INFO *grant, 03853 const char *db_name, const char *table_name, 03854 const char *name, uint length, Security_context *sctx) 03855 { 03856 GRANT_TABLE *grant_table; 03857 GRANT_COLUMN *grant_column; 03858 ulong want_access= grant->want_privilege & ~grant->privilege; 03859 DBUG_ENTER("check_grant_column"); 03860 DBUG_PRINT("enter", ("table: %s want_access: %u", table_name, want_access)); 03861 03862 if (!want_access) 03863 DBUG_RETURN(0); // Already checked 03864 03865 rw_rdlock(&LOCK_grant); 03866 03867 /* reload table if someone has modified any grants */ 03868 03869 if (grant->version != grant_version) 03870 { 03871 grant->grant_table= 03872 table_hash_search(sctx->host, sctx->ip, db_name, 03873 sctx->priv_user, 03874 table_name, 0); /* purecov: inspected */ 03875 grant->version= grant_version; /* purecov: inspected */ 03876 } 03877 if (!(grant_table= grant->grant_table)) 03878 goto err; /* purecov: deadcode */ 03879 03880 grant_column=column_hash_search(grant_table, name, length); 03881 if (grant_column && !(~grant_column->rights & want_access)) 03882 { 03883 rw_unlock(&LOCK_grant); 03884 DBUG_RETURN(0); 03885 } 03886 03887 err: 03888 rw_unlock(&LOCK_grant); 03889 char command[128]; 03890 get_privilege_desc(command, sizeof(command), want_access); 03891 my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), 03892 command, 03893 sctx->priv_user, 03894 sctx->host_or_ip, 03895 name, 03896 table_name); 03897 DBUG_RETURN(1); 03898 } 03899 03900 03901 /* 03902 Check the access right to a column depending on the type of table. 03903 03904 SYNOPSIS 03905 check_column_grant_in_table_ref() 03906 thd thread handler 03907 table_ref table reference where to check the field 03908 name name of field to check 03909 length length of name 03910 03911 DESCRIPTION 03912 Check the access rights to a column depending on the type of table 03913 reference where the column is checked. The function provides a 03914 generic interface to check column access rights that hides the 03915 heterogeneity of the column representation - whether it is a view 03916 or a stored table colum. 03917 03918 RETURN 03919 FALSE OK 03920 TRUE access denied 03921 */ 03922 03923 bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, 03924 const char *name, uint length) 03925 { 03926 GRANT_INFO *grant; 03927 const char *db_name; 03928 const char *table_name; 03929 Security_context *sctx= test(table_ref->security_ctx) ? 03930 table_ref->security_ctx : thd->security_ctx; 03931 03932 if (table_ref->view || table_ref->field_translation) 03933 { 03934 /* View or derived information schema table. */ 03935 ulong view_privs; 03936 grant= &(table_ref->grant); 03937 db_name= table_ref->view_db.str; 03938 table_name= table_ref->view_name.str; 03939 if (table_ref->belong_to_view && 03940 (thd->lex->sql_command == SQLCOM_SHOW_FIELDS || 03941 thd->lex->sql_command == SQLCOM_SHOW_CREATE)) 03942 { 03943 view_privs= get_column_grant(thd, grant, db_name, table_name, name); 03944 if (view_privs & VIEW_ANY_ACL) 03945 { 03946 table_ref->belong_to_view->allowed_show= TRUE; 03947 return FALSE; 03948 } 03949 table_ref->belong_to_view->allowed_show= FALSE; 03950 my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0)); 03951 return TRUE; 03952 } 03953 } 03954 else 03955 { 03956 /* Normal or temporary table. */ 03957 TABLE *table= table_ref->table; 03958 grant= &(table->grant); 03959 db_name= table->s->db.str; 03960 table_name= table->s->table_name.str; 03961 } 03962 03963 if (grant->want_privilege) 03964 return check_grant_column(thd, grant, db_name, table_name, name, 03965 length, sctx); 03966 else 03967 return FALSE; 03968 03969 } 03970 03971 03972 bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, 03973 const char* db_name, const char *table_name, 03974 Field_iterator *fields) 03975 { 03976 Security_context *sctx= thd->security_ctx; 03977 GRANT_TABLE *grant_table; 03978 GRANT_COLUMN *grant_column; 03979 03980 want_access &= ~grant->privilege; 03981 if (!want_access) 03982 return 0; // Already checked 03983 if (!grant_option) 03984 goto err2; 03985 03986 rw_rdlock(&LOCK_grant); 03987 03988 /* reload table if someone has modified any grants */ 03989 03990 if (grant->version != grant_version) 03991 { 03992 grant->grant_table= 03993 table_hash_search(sctx->host, sctx->ip, db_name, 03994 sctx->priv_user, 03995 table_name, 0); /* purecov: inspected */ 03996 grant->version= grant_version; /* purecov: inspected */ 03997 } 03998 /* The following should always be true */ 03999 if (!(grant_table= grant->grant_table)) 04000 goto err; /* purecov: inspected */ 04001 04002 for (; !fields->end_of_fields(); fields->next()) 04003 { 04004 const char *field_name= fields->name(); 04005 grant_column= column_hash_search(grant_table, field_name, 04006 (uint) strlen(field_name)); 04007 if (!grant_column || (~grant_column->rights & want_access)) 04008 goto err; 04009 } 04010 rw_unlock(&LOCK_grant); 04011 return 0; 04012 04013 err: 04014 rw_unlock(&LOCK_grant); 04015 err2: 04016 char command[128]; 04017 get_privilege_desc(command, sizeof(command), want_access); 04018 my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), 04019 command, 04020 sctx->priv_user, 04021 sctx->host_or_ip, 04022 fields->name(), 04023 table_name); 04024 return 1; 04025 } 04026 04027 04028 /* 04029 Check if a user has the right to access a database 04030 Access is accepted if he has a grant for any table/routine in the database 04031 Return 1 if access is denied 04032 */ 04033 04034 bool check_grant_db(THD *thd,const char *db) 04035 { 04036 Security_context *sctx= thd->security_ctx; 04037 char helping [NAME_LEN+USERNAME_LENGTH+2]; 04038 uint len; 04039 bool error= 1; 04040 04041 len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; 04042 rw_rdlock(&LOCK_grant); 04043 04044 for (uint idx=0 ; idx < column_priv_hash.records ; idx++) 04045 { 04046 GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, 04047 idx); 04048 if (len < grant_table->key_length && 04049 !memcmp(grant_table->hash_key,helping,len) && 04050 compare_hostname(&grant_table->host, sctx->host, sctx->ip)) 04051 { 04052 error=0; // Found match 04053 break; 04054 } 04055 } 04056 rw_unlock(&LOCK_grant); 04057 return error; 04058 } 04059 04060 04061 /**************************************************************************** 04062 Check routine level grants 04063 04064 SYNPOSIS 04065 bool check_grant_routine() 04066 thd Thread handler 04067 want_access Bits of privileges user needs to have 04068 procs List of routines to check. The user should have 'want_access' 04069 is_proc True if the list is all procedures, else functions 04070 no_errors If 0 then we write an error. The error is sent directly to 04071 the client 04072 04073 RETURN 04074 0 ok 04075 1 Error: User did not have the requested privielges 04076 ****************************************************************************/ 04077 04078 bool check_grant_routine(THD *thd, ulong want_access, 04079 TABLE_LIST *procs, bool is_proc, bool no_errors) 04080 { 04081 TABLE_LIST *table; 04082 Security_context *sctx= thd->security_ctx; 04083 char *user= sctx->priv_user; 04084 char *host= sctx->priv_host; 04085 DBUG_ENTER("check_grant_routine"); 04086 04087 want_access&= ~sctx->master_access; 04088 if (!want_access) 04089 DBUG_RETURN(0); // ok 04090 04091 rw_rdlock(&LOCK_grant); 04092 for (table= procs; table; table= table->next_global) 04093 { 04094 GRANT_NAME *grant_proc; 04095 if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user, 04096 table->table_name, is_proc, 0))) 04097 table->grant.privilege|= grant_proc->privs; 04098 04099 if (want_access & ~table->grant.privilege) 04100 { 04101 want_access &= ~table->grant.privilege; 04102 goto err; 04103 } 04104 } 04105 rw_unlock(&LOCK_grant); 04106 DBUG_RETURN(0); 04107 err: 04108 rw_unlock(&LOCK_grant); 04109 if (!no_errors) 04110 { 04111 char buff[1024]; 04112 const char *command=""; 04113 if (table) 04114 strxmov(buff, table->db, ".", table->table_name, NullS); 04115 if (want_access & EXECUTE_ACL) 04116 command= "execute"; 04117 else if (want_access & ALTER_PROC_ACL) 04118 command= "alter routine"; 04119 else if (want_access & GRANT_ACL) 04120 command= "grant"; 04121 my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0), 04122 command, user, host, table ? buff : "unknown"); 04123 } 04124 DBUG_RETURN(1); 04125 } 04126 04127 04128 /* 04129 Check if routine has any of the 04130 routine level grants 04131 04132 SYNPOSIS 04133 bool check_routine_level_acl() 04134 thd Thread handler 04135 db Database name 04136 name Routine name 04137 04138 RETURN 04139 0 Ok 04140 1 error 04141 */ 04142 04143 bool check_routine_level_acl(THD *thd, const char *db, const char *name, 04144 bool is_proc) 04145 { 04146 bool no_routine_acl= 1; 04147 if (grant_option) 04148 { 04149 GRANT_NAME *grant_proc; 04150 Security_context *sctx= thd->security_ctx; 04151 rw_rdlock(&LOCK_grant); 04152 if ((grant_proc= routine_hash_search(sctx->priv_host, 04153 sctx->ip, db, 04154 sctx->priv_user, 04155 name, is_proc, 0))) 04156 no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); 04157 rw_unlock(&LOCK_grant); 04158 } 04159 return no_routine_acl; 04160 } 04161 04162 04163 /***************************************************************************** 04164 Functions to retrieve the grant for a table/column (for SHOW functions) 04165 *****************************************************************************/ 04166 04167 ulong get_table_grant(THD *thd, TABLE_LIST *table) 04168 { 04169 ulong privilege; 04170 Security_context *sctx= thd->security_ctx; 04171 const char *db = table->db ? table->db : thd->db; 04172 GRANT_TABLE *grant_table; 04173 04174 rw_rdlock(&LOCK_grant); 04175 #ifdef EMBEDDED_LIBRARY 04176 grant_table= NULL; 04177 #else 04178 grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user, 04179 table->table_name, 0); 04180 #endif 04181 table->grant.grant_table=grant_table; // Remember for column test 04182 table->grant.version=grant_version; 04183 if (grant_table) 04184 table->grant.privilege|= grant_table->privs; 04185 privilege= table->grant.privilege; 04186 rw_unlock(&LOCK_grant); 04187 return privilege; 04188 } 04189 04190 04191 /* 04192 Determine the access priviliges for a field. 04193 04194 SYNOPSIS 04195 get_column_grant() 04196 thd thread handler 04197 grant grants table descriptor 04198 db_name name of database that the field belongs to 04199 table_name name of table that the field belongs to 04200 field_name name of field 04201 04202 DESCRIPTION 04203 The procedure may also modify: grant->grant_table and grant->version. 04204 04205 RETURN 04206 The access priviliges for the field db_name.table_name.field_name 04207 */ 04208 04209 ulong get_column_grant(THD *thd, GRANT_INFO *grant, 04210 const char *db_name, const char *table_name, 04211 const char *field_name) 04212 { 04213 GRANT_TABLE *grant_table; 04214 GRANT_COLUMN *grant_column; 04215 ulong priv; 04216 04217 rw_rdlock(&LOCK_grant); 04218 /* reload table if someone has modified any grants */ 04219 if (grant->version != grant_version) 04220 { 04221 Security_context *sctx= thd->security_ctx; 04222 grant->grant_table= 04223 table_hash_search(sctx->host, sctx->ip, 04224 db_name, sctx->priv_user, 04225 table_name, 0); /* purecov: inspected */ 04226 grant->version= grant_version; /* purecov: inspected */ 04227 } 04228 04229 if (!(grant_table= grant->grant_table)) 04230 priv= grant->privilege; 04231 else 04232 { 04233 grant_column= column_hash_search(grant_table, field_name, 04234 (uint) strlen(field_name)); 04235 if (!grant_column) 04236 priv= (grant->privilege | grant_table->privs); 04237 else 04238 priv= (grant->privilege | grant_table->privs | grant_column->rights); 04239 } 04240 rw_unlock(&LOCK_grant); 04241 return priv; 04242 } 04243 04244 04245 /* Help function for mysql_show_grants */ 04246 04247 static void add_user_option(String *grant, ulong value, const char *name) 04248 { 04249 if (value) 04250 { 04251 char buff[22], *p; // just as in int2str 04252 grant->append(' '); 04253 grant->append(name, strlen(name)); 04254 grant->append(' '); 04255 p=int10_to_str(value, buff, 10); 04256 grant->append(buff,p-buff); 04257 } 04258 } 04259 04260 static const char *command_array[]= 04261 { 04262 "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD", 04263 "SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX", 04264 "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", 04265 "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", 04266 "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", 04267 "CREATE USER", "EVENT", "TRIGGER" 04268 }; 04269 04270 static uint command_lengths[]= 04271 { 04272 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, 04273 14, 13, 11, 5, 7 04274 }; 04275 04276 04277 static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash, 04278 const char *type, int typelen, 04279 char *buff, int buffsize); 04280 04281 04282 /* 04283 SHOW GRANTS; Send grants for a user to the client 04284 04285 IMPLEMENTATION 04286 Send to client grant-like strings depicting user@host privileges 04287 */ 04288 04289 bool mysql_show_grants(THD *thd,LEX_USER *lex_user) 04290 { 04291 ulong want_access; 04292 uint counter,index; 04293 int error = 0; 04294 ACL_USER *acl_user; 04295 ACL_DB *acl_db; 04296 char buff[1024]; 04297 Protocol *protocol= thd->protocol; 04298 DBUG_ENTER("mysql_show_grants"); 04299 04300 LINT_INIT(acl_user); 04301 if (!initialized) 04302 { 04303 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); 04304 DBUG_RETURN(TRUE); 04305 } 04306 04307 if (lex_user->host.length > HOSTNAME_LENGTH || 04308 lex_user->user.length > USERNAME_LENGTH) 04309 { 04310 my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER), 04311 MYF(0)); 04312 DBUG_RETURN(TRUE); 04313 } 04314 04315 rw_rdlock(&LOCK_grant); 04316 VOID(pthread_mutex_lock(&acl_cache->lock)); 04317 04318 acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE); 04319 if (!acl_user) 04320 { 04321 VOID(pthread_mutex_unlock(&acl_cache->lock)); 04322 rw_unlock(&LOCK_grant); 04323 04324 my_error(ER_NONEXISTING_GRANT, MYF(0), 04325 lex_user->user.str, lex_user->host.str); 04326 DBUG_RETURN(TRUE); 04327 } 04328 04329 Item_string *field=new Item_string("",0,&my_charset_latin1); 04330 List<Item> field_list; 04331 field->name=buff; 04332 field->max_length=1024; 04333 strxmov(buff,"Grants for ",lex_user->user.str,"@", 04334 lex_user->host.str,NullS); 04335 field_list.push_back(field); 04336 if (protocol->send_fields(&field_list, 04337 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 04338 { 04339 VOID(pthread_mutex_unlock(&acl_cache->lock)); 04340 rw_unlock(&LOCK_grant); 04341 04342 DBUG_RETURN(TRUE); 04343 } 04344 04345 /* Add first global access grants */ 04346 { 04347 String global(buff,sizeof(buff),system_charset_info); 04348 global.length(0); 04349 global.append(STRING_WITH_LEN("GRANT ")); 04350 04351 want_access= acl_user->access; 04352 if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL))) 04353 global.append(STRING_WITH_LEN("ALL PRIVILEGES")); 04354 else if (!(want_access & ~GRANT_ACL)) 04355 global.append(STRING_WITH_LEN("USAGE")); 04356 else 04357 { 04358 bool found=0; 04359 ulong j,test_access= want_access & ~GRANT_ACL; 04360 for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1) 04361 { 04362 if (test_access & j) 04363 { 04364 if (found) 04365 global.append(STRING_WITH_LEN(", ")); 04366 found=1; 04367 global.append(command_array[counter],command_lengths[counter]); 04368 } 04369 } 04370 } 04371 global.append (STRING_WITH_LEN(" ON *.* TO '")); 04372 global.append(lex_user->user.str, lex_user->user.length, 04373 system_charset_info); 04374 global.append (STRING_WITH_LEN("'@'")); 04375 global.append(lex_user->host.str,lex_user->host.length, 04376 system_charset_info); 04377 global.append ('\''); 04378 if (acl_user->salt_len) 04379 { 04380 char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; 04381 if (acl_user->salt_len == SCRAMBLE_LENGTH) 04382 make_password_from_salt(passwd_buff, acl_user->salt); 04383 else 04384 make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); 04385 global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '")); 04386 global.append(passwd_buff); 04387 global.append('\''); 04388 } 04389 /* "show grants" SSL related stuff */ 04390 if (acl_user->ssl_type == SSL_TYPE_ANY) 04391 global.append(STRING_WITH_LEN(" REQUIRE SSL")); 04392 else if (acl_user->ssl_type == SSL_TYPE_X509) 04393 global.append(STRING_WITH_LEN(" REQUIRE X509")); 04394 else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED) 04395 { 04396 int ssl_options = 0; 04397 global.append(STRING_WITH_LEN(" REQUIRE ")); 04398 if (acl_user->x509_issuer) 04399 { 04400 ssl_options++; 04401 global.append(STRING_WITH_LEN("ISSUER \'")); 04402 global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); 04403 global.append('\''); 04404 } 04405 if (acl_user->x509_subject) 04406 { 04407 if (ssl_options++) 04408 global.append(' '); 04409 global.append(STRING_WITH_LEN("SUBJECT \'")); 04410 global.append(acl_user->x509_subject,strlen(acl_user->x509_subject), 04411 system_charset_info); 04412 global.append('\''); 04413 } 04414 if (acl_user->ssl_cipher) 04415 { 04416 if (ssl_options++) 04417 global.append(' '); 04418 global.append(STRING_WITH_LEN("CIPHER '")); 04419 global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher), 04420 system_charset_info); 04421 global.append('\''); 04422 } 04423 } 04424 if ((want_access & GRANT_ACL) || 04425 (acl_user->user_resource.questions || 04426 acl_user->user_resource.updates || 04427 acl_user->user_resource.conn_per_hour || 04428 acl_user->user_resource.user_conn)) 04429 { 04430 global.append(STRING_WITH_LEN(" WITH")); 04431 if (want_access & GRANT_ACL) 04432 global.append(STRING_WITH_LEN(" GRANT OPTION")); 04433 add_user_option(&global, acl_user->user_resource.questions, 04434 "MAX_QUERIES_PER_HOUR"); 04435 add_user_option(&global, acl_user->user_resource.updates, 04436 "MAX_UPDATES_PER_HOUR"); 04437 add_user_option(&global, acl_user->user_resource.conn_per_hour, 04438 "MAX_CONNECTIONS_PER_HOUR"); 04439 add_user_option(&global, acl_user->user_resource.user_conn, 04440 "MAX_USER_CONNECTIONS"); 04441 } 04442 protocol->prepare_for_resend(); 04443 protocol->store(global.ptr(),global.length(),global.charset()); 04444 if (protocol->write()) 04445 { 04446 error= -1; 04447 goto end; 04448 } 04449 } 04450 04451 /* Add database access */ 04452 for (counter=0 ; counter < acl_dbs.elements ; counter++) 04453 { 04454 const char *user, *host; 04455 04456 acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); 04457 if (!(user=acl_db->user)) 04458 user= ""; 04459 if (!(host=acl_db->host.hostname)) 04460 host= ""; 04461 04462 if (!strcmp(lex_user->user.str,user) && 04463 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 04464 { 04465 want_access=acl_db->access; 04466 if (want_access) 04467 { 04468 String db(buff,sizeof(buff),system_charset_info); 04469 db.length(0); 04470 db.append(STRING_WITH_LEN("GRANT ")); 04471 04472 if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) 04473 db.append(STRING_WITH_LEN("ALL PRIVILEGES")); 04474 else if (!(want_access & ~GRANT_ACL)) 04475 db.append(STRING_WITH_LEN("USAGE")); 04476 else 04477 { 04478 int found=0, cnt; 04479 ulong j,test_access= want_access & ~GRANT_ACL; 04480 for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) 04481 { 04482 if (test_access & j) 04483 { 04484 if (found) 04485 db.append(STRING_WITH_LEN(", ")); 04486 found = 1; 04487 db.append(command_array[cnt],command_lengths[cnt]); 04488 } 04489 } 04490 } 04491 db.append (STRING_WITH_LEN(" ON ")); 04492 append_identifier(thd, &db, acl_db->db, strlen(acl_db->db)); 04493 db.append (STRING_WITH_LEN(".* TO '")); 04494 db.append(lex_user->user.str, lex_user->user.length, 04495 system_charset_info); 04496 db.append (STRING_WITH_LEN("'@'")); 04497 db.append(lex_user->host.str, lex_user->host.length, 04498 system_charset_info); 04499 db.append ('\''); 04500 if (want_access & GRANT_ACL) 04501 db.append(STRING_WITH_LEN(" WITH GRANT OPTION")); 04502 protocol->prepare_for_resend(); 04503 protocol->store(db.ptr(),db.length(),db.charset()); 04504 if (protocol->write()) 04505 { 04506 error= -1; 04507 goto end; 04508 } 04509 } 04510 } 04511 } 04512 04513 /* Add table & column access */ 04514 for (index=0 ; index < column_priv_hash.records ; index++) 04515 { 04516 const char *user, *host; 04517 GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, 04518 index); 04519 04520 if (!(user=grant_table->user)) 04521 user= ""; 04522 if (!(host= grant_table->host.hostname)) 04523 host= ""; 04524 04525 if (!strcmp(lex_user->user.str,user) && 04526 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 04527 { 04528 ulong table_access= grant_table->privs; 04529 if ((table_access | grant_table->cols) != 0) 04530 { 04531 String global(buff, sizeof(buff), system_charset_info); 04532 ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL; 04533 04534 global.length(0); 04535 global.append(STRING_WITH_LEN("GRANT ")); 04536 04537 if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL))) 04538 global.append(STRING_WITH_LEN("ALL PRIVILEGES")); 04539 else if (!test_access) 04540 global.append(STRING_WITH_LEN("USAGE")); 04541 else 04542 { 04543 /* Add specific column access */ 04544 int found= 0; 04545 ulong j; 04546 04547 for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1) 04548 { 04549 if (test_access & j) 04550 { 04551 if (found) 04552 global.append(STRING_WITH_LEN(", ")); 04553 found= 1; 04554 global.append(command_array[counter],command_lengths[counter]); 04555 04556 if (grant_table->cols) 04557 { 04558 uint found_col= 0; 04559 for (uint col_index=0 ; 04560 col_index < grant_table->hash_columns.records ; 04561 col_index++) 04562 { 04563 GRANT_COLUMN *grant_column = (GRANT_COLUMN*) 04564 hash_element(&grant_table->hash_columns,col_index); 04565 if (grant_column->rights & j) 04566 { 04567 if (!found_col) 04568 { 04569 found_col= 1; 04570 /* 04571 If we have a duplicated table level privilege, we 04572 must write the access privilege name again. 04573 */ 04574 if (table_access & j) 04575 { 04576 global.append(STRING_WITH_LEN(", ")); 04577 global.append(command_array[counter], 04578 command_lengths[counter]); 04579 } 04580 global.append(STRING_WITH_LEN(" (")); 04581 } 04582 else 04583 global.append(STRING_WITH_LEN(", ")); 04584 global.append(grant_column->column, 04585 grant_column->key_length, 04586 system_charset_info); 04587 } 04588 } 04589 if (found_col) 04590 global.append(')'); 04591 } 04592 } 04593 } 04594 } 04595 global.append(STRING_WITH_LEN(" ON ")); 04596 append_identifier(thd, &global, grant_table->db, 04597 strlen(grant_table->db)); 04598 global.append('.'); 04599 append_identifier(thd, &global, grant_table->tname, 04600 strlen(grant_table->tname)); 04601 global.append(STRING_WITH_LEN(" TO '")); 04602 global.append(lex_user->user.str, lex_user->user.length, 04603 system_charset_info); 04604 global.append(STRING_WITH_LEN("'@'")); 04605 global.append(lex_user->host.str,lex_user->host.length, 04606 system_charset_info); 04607 global.append('\''); 04608 if (table_access & GRANT_ACL) 04609 global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); 04610 protocol->prepare_for_resend(); 04611 protocol->store(global.ptr(),global.length(),global.charset()); 04612 if (protocol->write()) 04613 { 04614 error= -1; 04615 break; 04616 } 04617 } 04618 } 04619 } 04620 04621 if (show_routine_grants(thd, lex_user, &proc_priv_hash, 04622 STRING_WITH_LEN("PROCEDURE"), buff, sizeof(buff))) 04623 { 04624 error= -1; 04625 goto end; 04626 } 04627 04628 if (show_routine_grants(thd, lex_user, &func_priv_hash, 04629 STRING_WITH_LEN("FUNCTION"), buff, sizeof(buff))) 04630 { 04631 error= -1; 04632 goto end; 04633 } 04634 04635 end: 04636 VOID(pthread_mutex_unlock(&acl_cache->lock)); 04637 rw_unlock(&LOCK_grant); 04638 04639 send_eof(thd); 04640 DBUG_RETURN(error); 04641 } 04642 04643 static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, 04644 const char *type, int typelen, 04645 char *buff, int buffsize) 04646 { 04647 uint counter, index; 04648 int error= 0; 04649 Protocol *protocol= thd->protocol; 04650 /* Add routine access */ 04651 for (index=0 ; index < hash->records ; index++) 04652 { 04653 const char *user, *host; 04654 GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index); 04655 04656 if (!(user=grant_proc->user)) 04657 user= ""; 04658 if (!(host= grant_proc->host.hostname)) 04659 host= ""; 04660 04661 if (!strcmp(lex_user->user.str,user) && 04662 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 04663 { 04664 ulong proc_access= grant_proc->privs; 04665 if (proc_access != 0) 04666 { 04667 String global(buff, buffsize, system_charset_info); 04668 ulong test_access= proc_access & ~GRANT_ACL; 04669 04670 global.length(0); 04671 global.append(STRING_WITH_LEN("GRANT ")); 04672 04673 if (!test_access) 04674 global.append(STRING_WITH_LEN("USAGE")); 04675 else 04676 { 04677 /* Add specific procedure access */ 04678 int found= 0; 04679 ulong j; 04680 04681 for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1) 04682 { 04683 if (test_access & j) 04684 { 04685 if (found) 04686 global.append(STRING_WITH_LEN(", ")); 04687 found= 1; 04688 global.append(command_array[counter],command_lengths[counter]); 04689 } 04690 } 04691 } 04692 global.append(STRING_WITH_LEN(" ON ")); 04693 global.append(type,typelen); 04694 global.append(' '); 04695 append_identifier(thd, &global, grant_proc->db, 04696 strlen(grant_proc->db)); 04697 global.append('.'); 04698 append_identifier(thd, &global, grant_proc->tname, 04699 strlen(grant_proc->tname)); 04700 global.append(STRING_WITH_LEN(" TO '")); 04701 global.append(lex_user->user.str, lex_user->user.length, 04702 system_charset_info); 04703 global.append(STRING_WITH_LEN("'@'")); 04704 global.append(lex_user->host.str,lex_user->host.length, 04705 system_charset_info); 04706 global.append('\''); 04707 if (proc_access & GRANT_ACL) 04708 global.append(STRING_WITH_LEN(" WITH GRANT OPTION")); 04709 protocol->prepare_for_resend(); 04710 protocol->store(global.ptr(),global.length(),global.charset()); 04711 if (protocol->write()) 04712 { 04713 error= -1; 04714 break; 04715 } 04716 } 04717 } 04718 } 04719 return error; 04720 } 04721 04722 /* 04723 Make a clear-text version of the requested privilege. 04724 */ 04725 04726 void get_privilege_desc(char *to, uint max_length, ulong access) 04727 { 04728 uint pos; 04729 char *start=to; 04730 DBUG_ASSERT(max_length >= 30); // For end ',' removal 04731 04732 if (access) 04733 { 04734 max_length--; // Reserve place for end-zero 04735 for (pos=0 ; access ; pos++, access>>=1) 04736 { 04737 if ((access & 1) && 04738 command_lengths[pos] + (uint) (to-start) < max_length) 04739 { 04740 to= strmov(to, command_array[pos]); 04741 *to++=','; 04742 } 04743 } 04744 to--; // Remove end ',' 04745 } 04746 *to=0; 04747 } 04748 04749 04750 void get_mqh(const char *user, const char *host, USER_CONN *uc) 04751 { 04752 ACL_USER *acl_user; 04753 04754 pthread_mutex_lock(&acl_cache->lock); 04755 04756 if (initialized && (acl_user= find_acl_user(host,user, FALSE))) 04757 uc->user_resources= acl_user->user_resource; 04758 else 04759 bzero((char*) &uc->user_resources, sizeof(uc->user_resources)); 04760 04761 pthread_mutex_unlock(&acl_cache->lock); 04762 } 04763 04764 /* 04765 Open the grant tables. 04766 04767 SYNOPSIS 04768 open_grant_tables() 04769 thd The current thread. 04770 tables (out) The 4 elements array for the opened tables. 04771 04772 DESCRIPTION 04773 Tables are numbered as follows: 04774 0 user 04775 1 db 04776 2 tables_priv 04777 3 columns_priv 04778 04779 RETURN 04780 1 Skip GRANT handling during replication. 04781 0 OK. 04782 < 0 Error. 04783 */ 04784 04785 #define GRANT_TABLES 5 04786 int open_grant_tables(THD *thd, TABLE_LIST *tables) 04787 { 04788 DBUG_ENTER("open_grant_tables"); 04789 04790 if (!initialized) 04791 { 04792 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); 04793 DBUG_RETURN(-1); 04794 } 04795 04796 bzero((char*) tables, GRANT_TABLES*sizeof(*tables)); 04797 tables->alias= tables->table_name= (char*) "user"; 04798 (tables+1)->alias= (tables+1)->table_name= (char*) "db"; 04799 (tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv"; 04800 (tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv"; 04801 (tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv"; 04802 tables->next_local= tables->next_global= tables+1; 04803 (tables+1)->next_local= (tables+1)->next_global= tables+2; 04804 (tables+2)->next_local= (tables+2)->next_global= tables+3; 04805 (tables+3)->next_local= (tables+3)->next_global= tables+4; 04806 tables->lock_type= (tables+1)->lock_type= 04807 (tables+2)->lock_type= (tables+3)->lock_type= 04808 (tables+4)->lock_type= TL_WRITE; 04809 tables->db= (tables+1)->db= (tables+2)->db= 04810 (tables+3)->db= (tables+4)->db= (char*) "mysql"; 04811 04812 #ifdef HAVE_REPLICATION 04813 /* 04814 GRANT and REVOKE are applied the slave in/exclusion rules as they are 04815 some kind of updates to the mysql.% tables. 04816 */ 04817 if (thd->slave_thread && rpl_filter->is_on()) 04818 { 04819 /* 04820 The tables must be marked "updating" so that tables_ok() takes them into 04821 account in tests. 04822 */ 04823 tables[0].updating=tables[1].updating=tables[2].updating= 04824 tables[3].updating=tables[4].updating=1; 04825 if (!(thd->spcont || rpl_filter->tables_ok(0, tables))) 04826 DBUG_RETURN(1); 04827 tables[0].updating=tables[1].updating=tables[2].updating= 04828 tables[3].updating=tables[4].updating=0;; 04829 } 04830 #endif 04831 04832 if (simple_open_n_lock_tables(thd, tables)) 04833 { // This should never happen 04834 close_thread_tables(thd); 04835 DBUG_RETURN(-1); 04836 } 04837 04838 DBUG_RETURN(0); 04839 } 04840 04841 ACL_USER *check_acl_user(LEX_USER *user_name, 04842 uint *acl_acl_userdx) 04843 { 04844 ACL_USER *acl_user= 0; 04845 uint counter; 04846 04847 safe_mutex_assert_owner(&acl_cache->lock); 04848 04849 for (counter= 0 ; counter < acl_users.elements ; counter++) 04850 { 04851 const char *user,*host; 04852 acl_user= dynamic_element(&acl_users, counter, ACL_USER*); 04853 if (!(user=acl_user->user)) 04854 user= ""; 04855 if (!(host=acl_user->host.hostname)) 04856 host= ""; 04857 if (!strcmp(user_name->user.str,user) && 04858 !my_strcasecmp(system_charset_info, user_name->host.str, host)) 04859 break; 04860 } 04861 if (counter == acl_users.elements) 04862 return 0; 04863 04864 *acl_acl_userdx= counter; 04865 return acl_user; 04866 } 04867 04868 /* 04869 Modify a privilege table. 04870 04871 SYNOPSIS 04872 modify_grant_table() 04873 table The table to modify. 04874 host_field The host name field. 04875 user_field The user name field. 04876 user_to The new name for the user if to be renamed, 04877 NULL otherwise. 04878 04879 DESCRIPTION 04880 Update user/host in the current record if user_to is not NULL. 04881 Delete the current record if user_to is NULL. 04882 04883 RETURN 04884 0 OK. 04885 != 0 Error. 04886 */ 04887 04888 static int modify_grant_table(TABLE *table, Field *host_field, 04889 Field *user_field, LEX_USER *user_to) 04890 { 04891 int error; 04892 DBUG_ENTER("modify_grant_table"); 04893 04894 if (user_to) 04895 { 04896 /* rename */ 04897 store_record(table, record[1]); 04898 host_field->store(user_to->host.str, user_to->host.length, 04899 system_charset_info); 04900 user_field->store(user_to->user.str, user_to->user.length, 04901 system_charset_info); 04902 if ((error= table->file->ha_update_row(table->record[1], table->record[0]))) 04903 table->file->print_error(error, MYF(0)); 04904 } 04905 else 04906 { 04907 /* delete */ 04908 if ((error=table->file->ha_delete_row(table->record[0]))) 04909 table->file->print_error(error, MYF(0)); 04910 } 04911 04912 DBUG_RETURN(error); 04913 } 04914 04915 /* 04916 Handle a privilege table. 04917 04918 SYNOPSIS 04919 handle_grant_table() 04920 tables The array with the four open tables. 04921 table_no The number of the table to handle (0..4). 04922 drop If user_from is to be dropped. 04923 user_from The the user to be searched/dropped/renamed. 04924 user_to The new name for the user if to be renamed, 04925 NULL otherwise. 04926 04927 DESCRIPTION 04928 Scan through all records in a grant table and apply the requested 04929 operation. For the "user" table, a single index access is sufficient, 04930 since there is an unique index on (host, user). 04931 Delete from grant table if drop is true. 04932 Update in grant table if drop is false and user_to is not NULL. 04933 Search in grant table if drop is false and user_to is NULL. 04934 Tables are numbered as follows: 04935 0 user 04936 1 db 04937 2 tables_priv 04938 3 columns_priv 04939 4 procs_priv 04940 04941 RETURN 04942 > 0 At least one record matched. 04943 0 OK, but no record matched. 04944 < 0 Error. 04945 */ 04946 04947 static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop, 04948 LEX_USER *user_from, LEX_USER *user_to) 04949 { 04950 int result= 0; 04951 int error; 04952 TABLE *table= tables[table_no].table; 04953 Field *host_field= table->field[0]; 04954 Field *user_field= table->field[table_no ? 2 : 1]; 04955 char *host_str= user_from->host.str; 04956 char *user_str= user_from->user.str; 04957 const char *host; 04958 const char *user; 04959 byte user_key[MAX_KEY_LENGTH]; 04960 uint key_prefix_length; 04961 DBUG_ENTER("handle_grant_table"); 04962 04963 table->use_all_columns(); 04964 if (! table_no) // mysql.user table 04965 { 04966 /* 04967 The 'user' table has an unique index on (host, user). 04968 Thus, we can handle everything with a single index access. 04969 The host- and user fields are consecutive in the user table records. 04970 So we set host- and user fields of table->record[0] and use the 04971 pointer to the host field as key. 04972 index_read_idx() will replace table->record[0] (its first argument) 04973 by the searched record, if it exists. 04974 */ 04975 DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'", 04976 table->s->table_name.str, user_str, host_str)); 04977 host_field->store(host_str, user_from->host.length, system_charset_info); 04978 user_field->store(user_str, user_from->user.length, system_charset_info); 04979 04980 key_prefix_length= (table->key_info->key_part[0].store_length + 04981 table->key_info->key_part[1].store_length); 04982 key_copy(user_key, table->record[0], table->key_info, key_prefix_length); 04983 04984 if ((error= table->file->index_read_idx(table->record[0], 0, 04985 user_key, key_prefix_length, 04986 HA_READ_KEY_EXACT))) 04987 { 04988 if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) 04989 { 04990 table->file->print_error(error, MYF(0)); 04991 result= -1; 04992 } 04993 } 04994 else 04995 { 04996 /* If requested, delete or update the record. */ 04997 result= ((drop || user_to) && 04998 modify_grant_table(table, host_field, user_field, user_to)) ? 04999 -1 : 1; /* Error or found. */ 05000 } 05001 DBUG_PRINT("info",("read result: %d", result)); 05002 } 05003 else 05004 { 05005 /* 05006 The non-'user' table do not have indexes on (host, user). 05007 And their host- and user fields are not consecutive. 05008 Thus, we need to do a table scan to find all matching records. 05009 */ 05010 if ((error= table->file->ha_rnd_init(1))) 05011 { 05012 table->file->print_error(error, MYF(0)); 05013 result= -1; 05014 } 05015 else 05016 { 05017 #ifdef EXTRA_DEBUG 05018 DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'", 05019 table->s->table_name.str, user_str, host_str)); 05020 #endif 05021 while ((error= table->file->rnd_next(table->record[0])) != 05022 HA_ERR_END_OF_FILE) 05023 { 05024 if (error) 05025 { 05026 /* Most probable 'deleted record'. */ 05027 DBUG_PRINT("info",("scan error: %d", error)); 05028 continue; 05029 } 05030 if (! (host= get_field(&mem, host_field))) 05031 host= ""; 05032 if (! (user= get_field(&mem, user_field))) 05033 user= ""; 05034 05035 #ifdef EXTRA_DEBUG 05036 DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'", 05037 user, host, 05038 get_field(&mem, table->field[1]) /*db*/, 05039 get_field(&mem, table->field[3]) /*table*/, 05040 get_field(&mem, table->field[4]) /*column*/)); 05041 #endif 05042 if (strcmp(user_str, user) || 05043 my_strcasecmp(system_charset_info, host_str, host)) 05044 continue; 05045 05046 /* If requested, delete or update the record. */ 05047 result= ((drop || user_to) && 05048 modify_grant_table(table, host_field, user_field, user_to)) ? 05049 -1 : result ? result : 1; /* Error or keep result or found. */ 05050 /* If search is requested, we do not need to search further. */ 05051 if (! drop && ! user_to) 05052 break ; 05053 } 05054 (void) table->file->ha_rnd_end(); 05055 DBUG_PRINT("info",("scan result: %d", result)); 05056 } 05057 } 05058 05059 DBUG_RETURN(result); 05060 } 05061 05062 05063 /* 05064 Handle an in-memory privilege structure. 05065 05066 SYNOPSIS 05067 handle_grant_struct() 05068 struct_no The number of the structure to handle (0..3). 05069 drop If user_from is to be dropped. 05070 user_from The the user to be searched/dropped/renamed. 05071 user_to The new name for the user if to be renamed, 05072 NULL otherwise. 05073 05074 DESCRIPTION 05075 Scan through all elements in an in-memory grant structure and apply 05076 the requested operation. 05077 Delete from grant structure if drop is true. 05078 Update in grant structure if drop is false and user_to is not NULL. 05079 Search in grant structure if drop is false and user_to is NULL. 05080 Structures are numbered as follows: 05081 0 acl_users 05082 1 acl_dbs 05083 2 column_priv_hash 05084 3 procs_priv_hash 05085 05086 RETURN 05087 > 0 At least one element matched. 05088 0 OK, but no element matched. 05089 -1 Wrong arguments to function 05090 */ 05091 05092 static int handle_grant_struct(uint struct_no, bool drop, 05093 LEX_USER *user_from, LEX_USER *user_to) 05094 { 05095 int result= 0; 05096 uint idx; 05097 uint elements; 05098 const char *user; 05099 const char *host; 05100 ACL_USER *acl_user; 05101 ACL_DB *acl_db; 05102 GRANT_NAME *grant_name; 05103 DBUG_ENTER("handle_grant_struct"); 05104 DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'", 05105 struct_no, user_from->user.str, user_from->host.str)); 05106 05107 LINT_INIT(acl_user); 05108 LINT_INIT(acl_db); 05109 LINT_INIT(grant_name); 05110 LINT_INIT(user); 05111 LINT_INIT(host); 05112 05113 safe_mutex_assert_owner(&acl_cache->lock); 05114 05115 /* Get the number of elements in the in-memory structure. */ 05116 switch (struct_no) { 05117 case 0: 05118 elements= acl_users.elements; 05119 break; 05120 case 1: 05121 elements= acl_dbs.elements; 05122 break; 05123 case 2: 05124 elements= column_priv_hash.records; 05125 break; 05126 case 3: 05127 elements= proc_priv_hash.records; 05128 break; 05129 default: 05130 return -1; 05131 } 05132 05133 #ifdef EXTRA_DEBUG 05134 DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'", 05135 struct_no, user_from->user.str, user_from->host.str)); 05136 #endif 05137 /* Loop over all elements. */ 05138 for (idx= 0; idx < elements; idx++) 05139 { 05140 /* 05141 Get a pointer to the element. 05142 */ 05143 switch (struct_no) { 05144 case 0: 05145 acl_user= dynamic_element(&acl_users, idx, ACL_USER*); 05146 user= acl_user->user; 05147 host= acl_user->host.hostname; 05148 break; 05149 05150 case 1: 05151 acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*); 05152 user= acl_db->user; 05153 host= acl_db->host.hostname; 05154 break; 05155 05156 case 2: 05157 grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx); 05158 user= grant_name->user; 05159 host= grant_name->host.hostname; 05160 break; 05161 05162 case 3: 05163 grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx); 05164 user= grant_name->user; 05165 host= grant_name->host.hostname; 05166 break; 05167 } 05168 if (! user) 05169 user= ""; 05170 if (! host) 05171 host= ""; 05172 05173 #ifdef EXTRA_DEBUG 05174 DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", 05175 struct_no, idx, user, host)); 05176 #endif 05177 if (strcmp(user_from->user.str, user) || 05178 my_strcasecmp(system_charset_info, user_from->host.str, host)) 05179 continue; 05180 05181 result= 1; /* At least one element found. */ 05182 if ( drop ) 05183 { 05184 switch ( struct_no ) { 05185 case 0: 05186 delete_dynamic_element(&acl_users, idx); 05187 break; 05188 05189 case 1: 05190 delete_dynamic_element(&acl_dbs, idx); 05191 break; 05192 05193 case 2: 05194 hash_delete(&column_priv_hash, (byte*) grant_name); 05195 break; 05196 05197 case 3: 05198 hash_delete(&proc_priv_hash, (byte*) grant_name); 05199 break; 05200 } 05201 elements--; 05202 idx--; 05203 } 05204 else if ( user_to ) 05205 { 05206 switch ( struct_no ) { 05207 case 0: 05208 acl_user->user= strdup_root(&mem, user_to->user.str); 05209 acl_user->host.hostname= strdup_root(&mem, user_to->host.str); 05210 break; 05211 05212 case 1: 05213 acl_db->user= strdup_root(&mem, user_to->user.str); 05214 acl_db->host.hostname= strdup_root(&mem, user_to->host.str); 05215 break; 05216 05217 case 2: 05218 case 3: 05219 grant_name->user= strdup_root(&mem, user_to->user.str); 05220 update_hostname(&grant_name->host, 05221 strdup_root(&mem, user_to->host.str)); 05222 break; 05223 } 05224 } 05225 else 05226 { 05227 /* If search is requested, we do not need to search further. */ 05228 break; 05229 } 05230 } 05231 #ifdef EXTRA_DEBUG 05232 DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result)); 05233 #endif 05234 05235 DBUG_RETURN(result); 05236 } 05237 05238 05239 /* 05240 Handle all privilege tables and in-memory privilege structures. 05241 05242 SYNOPSIS 05243 handle_grant_data() 05244 tables The array with the four open tables. 05245 drop If user_from is to be dropped. 05246 user_from The the user to be searched/dropped/renamed. 05247 user_to The new name for the user if to be renamed, 05248 NULL otherwise. 05249 05250 DESCRIPTION 05251 Go through all grant tables and in-memory grant structures and apply 05252 the requested operation. 05253 Delete from grant data if drop is true. 05254 Update in grant data if drop is false and user_to is not NULL. 05255 Search in grant data if drop is false and user_to is NULL. 05256 05257 RETURN 05258 > 0 At least one element matched. 05259 0 OK, but no element matched. 05260 < 0 Error. 05261 */ 05262 05263 static int handle_grant_data(TABLE_LIST *tables, bool drop, 05264 LEX_USER *user_from, LEX_USER *user_to) 05265 { 05266 int result= 0; 05267 int found; 05268 DBUG_ENTER("handle_grant_data"); 05269 05270 /* Handle user table. */ 05271 if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0) 05272 { 05273 /* Handle of table failed, don't touch the in-memory array. */ 05274 result= -1; 05275 } 05276 else 05277 { 05278 /* Handle user array. */ 05279 if ((handle_grant_struct(0, drop, user_from, user_to) && ! result) || 05280 found) 05281 { 05282 result= 1; /* At least one record/element found. */ 05283 /* If search is requested, we do not need to search further. */ 05284 if (! drop && ! user_to) 05285 goto end; 05286 } 05287 } 05288 05289 /* Handle db table. */ 05290 if ((found= handle_grant_table(tables, 1, drop, user_from, user_to)) < 0) 05291 { 05292 /* Handle of table failed, don't touch the in-memory array. */ 05293 result= -1; 05294 } 05295 else 05296 { 05297 /* Handle db array. */ 05298 if (((handle_grant_struct(1, drop, user_from, user_to) && ! result) || 05299 found) && ! result) 05300 { 05301 result= 1; /* At least one record/element found. */ 05302 /* If search is requested, we do not need to search further. */ 05303 if (! drop && ! user_to) 05304 goto end; 05305 } 05306 } 05307 05308 /* Handle procedures table. */ 05309 if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0) 05310 { 05311 /* Handle of table failed, don't touch in-memory array. */ 05312 result= -1; 05313 } 05314 else 05315 { 05316 /* Handle procs array. */ 05317 if (((handle_grant_struct(3, drop, user_from, user_to) && ! result) || 05318 found) && ! result) 05319 { 05320 result= 1; /* At least one record/element found. */ 05321 /* If search is requested, we do not need to search further. */ 05322 if (! drop && ! user_to) 05323 goto end; 05324 } 05325 } 05326 05327 /* Handle tables table. */ 05328 if ((found= handle_grant_table(tables, 2, drop, user_from, user_to)) < 0) 05329 { 05330 /* Handle of table failed, don't touch columns and in-memory array. */ 05331 result= -1; 05332 } 05333 else 05334 { 05335 if (found && ! result) 05336 { 05337 result= 1; /* At least one record found. */ 05338 /* If search is requested, we do not need to search further. */ 05339 if (! drop && ! user_to) 05340 goto end; 05341 } 05342 05343 /* Handle columns table. */ 05344 if ((found= handle_grant_table(tables, 3, drop, user_from, user_to)) < 0) 05345 { 05346 /* Handle of table failed, don't touch the in-memory array. */ 05347 result= -1; 05348 } 05349 else 05350 { 05351 /* Handle columns hash. */ 05352 if (((handle_grant_struct(2, drop, user_from, user_to) && ! result) || 05353 found) && ! result) 05354 result= 1; /* At least one record/element found. */ 05355 } 05356 } 05357 end: 05358 DBUG_RETURN(result); 05359 } 05360 05361 05362 static void append_user(String *str, LEX_USER *user) 05363 { 05364 if (str->length()) 05365 str->append(','); 05366 str->append('\''); 05367 str->append(user->user.str); 05368 str->append(STRING_WITH_LEN("'@'")); 05369 str->append(user->host.str); 05370 str->append('\''); 05371 } 05372 05373 05374 /* 05375 Create a list of users. 05376 05377 SYNOPSIS 05378 mysql_create_user() 05379 thd The current thread. 05380 list The users to create. 05381 05382 RETURN 05383 FALSE OK. 05384 TRUE Error. 05385 */ 05386 05387 bool mysql_create_user(THD *thd, List <LEX_USER> &list) 05388 { 05389 int result; 05390 String wrong_users; 05391 ulong sql_mode; 05392 LEX_USER *user_name, *tmp_user_name; 05393 List_iterator <LEX_USER> user_list(list); 05394 TABLE_LIST tables[GRANT_TABLES]; 05395 DBUG_ENTER("mysql_create_user"); 05396 05397 /* CREATE USER may be skipped on replication client. */ 05398 if ((result= open_grant_tables(thd, tables))) 05399 DBUG_RETURN(result != 1); 05400 05401 rw_wrlock(&LOCK_grant); 05402 VOID(pthread_mutex_lock(&acl_cache->lock)); 05403 05404 while ((tmp_user_name= user_list++)) 05405 { 05406 if (!(user_name= get_current_user(thd, tmp_user_name))) 05407 { 05408 result= TRUE; 05409 continue; 05410 } 05411 05412 if (user_name->host.length > HOSTNAME_LENGTH || 05413 user_name->user.length > USERNAME_LENGTH) 05414 { 05415 append_user(&wrong_users, user_name); 05416 result= TRUE; 05417 continue; 05418 } 05419 05420 /* 05421 Search all in-memory structures and grant tables 05422 for a mention of the new user name. 05423 */ 05424 if (handle_grant_data(tables, 0, user_name, NULL)) 05425 { 05426 append_user(&wrong_users, user_name); 05427 result= TRUE; 05428 continue; 05429 } 05430 05431 sql_mode= thd->variables.sql_mode; 05432 if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0)) 05433 { 05434 append_user(&wrong_users, user_name); 05435 result= TRUE; 05436 } 05437 } 05438 05439 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05440 rw_unlock(&LOCK_grant); 05441 close_thread_tables(thd); 05442 if (result) 05443 my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); 05444 DBUG_RETURN(result); 05445 } 05446 05447 05448 /* 05449 Drop a list of users and all their privileges. 05450 05451 SYNOPSIS 05452 mysql_drop_user() 05453 thd The current thread. 05454 list The users to drop. 05455 05456 RETURN 05457 FALSE OK. 05458 TRUE Error. 05459 */ 05460 05461 bool mysql_drop_user(THD *thd, List <LEX_USER> &list) 05462 { 05463 int result; 05464 String wrong_users; 05465 LEX_USER *user_name, *tmp_user_name; 05466 List_iterator <LEX_USER> user_list(list); 05467 TABLE_LIST tables[GRANT_TABLES]; 05468 DBUG_ENTER("mysql_drop_user"); 05469 05470 /* DROP USER may be skipped on replication client. */ 05471 if ((result= open_grant_tables(thd, tables))) 05472 DBUG_RETURN(result != 1); 05473 05474 rw_wrlock(&LOCK_grant); 05475 VOID(pthread_mutex_lock(&acl_cache->lock)); 05476 05477 while ((tmp_user_name= user_list++)) 05478 { 05479 user_name= get_current_user(thd, tmp_user_name); 05480 if (!(user_name= get_current_user(thd, tmp_user_name))) 05481 { 05482 result= TRUE; 05483 continue; 05484 } 05485 if (handle_grant_data(tables, 1, user_name, NULL) <= 0) 05486 { 05487 append_user(&wrong_users, user_name); 05488 result= TRUE; 05489 } 05490 } 05491 05492 /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ 05493 rebuild_check_host(); 05494 05495 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05496 rw_unlock(&LOCK_grant); 05497 close_thread_tables(thd); 05498 if (result) 05499 my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); 05500 DBUG_RETURN(result); 05501 } 05502 05503 05504 /* 05505 Rename a user. 05506 05507 SYNOPSIS 05508 mysql_rename_user() 05509 thd The current thread. 05510 list The user name pairs: (from, to). 05511 05512 RETURN 05513 FALSE OK. 05514 TRUE Error. 05515 */ 05516 05517 bool mysql_rename_user(THD *thd, List <LEX_USER> &list) 05518 { 05519 int result; 05520 String wrong_users; 05521 LEX_USER *user_from, *tmp_user_from; 05522 LEX_USER *user_to, *tmp_user_to; 05523 List_iterator <LEX_USER> user_list(list); 05524 TABLE_LIST tables[GRANT_TABLES]; 05525 DBUG_ENTER("mysql_rename_user"); 05526 05527 /* RENAME USER may be skipped on replication client. */ 05528 if ((result= open_grant_tables(thd, tables))) 05529 DBUG_RETURN(result != 1); 05530 05531 rw_wrlock(&LOCK_grant); 05532 VOID(pthread_mutex_lock(&acl_cache->lock)); 05533 05534 while ((tmp_user_from= user_list++)) 05535 { 05536 if (!(user_from= get_current_user(thd, tmp_user_from))) 05537 { 05538 result= TRUE; 05539 continue; 05540 } 05541 tmp_user_to= user_list++; 05542 if (!(user_to= get_current_user(thd, tmp_user_to))) 05543 { 05544 result= TRUE; 05545 continue; 05546 } 05547 DBUG_ASSERT(user_to != 0); /* Syntax enforces pairs of users. */ 05548 05549 /* 05550 Search all in-memory structures and grant tables 05551 for a mention of the new user name. 05552 */ 05553 if (handle_grant_data(tables, 0, user_to, NULL) || 05554 handle_grant_data(tables, 0, user_from, user_to) <= 0) 05555 { 05556 append_user(&wrong_users, user_from); 05557 result= TRUE; 05558 } 05559 } 05560 05561 /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ 05562 rebuild_check_host(); 05563 05564 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05565 rw_unlock(&LOCK_grant); 05566 close_thread_tables(thd); 05567 if (result) 05568 my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); 05569 DBUG_RETURN(result); 05570 } 05571 05572 05573 /* 05574 Revoke all privileges from a list of users. 05575 05576 SYNOPSIS 05577 mysql_revoke_all() 05578 thd The current thread. 05579 list The users to revoke all privileges from. 05580 05581 RETURN 05582 > 0 Error. Error message already sent. 05583 0 OK. 05584 < 0 Error. Error message not yet sent. 05585 */ 05586 05587 bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) 05588 { 05589 uint counter, revoked, is_proc; 05590 int result; 05591 ACL_DB *acl_db; 05592 TABLE_LIST tables[GRANT_TABLES]; 05593 DBUG_ENTER("mysql_revoke_all"); 05594 05595 if ((result= open_grant_tables(thd, tables))) 05596 DBUG_RETURN(result != 1); 05597 05598 rw_wrlock(&LOCK_grant); 05599 VOID(pthread_mutex_lock(&acl_cache->lock)); 05600 05601 LEX_USER *lex_user, *tmp_lex_user; 05602 List_iterator <LEX_USER> user_list(list); 05603 while ((tmp_lex_user= user_list++)) 05604 { 05605 if (!(lex_user= get_current_user(thd, tmp_lex_user))) 05606 { 05607 result= -1; 05608 continue; 05609 } 05610 if (!find_acl_user(lex_user->host.str, lex_user->user.str, TRUE)) 05611 { 05612 sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' does not " 05613 "exists", lex_user->user.str, lex_user->host.str); 05614 result= -1; 05615 continue; 05616 } 05617 05618 if (replace_user_table(thd, tables[0].table, 05619 *lex_user, ~(ulong)0, 1, 0, 0)) 05620 { 05621 result= -1; 05622 continue; 05623 } 05624 05625 /* Remove db access privileges */ 05626 /* 05627 Because acl_dbs and column_priv_hash shrink and may re-order 05628 as privileges are removed, removal occurs in a repeated loop 05629 until no more privileges are revoked. 05630 */ 05631 do 05632 { 05633 for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; ) 05634 { 05635 const char *user,*host; 05636 05637 acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); 05638 if (!(user=acl_db->user)) 05639 user= ""; 05640 if (!(host=acl_db->host.hostname)) 05641 host= ""; 05642 05643 if (!strcmp(lex_user->user.str,user) && 05644 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 05645 { 05646 if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, 05647 ~(ulong)0, 1)) 05648 { 05649 /* 05650 Don't increment counter as replace_db_table deleted the 05651 current element in acl_dbs. 05652 */ 05653 revoked= 1; 05654 continue; 05655 } 05656 result= -1; // Something went wrong 05657 } 05658 counter++; 05659 } 05660 } while (revoked); 05661 05662 /* Remove column access */ 05663 do 05664 { 05665 for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; ) 05666 { 05667 const char *user,*host; 05668 GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash, 05669 counter); 05670 if (!(user=grant_table->user)) 05671 user= ""; 05672 if (!(host=grant_table->host.hostname)) 05673 host= ""; 05674 05675 if (!strcmp(lex_user->user.str,user) && 05676 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 05677 { 05678 if (replace_table_table(thd,grant_table,tables[2].table,*lex_user, 05679 grant_table->db, 05680 grant_table->tname, 05681 ~(ulong)0, 0, 1)) 05682 { 05683 result= -1; 05684 } 05685 else 05686 { 05687 if (!grant_table->cols) 05688 { 05689 revoked= 1; 05690 continue; 05691 } 05692 List<LEX_COLUMN> columns; 05693 if (!replace_column_table(grant_table,tables[3].table, *lex_user, 05694 columns, 05695 grant_table->db, 05696 grant_table->tname, 05697 ~(ulong)0, 1)) 05698 { 05699 revoked= 1; 05700 continue; 05701 } 05702 result= -1; 05703 } 05704 } 05705 counter++; 05706 } 05707 } while (revoked); 05708 05709 /* Remove procedure access */ 05710 for (is_proc=0; is_proc<2; is_proc++) do { 05711 HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; 05712 for (counter= 0, revoked= 0 ; counter < hash->records ; ) 05713 { 05714 const char *user,*host; 05715 GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); 05716 if (!(user=grant_proc->user)) 05717 user= ""; 05718 if (!(host=grant_proc->host.hostname)) 05719 host= ""; 05720 05721 if (!strcmp(lex_user->user.str,user) && 05722 !my_strcasecmp(system_charset_info, lex_user->host.str, host)) 05723 { 05724 if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user, 05725 grant_proc->db, 05726 grant_proc->tname, 05727 is_proc, 05728 ~(ulong)0, 1)) 05729 { 05730 revoked= 1; 05731 continue; 05732 } 05733 result= -1; // Something went wrong 05734 } 05735 counter++; 05736 } 05737 } while (revoked); 05738 } 05739 05740 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05741 rw_unlock(&LOCK_grant); 05742 close_thread_tables(thd); 05743 05744 if (result) 05745 my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); 05746 05747 DBUG_RETURN(result); 05748 } 05749 05750 05751 /* 05752 Revoke privileges for all users on a stored procedure 05753 05754 SYNOPSIS 05755 sp_revoke_privileges() 05756 thd The current thread. 05757 db DB of the stored procedure 05758 name Name of the stored procedure 05759 05760 RETURN 05761 0 OK. 05762 < 0 Error. Error message not yet sent. 05763 */ 05764 05765 bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, 05766 bool is_proc) 05767 { 05768 uint counter, revoked; 05769 int result; 05770 TABLE_LIST tables[GRANT_TABLES]; 05771 HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; 05772 DBUG_ENTER("sp_revoke_privileges"); 05773 05774 if ((result= open_grant_tables(thd, tables))) 05775 DBUG_RETURN(result != 1); 05776 05777 rw_wrlock(&LOCK_grant); 05778 VOID(pthread_mutex_lock(&acl_cache->lock)); 05779 05780 /* Remove procedure access */ 05781 do 05782 { 05783 for (counter= 0, revoked= 0 ; counter < hash->records ; ) 05784 { 05785 GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); 05786 if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && 05787 !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) 05788 { 05789 LEX_USER lex_user; 05790 lex_user.user.str= grant_proc->user; 05791 lex_user.user.length= strlen(grant_proc->user); 05792 lex_user.host.str= grant_proc->host.hostname ? 05793 grant_proc->host.hostname : (char*)""; 05794 lex_user.host.length= grant_proc->host.hostname ? 05795 strlen(grant_proc->host.hostname) : 0; 05796 if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user, 05797 grant_proc->db, grant_proc->tname, 05798 is_proc, ~(ulong)0, 1)) 05799 { 05800 revoked= 1; 05801 continue; 05802 } 05803 result= -1; // Something went wrong 05804 } 05805 counter++; 05806 } 05807 } while (revoked); 05808 05809 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05810 rw_unlock(&LOCK_grant); 05811 close_thread_tables(thd); 05812 05813 if (result) 05814 my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); 05815 05816 DBUG_RETURN(result); 05817 } 05818 05819 05820 /* 05821 Grant EXECUTE,ALTER privilege for a stored procedure 05822 05823 SYNOPSIS 05824 sp_grant_privileges() 05825 thd The current thread. 05826 db DB of the stored procedure 05827 name Name of the stored procedure 05828 05829 RETURN 05830 0 OK. 05831 < 0 Error. Error message not yet sent. 05832 */ 05833 05834 bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, 05835 bool is_proc) 05836 { 05837 Security_context *sctx= thd->security_ctx; 05838 LEX_USER *combo; 05839 TABLE_LIST tables[1]; 05840 List<LEX_USER> user_list; 05841 bool result; 05842 ACL_USER *au; 05843 char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; 05844 DBUG_ENTER("sp_grant_privileges"); 05845 05846 if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) 05847 DBUG_RETURN(TRUE); 05848 05849 combo->user.str= sctx->user; 05850 05851 VOID(pthread_mutex_lock(&acl_cache->lock)); 05852 05853 if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) 05854 goto found_acl; 05855 if ((au= find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE))) 05856 goto found_acl; 05857 if ((au= find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE))) 05858 goto found_acl; 05859 if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) 05860 goto found_acl; 05861 05862 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05863 DBUG_RETURN(TRUE); 05864 05865 found_acl: 05866 VOID(pthread_mutex_unlock(&acl_cache->lock)); 05867 05868 bzero((char*)tables, sizeof(TABLE_LIST)); 05869 user_list.empty(); 05870 05871 tables->db= (char*)sp_db; 05872 tables->table_name= tables->alias= (char*)sp_name; 05873 05874 combo->host.length= strlen(combo->host.str); 05875 combo->user.length= strlen(combo->user.str); 05876 combo->host.str= thd->strmake(combo->host.str,combo->host.length); 05877 combo->user.str= thd->strmake(combo->user.str,combo->user.length); 05878 05879 05880 if(au && au->salt_len) 05881 { 05882 if (au->salt_len == SCRAMBLE_LENGTH) 05883 { 05884 make_password_from_salt(passwd_buff, au->salt); 05885 combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; 05886 } 05887 else if (au->salt_len == SCRAMBLE_LENGTH_323) 05888 { 05889 make_password_from_salt_323(passwd_buff, (ulong *) au->salt); 05890 combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; 05891 } 05892 else 05893 { 05894 my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); 05895 return -1; 05896 } 05897 combo->password.str= passwd_buff; 05898 } 05899 else 05900 { 05901 combo->password.str= (char*)""; 05902 combo->password.length= 0; 05903 } 05904 05905 if (user_list.push_back(combo)) 05906 DBUG_RETURN(TRUE); 05907 05908 thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; 05909 bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh)); 05910 05911 result= mysql_routine_grant(thd, tables, is_proc, user_list, 05912 DEFAULT_CREATE_PROC_ACLS, 0, 1); 05913 DBUG_RETURN(result); 05914 } 05915 05916 05917 /***************************************************************************** 05918 Instantiate used templates 05919 *****************************************************************************/ 05920 05921 #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION 05922 template class List_iterator<LEX_COLUMN>; 05923 template class List_iterator<LEX_USER>; 05924 template class List<LEX_COLUMN>; 05925 template class List<LEX_USER>; 05926 #endif 05927 05928 #endif /*NO_EMBEDDED_ACCESS_CHECKS */ 05929 05930 05931 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr) 05932 { 05933 reg3 int flag; 05934 DBUG_ENTER("wild_case_compare"); 05935 DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr)); 05936 while (*wildstr) 05937 { 05938 while (*wildstr && *wildstr != wild_many && *wildstr != wild_one) 05939 { 05940 if (*wildstr == wild_prefix && wildstr[1]) 05941 wildstr++; 05942 if (my_toupper(cs, *wildstr++) != 05943 my_toupper(cs, *str++)) DBUG_RETURN(1); 05944 } 05945 if (! *wildstr ) DBUG_RETURN (*str != 0); 05946 if (*wildstr++ == wild_one) 05947 { 05948 if (! *str++) DBUG_RETURN (1); /* One char; skip */ 05949 } 05950 else 05951 { /* Found '*' */ 05952 if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */ 05953 flag=(*wildstr != wild_many && *wildstr != wild_one); 05954 do 05955 { 05956 if (flag) 05957 { 05958 char cmp; 05959 if ((cmp= *wildstr) == wild_prefix && wildstr[1]) 05960 cmp=wildstr[1]; 05961 cmp=my_toupper(cs, cmp); 05962 while (*str && my_toupper(cs, *str) != cmp) 05963 str++; 05964 if (!*str) DBUG_RETURN (1); 05965 } 05966 if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0); 05967 } while (*str++); 05968 DBUG_RETURN(1); 05969 } 05970 } 05971 DBUG_RETURN (*str != '\0'); 05972 } 05973 05974 05975 void update_schema_privilege(TABLE *table, char *buff, const char* db, 05976 const char* t_name, const char* column, 05977 uint col_length, const char *priv, 05978 uint priv_length, const char* is_grantable) 05979 { 05980 int i= 2; 05981 CHARSET_INFO *cs= system_charset_info; 05982 restore_record(table, s->default_values); 05983 table->field[0]->store(buff, strlen(buff), cs); 05984 if (db) 05985 table->field[i++]->store(db, strlen(db), cs); 05986 if (t_name) 05987 table->field[i++]->store(t_name, strlen(t_name), cs); 05988 if (column) 05989 table->field[i++]->store(column, col_length, cs); 05990 table->field[i++]->store(priv, priv_length, cs); 05991 table->field[i]->store(is_grantable, strlen(is_grantable), cs); 05992 table->file->ha_write_row(table->record[0]); 05993 } 05994 05995 05996 int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) 05997 { 05998 #ifndef NO_EMBEDDED_ACCESS_CHECKS 05999 uint counter; 06000 ACL_USER *acl_user; 06001 ulong want_access; 06002 char buff[100]; 06003 TABLE *table= tables->table; 06004 bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); 06005 char *curr_host= thd->security_ctx->priv_host_name(); 06006 DBUG_ENTER("fill_schema_user_privileges"); 06007 06008 pthread_mutex_lock(&acl_cache->lock); 06009 06010 for (counter=0 ; counter < acl_users.elements ; counter++) 06011 { 06012 const char *user,*host, *is_grantable="YES"; 06013 acl_user=dynamic_element(&acl_users,counter,ACL_USER*); 06014 if (!(user=acl_user->user)) 06015 user= ""; 06016 if (!(host=acl_user->host.hostname)) 06017 host= ""; 06018 06019 if (no_global_access && 06020 (strcmp(thd->security_ctx->priv_user, user) || 06021 my_strcasecmp(system_charset_info, curr_host, host))) 06022 continue; 06023 06024 want_access= acl_user->access; 06025 if (!(want_access & GRANT_ACL)) 06026 is_grantable= "NO"; 06027 06028 strxmov(buff,"'",user,"'@'",host,"'",NullS); 06029 if (!(want_access & ~GRANT_ACL)) 06030 update_schema_privilege(table, buff, 0, 0, 0, 0, 06031 STRING_WITH_LEN("USAGE"), is_grantable); 06032 else 06033 { 06034 uint priv_id; 06035 ulong j,test_access= want_access & ~GRANT_ACL; 06036 for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1) 06037 { 06038 if (test_access & j) 06039 update_schema_privilege(table, buff, 0, 0, 0, 0, 06040 command_array[priv_id], 06041 command_lengths[priv_id], is_grantable); 06042 } 06043 } 06044 } 06045 06046 pthread_mutex_unlock(&acl_cache->lock); 06047 06048 DBUG_RETURN(0); 06049 #else 06050 return(0); 06051 #endif 06052 } 06053 06054 06055 int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) 06056 { 06057 #ifndef NO_EMBEDDED_ACCESS_CHECKS 06058 uint counter; 06059 ACL_DB *acl_db; 06060 ulong want_access; 06061 char buff[100]; 06062 TABLE *table= tables->table; 06063 bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); 06064 char *curr_host= thd->security_ctx->priv_host_name(); 06065 DBUG_ENTER("fill_schema_schema_privileges"); 06066 06067 pthread_mutex_lock(&acl_cache->lock); 06068 06069 for (counter=0 ; counter < acl_dbs.elements ; counter++) 06070 { 06071 const char *user, *host, *is_grantable="YES"; 06072 06073 acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); 06074 if (!(user=acl_db->user)) 06075 user= ""; 06076 if (!(host=acl_db->host.hostname)) 06077 host= ""; 06078 06079 if (no_global_access && 06080 (strcmp(thd->security_ctx->priv_user, user) || 06081 my_strcasecmp(system_charset_info, curr_host, host))) 06082 continue; 06083 06084 want_access=acl_db->access; 06085 if (want_access) 06086 { 06087 if (!(want_access & GRANT_ACL)) 06088 { 06089 is_grantable= "NO"; 06090 } 06091 strxmov(buff,"'",user,"'@'",host,"'",NullS); 06092 if (!(want_access & ~GRANT_ACL)) 06093 update_schema_privilege(table, buff, acl_db->db, 0, 0, 06094 0, STRING_WITH_LEN("USAGE"), is_grantable); 06095 else 06096 { 06097 int cnt; 06098 ulong j,test_access= want_access & ~GRANT_ACL; 06099 for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) 06100 if (test_access & j) 06101 update_schema_privilege(table, buff, acl_db->db, 0, 0, 0, 06102 command_array[cnt], command_lengths[cnt], 06103 is_grantable); 06104 } 06105 } 06106 } 06107 06108 pthread_mutex_unlock(&acl_cache->lock); 06109 06110 DBUG_RETURN(0); 06111 #else 06112 return (0); 06113 #endif 06114 } 06115 06116 06117 int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) 06118 { 06119 #ifndef NO_EMBEDDED_ACCESS_CHECKS 06120 uint index; 06121 char buff[100]; 06122 TABLE *table= tables->table; 06123 bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); 06124 char *curr_host= thd->security_ctx->priv_host_name(); 06125 DBUG_ENTER("fill_schema_table_privileges"); 06126 06127 rw_rdlock(&LOCK_grant); 06128 06129 for (index=0 ; index < column_priv_hash.records ; index++) 06130 { 06131 const char *user, *host, *is_grantable= "YES"; 06132 GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, 06133 index); 06134 if (!(user=grant_table->user)) 06135 user= ""; 06136 if (!(host= grant_table->host.hostname)) 06137 host= ""; 06138 06139 if (no_global_access && 06140 (strcmp(thd->security_ctx->priv_user, user) || 06141 my_strcasecmp(system_charset_info, curr_host, host))) 06142 continue; 06143 06144 ulong table_access= grant_table->privs; 06145 if (table_access) 06146 { 06147 ulong test_access= table_access & ~GRANT_ACL; 06148 /* 06149 We should skip 'usage' privilege on table if 06150 we have any privileges on column(s) of this table 06151 */ 06152 if (!test_access && grant_table->cols) 06153 continue; 06154 if (!(table_access & GRANT_ACL)) 06155 is_grantable= "NO"; 06156 06157 strxmov(buff, "'", user, "'@'", host, "'", NullS); 06158 if (!test_access) 06159 update_schema_privilege(table, buff, grant_table->db, grant_table->tname, 06160 0, 0, STRING_WITH_LEN("USAGE"), is_grantable); 06161 else 06162 { 06163 ulong j; 06164 int cnt; 06165 for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1) 06166 { 06167 if (test_access & j) 06168 update_schema_privilege(table, buff, grant_table->db, 06169 grant_table->tname, 0, 0, command_array[cnt], 06170 command_lengths[cnt], is_grantable); 06171 } 06172 } 06173 } 06174 } 06175 06176 rw_unlock(&LOCK_grant); 06177 06178 DBUG_RETURN(0); 06179 #else 06180 return (0); 06181 #endif 06182 } 06183 06184 06185 int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) 06186 { 06187 #ifndef NO_EMBEDDED_ACCESS_CHECKS 06188 uint index; 06189 char buff[100]; 06190 TABLE *table= tables->table; 06191 bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); 06192 char *curr_host= thd->security_ctx->priv_host_name(); 06193 DBUG_ENTER("fill_schema_table_privileges"); 06194 06195 rw_rdlock(&LOCK_grant); 06196 06197 for (index=0 ; index < column_priv_hash.records ; index++) 06198 { 06199 const char *user, *host, *is_grantable= "YES"; 06200 GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, 06201 index); 06202 if (!(user=grant_table->user)) 06203 user= ""; 06204 if (!(host= grant_table->host.hostname)) 06205 host= ""; 06206 06207 if (no_global_access && 06208 (strcmp(thd->security_ctx->priv_user, user) || 06209 my_strcasecmp(system_charset_info, curr_host, host))) 06210 continue; 06211 06212 ulong table_access= grant_table->cols; 06213 if (table_access != 0) 06214 { 06215 if (!(grant_table->privs & GRANT_ACL)) 06216 is_grantable= "NO"; 06217 06218 ulong test_access= table_access & ~GRANT_ACL; 06219 strxmov(buff, "'", user, "'@'", host, "'", NullS); 06220 if (!test_access) 06221 continue; 06222 else 06223 { 06224 ulong j; 06225 int cnt; 06226 for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1) 06227 { 06228 if (test_access & j) 06229 { 06230 for (uint col_index=0 ; 06231 col_index < grant_table->hash_columns.records ; 06232 col_index++) 06233 { 06234 GRANT_COLUMN *grant_column = (GRANT_COLUMN*) 06235 hash_element(&grant_table->hash_columns,col_index); 06236 if ((grant_column->rights & j) && (table_access & j)) 06237 update_schema_privilege(table, buff, grant_table->db, 06238 grant_table->tname, 06239 grant_column->column, 06240 grant_column->key_length, 06241 command_array[cnt], 06242 command_lengths[cnt], is_grantable); 06243 } 06244 } 06245 } 06246 } 06247 } 06248 } 06249 06250 rw_unlock(&LOCK_grant); 06251 06252 DBUG_RETURN(0); 06253 #else 06254 return (0); 06255 #endif 06256 } 06257 06258 06259 #ifndef NO_EMBEDDED_ACCESS_CHECKS 06260 /* 06261 fill effective privileges for table 06262 06263 SYNOPSIS 06264 fill_effective_table_privileges() 06265 thd thread handler 06266 grant grants table descriptor 06267 db db name 06268 table table name 06269 */ 06270 06271 void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, 06272 const char *db, const char *table) 06273 { 06274 Security_context *sctx= thd->security_ctx; 06275 DBUG_ENTER("fill_effective_table_privileges"); 06276 DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`", 06277 sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"), 06278 (sctx->priv_user ? sctx->priv_user : "(NULL)"), 06279 db, table)); 06280 /* --skip-grants */ 06281 if (!initialized) 06282 { 06283 DBUG_PRINT("info", ("skip grants")); 06284 grant->privilege= ~NO_ACCESS; // everything is allowed 06285 DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); 06286 DBUG_VOID_RETURN; 06287 } 06288 06289 /* global privileges */ 06290 grant->privilege= sctx->master_access; 06291 06292 if (!sctx->priv_user) 06293 { 06294 DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); 06295 DBUG_VOID_RETURN; // it is slave 06296 } 06297 06298 /* db privileges */ 06299 grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0); 06300 06301 if (!grant_option) 06302 { 06303 DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); 06304 DBUG_VOID_RETURN; 06305 } 06306 06307 /* table privileges */ 06308 rw_rdlock(&LOCK_grant); 06309 if (grant->version != grant_version) 06310 { 06311 grant->grant_table= 06312 table_hash_search(sctx->host, sctx->ip, db, 06313 sctx->priv_user, 06314 table, 0); /* purecov: inspected */ 06315 grant->version= grant_version; /* purecov: inspected */ 06316 } 06317 if (grant->grant_table != 0) 06318 { 06319 grant->privilege|= grant->grant_table->privs; 06320 } 06321 rw_unlock(&LOCK_grant); 06322 06323 DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); 06324 DBUG_VOID_RETURN; 06325 } 06326 06327 #else /* NO_EMBEDDED_ACCESS_CHECKS */ 06328 06329 /**************************************************************************** 06330 Dummy wrappers when we don't have any access checks 06331 ****************************************************************************/ 06332 06333 bool check_routine_level_acl(THD *thd, const char *db, const char *name, 06334 bool is_proc) 06335 { 06336 return FALSE; 06337 } 06338 06339 #endif
1.4.7

