sql_acl.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:112k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000-2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*
  14.   The privileges are saved in the following tables:
  15.   mysql/user  ; super user who are allowed to do almoust anything
  16.   mysql/host  ; host priviliges. This is used if host is empty in mysql/db.
  17.   mysql/db  ; database privileges / user
  18.   data in tables is sorted according to how many not-wild-cards there is
  19.   in the relevant fields. Empty strings comes last.
  20. */
  21. #include "mysql_priv.h"
  22. #include "hash_filo.h"
  23. #ifdef HAVE_REPLICATION
  24. #include "sql_repl.h" //for tables_ok()
  25. #endif
  26. #include <m_ctype.h>
  27. #include <stdarg.h>
  28. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  29. class acl_entry :public hash_filo_element
  30. {
  31. public:
  32.   ulong access;
  33.   uint16 length;
  34.   char key[1]; // Key will be stored here
  35. };
  36. static byte* acl_entry_get_key(acl_entry *entry,uint *length,
  37.        my_bool not_used __attribute__((unused)))
  38. {
  39.   *length=(uint) entry->length;
  40.   return (byte*) entry->key;
  41. }
  42. #define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
  43. #define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1)
  44. static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
  45. static MEM_ROOT mem, memex;
  46. static bool initialized=0;
  47. static bool allow_all_hosts=1;
  48. static HASH acl_check_hosts, column_priv_hash;
  49. static DYNAMIC_ARRAY acl_wild_hosts;
  50. static hash_filo *acl_cache;
  51. static uint grant_version=0;
  52. static uint priv_version=0; /* Version of priv tables. incremented by acl_load */
  53. static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
  54. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
  55. static ulong get_sort(uint count,...);
  56. static void init_check_host(void);
  57. static ACL_USER *find_acl_user(const char *host, const char *user,
  58.                                my_bool exact);
  59. static bool update_user_table(THD *thd, TABLE *table,
  60.                               const char *host, const char *user,
  61.       const char *new_password, uint new_password_len);
  62. static void update_hostname(acl_host_and_ip *host, const char *hostname);
  63. static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
  64.      const char *ip);
  65. static my_bool acl_load(THD *thd, TABLE_LIST *tables);
  66. static my_bool grant_load(TABLE_LIST *tables);
  67. /*
  68.   Convert scrambled password to binary form, according to scramble type, 
  69.   Binary form is stored in user.salt.
  70. */
  71. static
  72. void
  73. set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
  74. {
  75.   if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
  76.   {
  77.     get_salt_from_password(acl_user->salt, password);
  78.     acl_user->salt_len= SCRAMBLE_LENGTH;
  79.   }
  80.   else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  81.   {
  82.     get_salt_from_password_323((ulong *) acl_user->salt, password);
  83.     acl_user->salt_len= SCRAMBLE_LENGTH_323;
  84.   }
  85.   else
  86.     acl_user->salt_len= 0;
  87. }
  88. /*
  89.   This after_update function is used when user.password is less than
  90.   SCRAMBLE_LENGTH bytes.
  91. */
  92. static void restrict_update_of_old_passwords_var(THD *thd,
  93.                                                  enum_var_type var_type)
  94. {
  95.   if (var_type == OPT_GLOBAL)
  96.   {
  97.     pthread_mutex_lock(&LOCK_global_system_variables);
  98.     global_system_variables.old_passwords= 1;
  99.     pthread_mutex_unlock(&LOCK_global_system_variables);
  100.   }
  101.   else
  102.     thd->variables.old_passwords= 1;
  103. }
  104. /*
  105.   Initialize structures responsible for user/db-level privilege checking and
  106.   load privilege information for them from tables in the 'mysql' database.
  107.   SYNOPSIS
  108.     acl_init()
  109.       dont_read_acl_tables  TRUE if we want to skip loading data from
  110.                             privilege tables and disable privilege checking.
  111.   NOTES
  112.     This function is mostly responsible for preparatory steps, main work
  113.     on initialization and grants loading is done in acl_reload().
  114.   RETURN VALUES
  115.     0 ok
  116.     1 Could not initialize grant's
  117. */
  118. my_bool acl_init(bool dont_read_acl_tables)
  119. {
  120.   THD  *thd;
  121.   my_bool return_val;
  122.   DBUG_ENTER("acl_init");
  123.   acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
  124.                            (hash_get_key) acl_entry_get_key,
  125.                            (hash_free_key) free, system_charset_info);
  126.   if (dont_read_acl_tables)
  127.   {
  128.     DBUG_RETURN(0); /* purecov: tested */
  129.   }
  130.   /*
  131.     To be able to run this from boot, we allocate a temporary THD
  132.   */
  133.   if (!(thd=new THD))
  134.     DBUG_RETURN(1); /* purecov: inspected */
  135.   thd->store_globals();
  136.   /*
  137.     It is safe to call acl_reload() since acl_* arrays and hashes which
  138.     will be freed there are global static objects and thus are initialized
  139.     by zeros at startup.
  140.   */
  141.   return_val= acl_reload(thd);
  142.   delete thd;
  143.   /* Remember that we don't have a THD */
  144.   my_pthread_setspecific_ptr(THR_THD,  0);
  145.   DBUG_RETURN(return_val);
  146. }
  147. /*
  148.   Initialize structures responsible for user/db-level privilege checking
  149.   and load information about grants from open privilege tables.
  150.   SYNOPSIS
  151.     acl_load()
  152.       thd     Current thread
  153.       tables  List containing open "mysql.host", "mysql.user" and
  154.               "mysql.db" tables.
  155.   RETURN VALUES
  156.     FALSE  Success
  157.     TRUE   Error
  158. */
  159. static my_bool acl_load(THD *thd, TABLE_LIST *tables)
  160. {
  161.   TABLE *table;
  162.   READ_RECORD read_record_info;
  163.   my_bool return_val= 1;
  164.   bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
  165.   char tmp_name[NAME_LEN+1];
  166.   int password_length;
  167.   DBUG_ENTER("acl_load");
  168.   priv_version++; /* Privileges updated */
  169.   acl_cache->clear(1); // Clear locked hostname cache
  170.   init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
  171.   init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
  172.   VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
  173.   while (!(read_record_info.read_record(&read_record_info)))
  174.   {
  175.     ACL_HOST host;
  176.     update_hostname(&host.host,get_field(&mem, table->field[0]));
  177.     host.db=  get_field(&mem, table->field[1]);
  178.     if (lower_case_table_names && host.db)
  179.     {
  180.       /*
  181.        We make a temporary copy of the database, force it to lower case,
  182.        and then check it against the original name.
  183.       */
  184.       (void)strnmov(tmp_name, host.db, sizeof(tmp_name));
  185.       my_casedn_str(files_charset_info, host.db);
  186.       if (strcmp(host.db, tmp_name) != 0)
  187.       {
  188.         sql_print_warning("'host' entry '%s|%s' had database in mixed "
  189.                           "case that has been forced to lowercase because "
  190.                           "lower_case_table_names is set. It will not be "
  191.                           "possible to remove this privilege using REVOKE.",
  192.                           host.host.hostname, host.db);
  193.       }
  194.     }
  195.     host.access= get_access(table,2);
  196.     host.access= fix_rights_for_db(host.access);
  197.     host.sort=  get_sort(2,host.host.hostname,host.db);
  198.     if (check_no_resolve && hostname_requires_resolving(host.host.hostname))
  199.     {
  200.       sql_print_warning("'host' entry '%s|%s' "
  201.       "ignored in --skip-name-resolve mode.",
  202.       host.host.hostname, host.db?host.db:"");
  203.       continue;
  204.     }
  205. #ifndef TO_BE_REMOVED
  206.     if (table->fields ==  8)
  207.     { // Without grant
  208.       if (host.access & CREATE_ACL)
  209. host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
  210.     }
  211. #endif
  212.     VOID(push_dynamic(&acl_hosts,(gptr) &host));
  213.   }
  214.   qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
  215. sizeof(ACL_HOST),(qsort_cmp) acl_compare);
  216.   end_read_record(&read_record_info);
  217.   freeze_size(&acl_hosts);
  218.   init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
  219.   VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
  220.   password_length= table->field[2]->field_length /
  221.     table->field[2]->charset()->mbmaxlen;
  222.   if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  223.   {
  224.     sql_print_error("Fatal error: mysql.user table is damaged or in "
  225.                     "unsupported 3.20 format.");
  226.     goto end;
  227.   }
  228.   DBUG_PRINT("info",("user table fields: %d, password length: %d",
  229.      table->fields, password_length));
  230.   
  231.   pthread_mutex_lock(&LOCK_global_system_variables);
  232.   if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
  233.   {
  234.     if (opt_secure_auth)
  235.     {
  236.       pthread_mutex_unlock(&LOCK_global_system_variables);
  237.       sql_print_error("Fatal error: mysql.user table is in old format, "
  238.                       "but server started with --secure-auth option.");
  239.       goto end;
  240.     }
  241.     sys_old_passwords.after_update= restrict_update_of_old_passwords_var;
  242.     if (global_system_variables.old_passwords)
  243.       pthread_mutex_unlock(&LOCK_global_system_variables);
  244.     else
  245.     {
  246.       global_system_variables.old_passwords= 1;
  247.       pthread_mutex_unlock(&LOCK_global_system_variables);
  248.       sql_print_warning("mysql.user table is not updated to new password format; "
  249.                         "Disabling new password usage until "
  250.                         "mysql_fix_privilege_tables is run");
  251.     }
  252.     thd->variables.old_passwords= 1;
  253.   }
  254.   else
  255.   {
  256.     sys_old_passwords.after_update= 0;
  257.     pthread_mutex_unlock(&LOCK_global_system_variables);
  258.   }
  259.   allow_all_hosts=0;
  260.   while (!(read_record_info.read_record(&read_record_info)))
  261.   {
  262.     ACL_USER user;
  263.     update_hostname(&user.host, get_field(&mem, table->field[0]));
  264.     user.user= get_field(&mem, table->field[1]);
  265.     if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
  266.     {
  267.       sql_print_warning("'user' entry '%s@%s' "
  268.                         "ignored in --skip-name-resolve mode.",
  269.       user.user, user.host.hostname);
  270.       continue;
  271.     }
  272.     const char *password= get_field(&mem, table->field[2]);
  273.     uint password_len= password ? strlen(password) : 0;
  274.     set_user_salt(&user, password, password_len);
  275.     if (user.salt_len == 0 && password_len != 0)
  276.     {
  277.       switch (password_len) {
  278.       case 45: /* 4.1: to be removed */
  279.         sql_print_warning("Found 4.1 style password for user '%s@%s'. "
  280.                           "Ignoring user. "
  281.                           "You should change password for this user.",
  282.                           user.user ? user.user : "",
  283.                           user.host.hostname ? user.host.hostname : "");
  284.         break;
  285.       default:
  286.         sql_print_warning("Found invalid password for user: '%s@%s'; "
  287.                           "Ignoring user", user.user ? user.user : "",
  288.                            user.host.hostname ? user.host.hostname : "");
  289.         break;
  290.       }
  291.     }
  292.     else                                        // password is correct
  293.     {
  294.       uint next_field;
  295.       user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
  296.       user.sort= get_sort(2,user.host.hostname,user.user);
  297.       user.hostname_length= (user.host.hostname ?
  298.                              (uint) strlen(user.host.hostname) : 0);
  299.       if (table->fields >= 31)  /* Starting from 4.0.2 we have more fields */
  300.       {
  301.         char *ssl_type=get_field(&mem, table->field[next_field++]);
  302.         if (!ssl_type)
  303.           user.ssl_type=SSL_TYPE_NONE;
  304.         else if (!strcmp(ssl_type, "ANY"))
  305.           user.ssl_type=SSL_TYPE_ANY;
  306.         else if (!strcmp(ssl_type, "X509"))
  307.           user.ssl_type=SSL_TYPE_X509;
  308.         else  /* !strcmp(ssl_type, "SPECIFIED") */
  309.           user.ssl_type=SSL_TYPE_SPECIFIED;
  310.         user.ssl_cipher=   get_field(&mem, table->field[next_field++]);
  311.         user.x509_issuer=  get_field(&mem, table->field[next_field++]);
  312.         user.x509_subject= get_field(&mem, table->field[next_field++]);
  313.         char *ptr = get_field(&mem, table->field[next_field++]);
  314.         user.user_resource.questions=ptr ? atoi(ptr) : 0;
  315.         ptr = get_field(&mem, table->field[next_field++]);
  316.         user.user_resource.updates=ptr ? atoi(ptr) : 0;
  317.         ptr = get_field(&mem, table->field[next_field++]);
  318.         user.user_resource.connections=ptr ? atoi(ptr) : 0;
  319.         if (user.user_resource.questions || user.user_resource.updates ||
  320.             user.user_resource.connections)
  321.           mqh_used=1;
  322.       }
  323.       else
  324.       {
  325.         user.ssl_type=SSL_TYPE_NONE;
  326.         bzero((char *)&(user.user_resource),sizeof(user.user_resource));
  327. #ifndef TO_BE_REMOVED
  328.         if (table->fields <= 13)
  329.         { // Without grant
  330.           if (user.access & CREATE_ACL)
  331.             user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  332.         }
  333.         /* Convert old privileges */
  334.         user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
  335.         if (user.access & FILE_ACL)
  336.           user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
  337.         if (user.access & PROCESS_ACL)
  338.           user.access|= SUPER_ACL | EXECUTE_ACL;
  339. #endif
  340.       }
  341.       VOID(push_dynamic(&acl_users,(gptr) &user));
  342.       if (!user.host.hostname || user.host.hostname[0] == wild_many &&
  343.           !user.host.hostname[1])
  344.         allow_all_hosts=1; // Anyone can connect
  345.     }
  346.   }
  347.   qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  348. sizeof(ACL_USER),(qsort_cmp) acl_compare);
  349.   end_read_record(&read_record_info);
  350.   freeze_size(&acl_users);
  351.   init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
  352.   VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
  353.   while (!(read_record_info.read_record(&read_record_info)))
  354.   {
  355.     ACL_DB db;
  356.     update_hostname(&db.host,get_field(&mem, table->field[0]));
  357.     db.db=get_field(&mem, table->field[1]);
  358.     if (!db.db)
  359.     {
  360.       sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
  361.       continue;
  362.     }
  363.     db.user=get_field(&mem, table->field[2]);
  364.     if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
  365.     {
  366.       sql_print_warning("'db' entry '%s %s@%s' "
  367.         "ignored in --skip-name-resolve mode.",
  368.         db.db, db.user, db.host.hostname);
  369.       continue;
  370.     }
  371.     db.access=get_access(table,3);
  372.     db.access=fix_rights_for_db(db.access);
  373.     if (lower_case_table_names)
  374.     {
  375.       /*
  376.        We make a temporary copy of the database, force it to lower case,
  377.        and then check it against the original name.
  378.       */
  379.       (void)strnmov(tmp_name, db.db, sizeof(tmp_name));
  380.       my_casedn_str(files_charset_info, db.db);
  381.       if (strcmp(db.db, tmp_name) != 0)
  382.       {
  383.         sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
  384.                           "case that has been forced to lowercase because "
  385.                           "lower_case_table_names is set. It will not be "
  386.                           "possible to remove this privilege using REVOKE.",
  387.           db.db, db.user, db.host.hostname, db.host.hostname);
  388.       }
  389.     }
  390.     db.sort=get_sort(3,db.host.hostname,db.db,db.user);
  391. #ifndef TO_BE_REMOVED
  392.     if (table->fields <=  9)
  393.     { // Without grant
  394.       if (db.access & CREATE_ACL)
  395. db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  396.     }
  397. #endif
  398.     VOID(push_dynamic(&acl_dbs,(gptr) &db));
  399.   }
  400.   qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  401. sizeof(ACL_DB),(qsort_cmp) acl_compare);
  402.   end_read_record(&read_record_info);
  403.   freeze_size(&acl_dbs);
  404.   init_check_host();
  405.   initialized=1;
  406.   return_val=0;
  407. end:
  408.   DBUG_RETURN(return_val);
  409. }
  410. void acl_free(bool end)
  411. {
  412.   free_root(&mem,MYF(0));
  413.   delete_dynamic(&acl_hosts);
  414.   delete_dynamic(&acl_users);
  415.   delete_dynamic(&acl_dbs);
  416.   delete_dynamic(&acl_wild_hosts);
  417.   hash_free(&acl_check_hosts);
  418.   if (!end)
  419.     acl_cache->clear(1); /* purecov: inspected */
  420.   else
  421.   {
  422.     delete acl_cache;
  423.     acl_cache=0;
  424.   }
  425. }
  426. /*
  427.   Forget current user/db-level privileges and read new privileges
  428.   from the privilege tables.
  429.   SYNOPSIS
  430.     acl_reload()
  431.       thd  Current thread
  432.   NOTE
  433.     All tables of calling thread which were open and locked by LOCK TABLES
  434.     statement will be unlocked and closed.
  435.     This function is also used for initialization of structures responsible
  436.     for user/db-level privilege checking.
  437.   RETURN VALUE
  438.     FALSE  Success
  439.     TRUE   Failure
  440. */
  441. my_bool acl_reload(THD *thd)
  442. {
  443.   TABLE_LIST tables[3];
  444.   DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
  445.   MEM_ROOT old_mem;
  446.   bool old_initialized;
  447.   my_bool return_val= 1;
  448.   DBUG_ENTER("acl_reload");
  449.   if (thd->locked_tables)
  450.   { // Can't have locked tables here
  451.     thd->lock=thd->locked_tables;
  452.     thd->locked_tables=0;
  453.     close_thread_tables(thd);
  454.   }
  455.   /*
  456.     To avoid deadlocks we should obtain table locks before
  457.     obtaining acl_cache->lock mutex.
  458.   */
  459.   bzero((char*) tables, sizeof(tables));
  460.   tables[0].alias=tables[0].real_name=(char*) "host";
  461.   tables[1].alias=tables[1].real_name=(char*) "user";
  462.   tables[2].alias=tables[2].real_name=(char*) "db";
  463.   tables[0].db=tables[1].db=tables[2].db= (char*) "mysql";
  464.   tables[0].next= tables+1;
  465.   tables[1].next= tables+2;
  466.   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
  467.   if (simple_open_n_lock_tables(thd, tables))
  468.   {
  469.     sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
  470.     thd->net.last_error);
  471.     goto end;
  472.   }
  473.   if ((old_initialized=initialized))
  474.     VOID(pthread_mutex_lock(&acl_cache->lock));
  475.   old_acl_hosts=acl_hosts;
  476.   old_acl_users=acl_users;
  477.   old_acl_dbs=acl_dbs;
  478.   old_mem=mem;
  479.   delete_dynamic(&acl_wild_hosts);
  480.   hash_free(&acl_check_hosts);
  481.   if ((return_val= acl_load(thd, tables)))
  482.   { // Error. Revert to old list
  483.     DBUG_PRINT("error",("Reverting to old privileges"));
  484.     acl_free(); /* purecov: inspected */
  485.     acl_hosts=old_acl_hosts;
  486.     acl_users=old_acl_users;
  487.     acl_dbs=old_acl_dbs;
  488.     mem=old_mem;
  489.     init_check_host();
  490.   }
  491.   else
  492.   {
  493.     free_root(&old_mem,MYF(0));
  494.     delete_dynamic(&old_acl_hosts);
  495.     delete_dynamic(&old_acl_users);
  496.     delete_dynamic(&old_acl_dbs);
  497.   }
  498.   if (old_initialized)
  499.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  500. end:
  501.   close_thread_tables(thd);
  502.   DBUG_RETURN(return_val);
  503. }
  504. /*
  505.   Get all access bits from table after fieldnr
  506.   IMPLEMENTATION
  507.     We know that the access privileges ends when there is no more fields
  508.     or the field is not an enum with two elements.
  509.   SYNOPSIS
  510.     get_access()
  511.     form        an open table to read privileges from.
  512.                 The record should be already read in table->record[0]
  513.     fieldnr     number of the first privilege (that is ENUM('N','Y') field
  514.     next_field  on return - number of the field next to the last ENUM
  515.                 (unless next_field == 0)
  516.   RETURN VALUE
  517.     privilege mask
  518. */
  519. static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
  520. {
  521.   ulong access_bits=0,bit;
  522.   char buff[2];
  523.   String res(buff,sizeof(buff),&my_charset_latin1);
  524.   Field **pos;
  525.   for (pos=form->field+fieldnr, bit=1;
  526.        *pos && (*pos)->real_type() == FIELD_TYPE_ENUM &&
  527.  ((Field_enum*) (*pos))->typelib->count == 2 ;
  528.        pos++, fieldnr++, bit<<=1)
  529.   {
  530.     (*pos)->val_str(&res);
  531.     if (my_toupper(&my_charset_latin1, res[0]) == 'Y')
  532.       access_bits|= bit;
  533.   }
  534.   if (next_field)
  535.     *next_field=fieldnr;
  536.   return access_bits;
  537. }
  538. /*
  539.   Return a number which, if sorted 'desc', puts strings in this order:
  540.     no wildcards
  541.     wildcards
  542.     empty string
  543. */
  544. static ulong get_sort(uint count,...)
  545. {
  546.   va_list args;
  547.   va_start(args,count);
  548.   ulong sort=0;
  549.   /* Should not use this function with more than 4 arguments for compare. */
  550.   DBUG_ASSERT(count <= 4);
  551.   while (count--)
  552.   {
  553.     char *start, *str= va_arg(args,char*);
  554.     uint chars= 0;
  555.     uint wild_pos= 0;           /* first wildcard position */
  556.     if ((start= str))
  557.     {
  558.       for (; *str ; str++)
  559.       {
  560. if (*str == wild_many || *str == wild_one || *str == wild_prefix)
  561.         {
  562.           wild_pos= (uint) (str - start) + 1;
  563.           break;
  564.         }
  565.         chars= 128;                             // Marker that chars existed
  566.       }
  567.     }
  568.     sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars);
  569.   }
  570.   va_end(args);
  571.   return sort;
  572. }
  573. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
  574. {
  575.   if (a->sort > b->sort)
  576.     return -1;
  577.   if (a->sort < b->sort)
  578.     return 1;
  579.   return 0;
  580. }
  581. /*
  582.   Seek ACL entry for a user, check password, SSL cypher, and if
  583.   everything is OK, update THD user data and USER_RESOURCES struct.
  584.   IMPLEMENTATION
  585.    This function does not check if the user has any sensible privileges:
  586.    only user's existence and  validity is checked.
  587.    Note, that entire operation is protected by acl_cache_lock.
  588.   SYNOPSIS
  589.     acl_getroot()
  590.     thd         thread handle. If all checks are OK,
  591.                 thd->priv_user, thd->master_access are updated.
  592.                 thd->host, thd->ip, thd->user are used for checks.
  593.     mqh         user resources; on success mqh is reset, else
  594.                 unchanged
  595.     passwd      scrambled & crypted password, recieved from client
  596.                 (to check): thd->scramble or thd->scramble_323 is
  597.                 used to decrypt passwd, so they must contain
  598.                 original random string,
  599.     passwd_len  length of passwd, must be one of 0, 8,
  600.                 SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
  601.     'thd' and 'mqh' are updated on success; other params are IN.
  602.   
  603.   RETURN VALUE
  604.     0  success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
  605.        updated
  606.     1  user not found or authentification failure
  607.     2  user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
  608.    -1  user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
  609. */
  610. int acl_getroot(THD *thd, USER_RESOURCES  *mqh,
  611.                 const char *passwd, uint passwd_len)
  612. {
  613.   ulong user_access= NO_ACCESS;
  614.   int res= 1;
  615.   ACL_USER *acl_user= 0;
  616.   DBUG_ENTER("acl_getroot");
  617.   if (!initialized)
  618.   {
  619.     /* 
  620.       here if mysqld's been started with --skip-grant-tables option.
  621.     */
  622.     thd->priv_user= (char *) "";                // privileges for
  623.     *thd->priv_host= '';                      // the user are unknown
  624.     thd->master_access= ~NO_ACCESS;             // everything is allowed
  625.     bzero((char*) mqh, sizeof(*mqh));
  626.     DBUG_RETURN(0);
  627.   }
  628.   VOID(pthread_mutex_lock(&acl_cache->lock));
  629.   /*
  630.     Find acl entry in user database. Note, that find_acl_user is not the same,
  631.     because it doesn't take into account the case when user is not empty,
  632.     but acl_user->user is empty
  633.   */
  634.   for (uint i=0 ; i < acl_users.elements ; i++)
  635.   {
  636.     ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
  637.     if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user))
  638.     {
  639.       if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip))
  640.       {
  641.         /* check password: it should be empty or valid */
  642.         if (passwd_len == acl_user_tmp->salt_len)
  643.         {
  644.           if (acl_user_tmp->salt_len == 0 ||
  645.               (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
  646.               check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
  647.               check_scramble_323(passwd, thd->scramble,
  648.                                  (ulong *) acl_user_tmp->salt)) == 0)
  649.           {
  650.             acl_user= acl_user_tmp;
  651.             res= 0;
  652.           }
  653.         }
  654.         else if (passwd_len == SCRAMBLE_LENGTH &&
  655.                  acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
  656.           res= -1;
  657.         else if (passwd_len == SCRAMBLE_LENGTH_323 &&
  658.                  acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
  659.           res= 2;
  660.         /* linear search complete: */
  661.         break;
  662.       }
  663.     }
  664.   }
  665.   /*
  666.     This was moved to separate tree because of heavy HAVE_OPENSSL case.
  667.     If acl_user is not null, res is 0.
  668.   */
  669.   if (acl_user)
  670.   {
  671.     /* OK. User found and password checked continue validation */
  672. #ifdef HAVE_OPENSSL
  673.     Vio *vio=thd->net.vio;
  674.     SSL *ssl= (SSL*) vio->ssl_arg;
  675. #endif
  676.     /*
  677.       At this point we know that user is allowed to connect
  678.       from given host by given username/password pair. Now
  679.       we check if SSL is required, if user is using SSL and
  680.       if X509 certificate attributes are OK
  681.     */
  682.     switch (acl_user->ssl_type) {
  683.     case SSL_TYPE_NOT_SPECIFIED: // Impossible
  684.     case SSL_TYPE_NONE: // SSL is not required
  685.       user_access= acl_user->access;
  686.       break;
  687. #ifdef HAVE_OPENSSL
  688.     case SSL_TYPE_ANY: // Any kind of SSL is ok
  689.       if (vio_type(vio) == VIO_TYPE_SSL)
  690. user_access= acl_user->access;
  691.       break;
  692.     case SSL_TYPE_X509: /* Client should have any valid certificate. */
  693.       /*
  694. Connections with non-valid certificates are dropped already
  695. in sslaccept() anyway, so we do not check validity here.
  696. We need to check for absence of SSL because without SSL
  697. we should reject connection.
  698.       */
  699.       if (vio_type(vio) == VIO_TYPE_SSL &&
  700.   SSL_get_verify_result(ssl) == X509_V_OK &&
  701.   SSL_get_peer_certificate(ssl))
  702. user_access= acl_user->access;
  703.       break;
  704.     case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
  705.       /*
  706. We do not check for absence of SSL because without SSL it does
  707. not pass all checks here anyway.
  708. If cipher name is specified, we compare it to actual cipher in
  709. use.
  710.       */
  711.       X509 *cert;
  712.       if (vio_type(vio) != VIO_TYPE_SSL ||
  713.   SSL_get_verify_result(ssl) != X509_V_OK)
  714. break;
  715.       if (acl_user->ssl_cipher)
  716.       {
  717. DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
  718.    acl_user->ssl_cipher,SSL_get_cipher(ssl)));
  719. if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
  720.   user_access= acl_user->access;
  721. else
  722. {
  723.   if (global_system_variables.log_warnings)
  724.     sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
  725.       acl_user->ssl_cipher,
  726.       SSL_get_cipher(ssl));
  727.   break;
  728. }
  729.       }
  730.       /* Prepare certificate (if exists) */
  731.       DBUG_PRINT("info",("checkpoint 1"));
  732.       if (!(cert= SSL_get_peer_certificate(ssl)))
  733.       {
  734. user_access=NO_ACCESS;
  735. break;
  736.       }
  737.       DBUG_PRINT("info",("checkpoint 2"));
  738.       /* If X509 issuer is speified, we check it... */
  739.       if (acl_user->x509_issuer)
  740.       {
  741.         DBUG_PRINT("info",("checkpoint 3"));
  742. char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  743. DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
  744.    acl_user->x509_issuer, ptr));
  745.         if (strcmp(acl_user->x509_issuer, ptr))
  746.         {
  747.           if (global_system_variables.log_warnings)
  748.             sql_print_information("X509 issuer mismatch: should be '%s' "
  749.       "but is '%s'", acl_user->x509_issuer, ptr);
  750.           free(ptr);
  751.           break;
  752.         }
  753.         user_access= acl_user->access;
  754.         free(ptr);
  755.       }
  756.       DBUG_PRINT("info",("checkpoint 4"));
  757.       /* X509 subject is specified, we check it .. */
  758.       if (acl_user->x509_subject)
  759.       {
  760.         char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  761.         DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
  762.                            acl_user->x509_subject, ptr));
  763.         if (strcmp(acl_user->x509_subject,ptr))
  764.         {
  765.           if (global_system_variables.log_warnings)
  766.             sql_print_information("X509 subject mismatch: '%s' vs '%s'",
  767.                             acl_user->x509_subject, ptr);
  768.         }
  769.         else
  770.           user_access= acl_user->access;
  771.         free(ptr);
  772.       }
  773.       break;
  774. #else  /* HAVE_OPENSSL */
  775.     default:
  776.       /*
  777.         If we don't have SSL but SSL is required for this user the 
  778.         authentication should fail.
  779.       */
  780.       break;
  781. #endif /* HAVE_OPENSSL */
  782.     }
  783.     thd->master_access= user_access;
  784.     thd->priv_user= acl_user->user ? thd->user : (char *) "";
  785.     *mqh= acl_user->user_resource;
  786.     if (acl_user->host.hostname)
  787.       strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
  788.     else
  789.       *thd->priv_host= 0;
  790.   }
  791.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  792.   DBUG_RETURN(res);
  793. }
  794. static byte* check_get_key(ACL_USER *buff,uint *length,
  795.    my_bool not_used __attribute__((unused)))
  796. {
  797.   *length=buff->hostname_length;
  798.   return (byte*) buff->host.hostname;
  799. }
  800. static void acl_update_user(const char *user, const char *host,
  801.     const char *password, uint password_len,
  802.     enum SSL_type ssl_type,
  803.     const char *ssl_cipher,
  804.     const char *x509_issuer,
  805.     const char *x509_subject,
  806.     USER_RESOURCES  *mqh,
  807.     ulong privileges)
  808. {
  809.   for (uint i=0 ; i < acl_users.elements ; i++)
  810.   {
  811.     ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  812.     if (!acl_user->user && !user[0] ||
  813. acl_user->user &&
  814. !strcmp(user,acl_user->user))
  815.     {
  816.       if (!acl_user->host.hostname && !host[0] ||
  817.   acl_user->host.hostname &&
  818.   !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
  819.       {
  820. acl_user->access=privileges;
  821. if (mqh->bits & 1)
  822.   acl_user->user_resource.questions=mqh->questions;
  823. if (mqh->bits & 2)
  824.   acl_user->user_resource.updates=mqh->updates;
  825. if (mqh->bits & 4)
  826.   acl_user->user_resource.connections=mqh->connections;
  827. if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
  828. {
  829.   acl_user->ssl_type= ssl_type;
  830.   acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&mem,ssl_cipher) :
  831.  0);
  832.   acl_user->x509_issuer= (x509_issuer ? strdup_root(&mem,x509_issuer) :
  833.   0);
  834.   acl_user->x509_subject= (x509_subject ?
  835.    strdup_root(&mem,x509_subject) : 0);
  836. }
  837. if (password)
  838.   set_user_salt(acl_user, password, password_len);
  839.         /* search complete: */
  840. break;
  841.       }
  842.     }
  843.   }
  844. }
  845. static void acl_insert_user(const char *user, const char *host,
  846.     const char *password, uint password_len,
  847.     enum SSL_type ssl_type,
  848.     const char *ssl_cipher,
  849.     const char *x509_issuer,
  850.     const char *x509_subject,
  851.     USER_RESOURCES *mqh,
  852.     ulong privileges)
  853. {
  854.   ACL_USER acl_user;
  855.   acl_user.user=*user ? strdup_root(&mem,user) : 0;
  856.   update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
  857.   acl_user.access=privileges;
  858.   acl_user.user_resource = *mqh;
  859.   acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
  860.   acl_user.hostname_length=(uint) strlen(host);
  861.   acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
  862.       ssl_type : SSL_TYPE_NONE);
  863.   acl_user.ssl_cipher= ssl_cipher   ? strdup_root(&mem,ssl_cipher) : 0;
  864.   acl_user.x509_issuer= x509_issuer  ? strdup_root(&mem,x509_issuer) : 0;
  865.   acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
  866.   set_user_salt(&acl_user, password, password_len);
  867.   VOID(push_dynamic(&acl_users,(gptr) &acl_user));
  868.   if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
  869.       && !acl_user.host.hostname[1])
  870.     allow_all_hosts=1; // Anyone can connect /* purecov: tested */
  871.   qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  872. sizeof(ACL_USER),(qsort_cmp) acl_compare);
  873.   /* We must free acl_check_hosts as its memory is mapped to acl_user */
  874.   delete_dynamic(&acl_wild_hosts);
  875.   hash_free(&acl_check_hosts);
  876.   init_check_host();
  877. }
  878. static void acl_update_db(const char *user, const char *host, const char *db,
  879.   ulong privileges)
  880. {
  881.   for (uint i=0 ; i < acl_dbs.elements ; i++)
  882.   {
  883.     ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  884.     if (!acl_db->user && !user[0] ||
  885. acl_db->user &&
  886. !strcmp(user,acl_db->user))
  887.     {
  888.       if (!acl_db->host.hostname && !host[0] ||
  889.   acl_db->host.hostname &&
  890.   !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
  891.       {
  892. if (!acl_db->db && !db[0] ||
  893.     acl_db->db && !strcmp(db,acl_db->db))
  894. {
  895.   if (privileges)
  896.     acl_db->access=privileges;
  897.   else
  898.     delete_dynamic_element(&acl_dbs,i);
  899. }
  900.       }
  901.     }
  902.   }
  903. }
  904. /*
  905.   Insert a user/db/host combination into the global acl_cache
  906.   SYNOPSIS
  907.     acl_insert_db()
  908.     user User name
  909.     host Host name
  910.     db Database name
  911.     privileges Bitmap of privileges
  912.   NOTES
  913.     acl_cache->lock must be locked when calling this
  914. */
  915. static void acl_insert_db(const char *user, const char *host, const char *db,
  916.   ulong privileges)
  917. {
  918.   ACL_DB acl_db;
  919.   safe_mutex_assert_owner(&acl_cache->lock);
  920.   acl_db.user=strdup_root(&mem,user);
  921.   update_hostname(&acl_db.host,strdup_root(&mem,host));
  922.   acl_db.db=strdup_root(&mem,db);
  923.   acl_db.access=privileges;
  924.   acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
  925.   VOID(push_dynamic(&acl_dbs,(gptr) &acl_db));
  926.   qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  927. sizeof(ACL_DB),(qsort_cmp) acl_compare);
  928. }
  929. /*
  930.   Get privilege for a host, user and db combination
  931.   as db_is_pattern changes the semantics of comparison,
  932.   acl_cache is not used if db_is_pattern is set.
  933. */
  934. ulong acl_get(const char *host, const char *ip,
  935.               const char *user, const char *db, my_bool db_is_pattern)
  936. {
  937.   ulong host_access= ~(ulong)0,db_access= 0;
  938.   uint i,key_length;
  939.   char key[ACL_KEY_LENGTH],*tmp_db,*end;
  940.   acl_entry *entry;
  941.   DBUG_ENTER("acl_get");
  942.   VOID(pthread_mutex_lock(&acl_cache->lock));
  943.   end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db);
  944.   if (lower_case_table_names)
  945.   {
  946.     my_casedn_str(files_charset_info, tmp_db);
  947.     db=tmp_db;
  948.   }
  949.   key_length=(uint) (end-key);
  950.   if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search(key,key_length)))
  951.   {
  952.     db_access=entry->access;
  953.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  954.     DBUG_PRINT("exit", ("access: 0x%lx", db_access));
  955.     DBUG_RETURN(db_access);
  956.   }
  957.   /*
  958.     Check if there are some access rights for database and user
  959.   */
  960.   for (i=0 ; i < acl_dbs.elements ; i++)
  961.   {
  962.     ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  963.     if (!acl_db->user || !strcmp(user,acl_db->user))
  964.     {
  965.       if (compare_hostname(&acl_db->host,host,ip))
  966.       {
  967. if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
  968. {
  969.   db_access=acl_db->access;
  970.   if (acl_db->host.hostname)
  971.     goto exit; // Fully specified. Take it
  972.   break; /* purecov: tested */
  973. }
  974.       }
  975.     }
  976.   }
  977.   if (!db_access)
  978.     goto exit; // Can't be better
  979.   /*
  980.     No host specified for user. Get hostdata from host table
  981.   */
  982.   host_access=0; // Host must be found
  983.   for (i=0 ; i < acl_hosts.elements ; i++)
  984.   {
  985.     ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
  986.     if (compare_hostname(&acl_host->host,host,ip))
  987.     {
  988.       if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern))
  989.       {
  990. host_access=acl_host->access; // Fully specified. Take it
  991. break;
  992.       }
  993.     }
  994.   }
  995. exit:
  996.   /* Save entry in cache for quick retrieval */
  997.   if (!db_is_pattern &&
  998.       (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
  999.   {
  1000.     entry->access=(db_access & host_access);
  1001.     entry->length=key_length;
  1002.     memcpy((gptr) entry->key,key,key_length);
  1003.     acl_cache->add(entry);
  1004.   }
  1005.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  1006.   DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
  1007.   DBUG_RETURN(db_access & host_access);
  1008. }
  1009. /*
  1010.   Check if there are any possible matching entries for this host
  1011.   NOTES
  1012.     All host names without wild cards are stored in a hash table,
  1013.     entries with wildcards are stored in a dynamic array
  1014. */
  1015. static void init_check_host(void)
  1016. {
  1017.   DBUG_ENTER("init_check_host");
  1018.   VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
  1019.   acl_users.elements,1));
  1020.   VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
  1021.  (hash_get_key) check_get_key,0,0));
  1022.   if (!allow_all_hosts)
  1023.   {
  1024.     for (uint i=0 ; i < acl_users.elements ; i++)
  1025.     {
  1026.       ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  1027.       if (strchr(acl_user->host.hostname,wild_many) ||
  1028.   strchr(acl_user->host.hostname,wild_one) ||
  1029.   acl_user->host.ip_mask)
  1030.       { // Has wildcard
  1031. uint j;
  1032. for (j=0 ; j < acl_wild_hosts.elements ; j++)
  1033. { // Check if host already exists
  1034.   acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
  1035.        acl_host_and_ip *);
  1036.   if (!my_strcasecmp(system_charset_info,
  1037.                              acl_user->host.hostname, acl->hostname))
  1038.     break; // already stored
  1039. }
  1040. if (j == acl_wild_hosts.elements) // If new
  1041.   (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
  1042.       }
  1043.       else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
  1044.     (uint) strlen(acl_user->host.hostname)))
  1045.       {
  1046. if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
  1047. { // End of memory
  1048.   allow_all_hosts=1; // Should never happen
  1049.   DBUG_VOID_RETURN;
  1050. }
  1051.       }
  1052.     }
  1053.   }
  1054.   freeze_size(&acl_wild_hosts);
  1055.   freeze_size(&acl_check_hosts.array);
  1056.   DBUG_VOID_RETURN;
  1057. }
  1058. /* Return true if there is no users that can match the given host */
  1059. bool acl_check_host(const char *host, const char *ip)
  1060. {
  1061.   if (allow_all_hosts)
  1062.     return 0;
  1063.   VOID(pthread_mutex_lock(&acl_cache->lock));
  1064.   if (host && hash_search(&acl_check_hosts,(byte*) host,(uint) strlen(host)) ||
  1065.       ip && hash_search(&acl_check_hosts,(byte*) ip,(uint) strlen(ip)))
  1066.   {
  1067.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  1068.     return 0; // Found host
  1069.   }
  1070.   for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
  1071.   {
  1072.     acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
  1073.     if (compare_hostname(acl, host, ip))
  1074.     {
  1075.       VOID(pthread_mutex_unlock(&acl_cache->lock));
  1076.       return 0; // Host ok
  1077.     }
  1078.   }
  1079.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  1080.   return 1; // Host is not allowed
  1081. }
  1082. /*
  1083.   Check if the user is allowed to change password
  1084.   SYNOPSIS:
  1085.     check_change_password()
  1086.     thd THD
  1087.     host hostname for the user
  1088.     user user name
  1089.     new_password new password
  1090.   NOTE:
  1091.     new_password cannot be NULL
  1092.     RETURN VALUE
  1093.       0 OK
  1094.       1 ERROR  ; In this case the error is sent to the client.
  1095. */
  1096. bool check_change_password(THD *thd, const char *host, const char *user,
  1097.                            char *new_password, uint new_password_len)
  1098. {
  1099.   if (!initialized)
  1100.   {
  1101.     net_printf(thd,ER_OPTION_PREVENTS_STATEMENT,
  1102.              "--skip-grant-tables");
  1103.     return(1);
  1104.   }
  1105.   if (!thd->slave_thread &&
  1106.       (strcmp(thd->user,user) ||
  1107.        my_strcasecmp(system_charset_info, host, thd->priv_host)))
  1108.   {
  1109.     if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
  1110.       return(1);
  1111.   }
  1112.   if (!thd->slave_thread && !thd->user[0])
  1113.   {
  1114.     send_error(thd, ER_PASSWORD_ANONYMOUS_USER);
  1115.     return(1);
  1116.   }
  1117.   uint len=strlen(new_password);
  1118.   if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
  1119.       len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  1120.   {
  1121.     net_printf(thd, 0,
  1122.                "Password hash should be a %d-digit hexadecimal number",
  1123.                SCRAMBLED_PASSWORD_CHAR_LENGTH);
  1124.     return -1;
  1125.   }
  1126.   return(0);
  1127. }
  1128. /*
  1129.   Change a password for a user
  1130.   SYNOPSIS
  1131.     change_password()
  1132.     thd Thread handle
  1133.     host Hostname
  1134.     user User name
  1135.     new_password New password for host@user
  1136.   RETURN VALUES
  1137.     0 ok
  1138.     1 ERROR; In this case the error is sent to the client.
  1139. */
  1140. bool change_password(THD *thd, const char *host, const char *user,
  1141.      char *new_password)
  1142. {
  1143.   TABLE_LIST tables;
  1144.   TABLE *table;
  1145.   /* Buffer should be extended when password length is extended. */
  1146.   char buff[512];
  1147.   ulong query_length;
  1148.   uint new_password_len= strlen(new_password);
  1149.   bool result= 1;
  1150.   DBUG_ENTER("change_password");
  1151.   DBUG_PRINT("enter",("host: '%s'  user: '%s'  new_password: '%s'",
  1152.       host,user,new_password));
  1153.   DBUG_ASSERT(host != 0); // Ensured by parent
  1154.   if (check_change_password(thd, host, user, new_password, new_password_len))
  1155.     DBUG_RETURN(1);
  1156.   bzero((char*) &tables, sizeof(tables));
  1157.   tables.alias=tables.real_name= (char*) "user";
  1158.   tables.db= (char*) "mysql";
  1159. #ifdef HAVE_REPLICATION
  1160.   /*
  1161.     GRANT and REVOKE are applied the slave in/exclusion rules as they are
  1162.     some kind of updates to the mysql.% tables.
  1163.   */
  1164.   if (thd->slave_thread && table_rules_on)
  1165.   {
  1166.     /*
  1167.       The tables must be marked "updating" so that tables_ok() takes them into
  1168.       account in tests.  It's ok to leave 'updating' set after tables_ok.
  1169.     */
  1170.     tables.updating= 1;
  1171.     /* Thanks to bzero, tables.next==0 */
  1172.     if (!tables_ok(0, &tables))
  1173.       DBUG_RETURN(0);
  1174.   }
  1175. #endif
  1176.   if (!(table= open_ltable(thd, &tables, TL_WRITE)))
  1177.     DBUG_RETURN(1);
  1178.   VOID(pthread_mutex_lock(&acl_cache->lock));
  1179.   ACL_USER *acl_user;
  1180.   if (!(acl_user= find_acl_user(host, user, TRUE)))
  1181.   {
  1182.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  1183.     send_error(thd, ER_PASSWORD_NO_MATCH);
  1184.     goto end;
  1185.   }
  1186.   /* update loaded acl entry: */
  1187.   set_user_salt(acl_user, new_password, new_password_len);
  1188.   if (update_user_table(thd, table,
  1189. acl_user->host.hostname ? acl_user->host.hostname : "",
  1190. acl_user->user ? acl_user->user : "",
  1191. new_password, new_password_len))
  1192.   {
  1193.     VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
  1194.     send_error(thd,0); /* purecov: deadcode */
  1195.     goto end;
  1196.   }
  1197.   acl_cache->clear(1); // Clear locked hostname cache
  1198.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  1199.   result= 0;
  1200.   query_length=
  1201.     my_sprintf(buff,
  1202.        (buff,"SET PASSWORD FOR "%-.120s"@"%-.120s"="%-.120s"",
  1203. acl_user->user ? acl_user->user : "",
  1204. acl_user->host.hostname ? acl_user->host.hostname : "",
  1205. new_password));
  1206.   mysql_update_log.write(thd, buff, query_length);
  1207.   if (mysql_bin_log.is_open())
  1208.   {
  1209.     thd->clear_error();
  1210.     Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
  1211.     mysql_bin_log.write(&qinfo);
  1212.   }
  1213. end:
  1214.   close_thread_tables(thd);
  1215.   DBUG_RETURN(result);
  1216. }
  1217. /*
  1218.   Find first entry that matches the current user
  1219. */
  1220. static ACL_USER *
  1221. find_acl_user(const char *host, const char *user, my_bool exact)
  1222. {
  1223.   DBUG_ENTER("find_acl_user");
  1224.   DBUG_PRINT("enter",("host: '%s'  user: '%s'",host,user));
  1225.   for (uint i=0 ; i < acl_users.elements ; i++)
  1226.   {
  1227.     ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  1228.     DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
  1229.        user,
  1230.        acl_user->user ? acl_user->user : "",
  1231.        host,
  1232.        acl_user->host.hostname ? acl_user->host.hostname :
  1233.        ""));
  1234.     if (!acl_user->user && !user[0] ||
  1235. acl_user->user && !strcmp(user,acl_user->user))
  1236.     {
  1237.       if (exact ? !my_strcasecmp(&my_charset_latin1, host,
  1238.                                  acl_user->host.hostname) :
  1239.           compare_hostname(&acl_user->host,host,host))
  1240.       {
  1241. DBUG_RETURN(acl_user);
  1242.       }
  1243.     }
  1244.   }
  1245.   DBUG_RETURN(0);
  1246. }
  1247. /*
  1248.   Comparing of hostnames
  1249.   NOTES
  1250.   A hostname may be of type:
  1251.   hostname   (May include wildcards);   monty.pp.sci.fi
  1252.   ip    (May include wildcards);   192.168.0.0
  1253.   ip/netmask       192.168.0.0/255.255.255.0
  1254.   A net mask of 0.0.0.0 is not allowed.
  1255. */
  1256. static const char *calc_ip(const char *ip, long *val, char end)
  1257. {
  1258.   long ip_val,tmp;
  1259.   if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
  1260.     return 0;
  1261.   ip_val<<=24;
  1262.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  1263.     return 0;
  1264.   ip_val+=tmp<<16;
  1265.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  1266.     return 0;
  1267.   ip_val+=tmp<<8;
  1268.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
  1269.     return 0;
  1270.   *val=ip_val+tmp;
  1271.   return ip;
  1272. }
  1273. static void update_hostname(acl_host_and_ip *host, const char *hostname)
  1274. {
  1275.   host->hostname=(char*) hostname; // This will not be modified!
  1276.   if (!hostname ||
  1277.       (!(hostname=calc_ip(hostname,&host->ip,'/')) ||
  1278.        !(hostname=calc_ip(hostname+1,&host->ip_mask,''))))
  1279.   {
  1280.     host->ip= host->ip_mask=0; // Not a masked ip
  1281.   }
  1282. }
  1283. static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
  1284.      const char *ip)
  1285. {
  1286.   long tmp;
  1287.   if (host->ip_mask && ip && calc_ip(ip,&tmp,''))
  1288.   {
  1289.     return (tmp & host->ip_mask) == host->ip;
  1290.   }
  1291.   return (!host->hostname ||
  1292.   (hostname && !wild_case_compare(system_charset_info,
  1293.                                           hostname,host->hostname)) ||
  1294.   (ip && !wild_compare(ip,host->hostname,0)));
  1295. }
  1296. bool hostname_requires_resolving(const char *hostname)
  1297. {
  1298.   char cur;
  1299.   if (!hostname)
  1300.     return FALSE;
  1301.   int namelen= strlen(hostname);
  1302.   int lhlen= strlen(my_localhost);
  1303.   if ((namelen == lhlen) &&
  1304.       !my_strnncoll(system_charset_info, (const uchar *)hostname,  namelen,
  1305.     (const uchar *)my_localhost, strlen(my_localhost)))
  1306.     return FALSE;
  1307.   for (; (cur=*hostname); hostname++)
  1308.   {
  1309.     if ((cur != '%') && (cur != '_') && (cur != '.') && (cur != '/') &&
  1310. ((cur < '0') || (cur > '9')))
  1311.       return TRUE;
  1312.   }
  1313.   return FALSE;
  1314. }
  1315. /*
  1316.   Update record for user in mysql.user privilege table with new password.
  1317.   SYNOPSIS
  1318.     update_user_table()
  1319.       thd               Thread handle
  1320.       table             Pointer to TABLE object for open mysql.user table
  1321.       host/user         Hostname/username pair identifying user for which
  1322.                         new password should be set
  1323.       new_password      New password
  1324.       new_password_len  Length of new password
  1325. */
  1326. static bool update_user_table(THD *thd, TABLE *table,
  1327.                               const char *host, const char *user,
  1328.       const char *new_password, uint new_password_len)
  1329. {
  1330.   int error;
  1331.   DBUG_ENTER("update_user_table");
  1332.   DBUG_PRINT("enter",("user: %s  host: %s",user,host));
  1333.   table->field[0]->store(host,(uint) strlen(host), system_charset_info);
  1334.   table->field[1]->store(user,(uint) strlen(user), system_charset_info);
  1335.   table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1336.   if (table->file->index_read_idx(table->record[0],0,
  1337.   (byte*) table->field[0]->ptr,
  1338.   table->key_info[0].key_length,
  1339.   HA_READ_KEY_EXACT))
  1340.   {
  1341.     my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
  1342.     DBUG_RETURN(1); /* purecov: deadcode */
  1343.   }
  1344.   store_record(table,record[1]);
  1345.   table->field[2]->store(new_password, new_password_len, system_charset_info);
  1346.   if ((error=table->file->update_row(table->record[1],table->record[0])))
  1347.   {
  1348.     table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1349.     DBUG_RETURN(1);
  1350.   }
  1351.   DBUG_RETURN(0);
  1352. }
  1353. /* Return 1 if we are allowed to create new users */
  1354. static bool test_if_create_new_users(THD *thd)
  1355. {
  1356.   bool create_new_users=1;    // Assume that we are allowed to create new users
  1357.   if (opt_safe_user_create && !(thd->master_access & INSERT_ACL))
  1358.   {
  1359.     TABLE_LIST tl;
  1360.     ulong db_access;
  1361.     bzero((char*) &tl,sizeof(tl));
  1362.     tl.db=    (char*) "mysql";
  1363.     tl.real_name=  (char*) "user";
  1364.     db_access=acl_get(thd->host, thd->ip,
  1365.       thd->priv_user, tl.db, 0);
  1366.     if (!(db_access & INSERT_ACL))
  1367.     {
  1368.       if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1))
  1369. create_new_users=0;
  1370.     }
  1371.   }
  1372.   return create_new_users;
  1373. }
  1374. /****************************************************************************
  1375.   Handle GRANT commands
  1376. ****************************************************************************/
  1377. static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
  1378.       ulong rights, bool revoke_grant,
  1379.       bool create_user)
  1380. {
  1381.   int error = -1;
  1382.   bool old_row_exists=0;
  1383.   const char *password= "";
  1384.   uint password_len= 0;
  1385.   char what= (revoke_grant) ? 'N' : 'Y';
  1386.   DBUG_ENTER("replace_user_table");
  1387.   safe_mutex_assert_owner(&acl_cache->lock);
  1388.   if (combo.password.str && combo.password.str[0])
  1389.   {
  1390.     if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
  1391.         combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  1392.     {
  1393.       my_printf_error(ER_UNKNOWN_ERROR,
  1394.                       "Password hash should be a %d-digit hexadecimal number",
  1395.                       MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
  1396.       DBUG_RETURN(-1);
  1397.     }
  1398.     password_len= combo.password.length;
  1399.     password=combo.password.str;
  1400.   }
  1401.   table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
  1402.   table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
  1403.   table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1404.   if (table->file->index_read_idx(table->record[0], 0,
  1405.   (byte*) table->field[0]->ptr,
  1406.   table->key_info[0].key_length,
  1407.   HA_READ_KEY_EXACT))
  1408.   {
  1409.     if (!create_user)
  1410.     {
  1411.       if (what == 'N')
  1412. my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
  1413.       else
  1414. my_error(ER_NO_PERMISSION_TO_CREATE_USER, MYF(0),
  1415.                  thd->user, thd->host_or_ip);
  1416.       goto end;
  1417.     }
  1418.     old_row_exists = 0;
  1419.     restore_record(table,default_values);       // cp empty row from default_values
  1420.     table->field[0]->store(combo.host.str,combo.host.length,
  1421.                            system_charset_info);
  1422.     table->field[1]->store(combo.user.str,combo.user.length,
  1423.                            system_charset_info);
  1424.     table->field[2]->store(password, password_len,
  1425.                            system_charset_info);
  1426.   }
  1427.   else
  1428.   {
  1429.     old_row_exists = 1;
  1430.     store_record(table,record[1]); // Save copy for update
  1431.     if (combo.password.str) // If password given
  1432.       table->field[2]->store(password, password_len, system_charset_info);
  1433.     else if (!rights && !revoke_grant && thd->lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
  1434.      !thd->lex->mqh.bits)
  1435.     {
  1436.       DBUG_RETURN(0);
  1437.     }
  1438.   }
  1439.   /* Update table columns with new privileges */
  1440.   Field **tmp_field;
  1441.   ulong priv;
  1442.   uint next_field;
  1443.   for (tmp_field= table->field+3, priv = SELECT_ACL;
  1444.        *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM &&
  1445.  ((Field_enum*) (*tmp_field))->typelib->count == 2 ;
  1446.        tmp_field++, priv <<= 1)
  1447.   {
  1448.     if (priv & rights)  // set requested privileges
  1449.       (*tmp_field)->store(&what, 1, &my_charset_latin1);
  1450.   }
  1451.   rights= get_access(table, 3, &next_field);
  1452.   DBUG_PRINT("info",("table->fields: %d",table->fields));
  1453.   if (table->fields >= 31) /* From 4.0.0 we have more fields */
  1454.   {
  1455.     /* We write down SSL related ACL stuff */
  1456.     switch (thd->lex->ssl_type) {
  1457.     case SSL_TYPE_ANY:
  1458.       table->field[next_field]->store("ANY", 3, &my_charset_latin1);
  1459.       table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1460.       table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1461.       table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1462.       break;
  1463.     case SSL_TYPE_X509:
  1464.       table->field[next_field]->store("X509", 4, &my_charset_latin1);
  1465.       table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1466.       table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1467.       table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1468.       break;
  1469.     case SSL_TYPE_SPECIFIED:
  1470.       table->field[next_field]->store("SPECIFIED", 9, &my_charset_latin1);
  1471.       table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1472.       table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1473.       table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1474.       if (thd->lex->ssl_cipher)
  1475.         table->field[next_field+1]->store(thd->lex->ssl_cipher,
  1476.                                           strlen(thd->lex->ssl_cipher),
  1477.                                           system_charset_info);
  1478.       if (thd->lex->x509_issuer)
  1479.         table->field[next_field+2]->store(thd->lex->x509_issuer,
  1480.                                           strlen(thd->lex->x509_issuer),
  1481.                                           system_charset_info);
  1482.       if (thd->lex->x509_subject)
  1483.         table->field[next_field+3]->store(thd->lex->x509_subject,
  1484.                                           strlen(thd->lex->x509_subject),
  1485.                                           system_charset_info);
  1486.       break;
  1487.     case SSL_TYPE_NOT_SPECIFIED:
  1488.       break;
  1489.     case SSL_TYPE_NONE:
  1490.       table->field[next_field]->store("", 0, &my_charset_latin1);
  1491.       table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1492.       table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1493.       table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1494.       break;
  1495.     }
  1496.     /* Skip over SSL related fields to first user limits related field */
  1497.     next_field+= 4;
  1498.     USER_RESOURCES mqh= thd->lex->mqh;
  1499.     if (mqh.bits & 1)
  1500.       table->field[next_field]->store((longlong) mqh.questions);
  1501.     if (mqh.bits & 2)
  1502.       table->field[next_field+1]->store((longlong) mqh.updates);
  1503.     if (mqh.bits & 4)
  1504.       table->field[next_field+2]->store((longlong) mqh.connections);
  1505.     mqh_used = mqh_used || mqh.questions || mqh.updates || mqh.connections;
  1506.   }
  1507.   if (old_row_exists)
  1508.   {
  1509.     /*
  1510.       We should NEVER delete from the user table, as a uses can still
  1511.       use mysqld even if he doesn't have any privileges in the user table!
  1512.     */
  1513.     table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1514.     if (cmp_record(table,record[1]) &&
  1515. (error=table->file->update_row(table->record[1],table->record[0])))
  1516.     { // This should never happen
  1517.       table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1518.       error= -1; /* purecov: deadcode */
  1519.       goto end; /* purecov: deadcode */
  1520.     }
  1521.   }
  1522.   else if ((error=table->file->write_row(table->record[0]))) // insert
  1523.   { // This should never happen
  1524.     if (error && error != HA_ERR_FOUND_DUPP_KEY &&
  1525. error != HA_ERR_FOUND_DUPP_UNIQUE) /* purecov: inspected */
  1526.     {
  1527.       table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1528.       error= -1; /* purecov: deadcode */
  1529.       goto end; /* purecov: deadcode */
  1530.     }
  1531.   }
  1532.   error=0; // Privileges granted / revoked
  1533. end:
  1534.   if (!error)
  1535.   {
  1536.     acl_cache->clear(1); // Clear privilege cache
  1537.     if (old_row_exists)
  1538.       acl_update_user(combo.user.str, combo.host.str,
  1539.                       combo.password.str, password_len,
  1540.       thd->lex->ssl_type,
  1541.       thd->lex->ssl_cipher,
  1542.       thd->lex->x509_issuer,
  1543.       thd->lex->x509_subject,
  1544.       &thd->lex->mqh,
  1545.       rights);
  1546.     else
  1547.       acl_insert_user(combo.user.str, combo.host.str, password, password_len,
  1548.       thd->lex->ssl_type,
  1549.       thd->lex->ssl_cipher,
  1550.       thd->lex->x509_issuer,
  1551.       thd->lex->x509_subject,
  1552.       &thd->lex->mqh,
  1553.       rights);
  1554.   }
  1555.   DBUG_RETURN(error);
  1556. }
  1557. /*
  1558.   change grants in the mysql.db table
  1559. */
  1560. static int replace_db_table(TABLE *table, const char *db,
  1561.     const LEX_USER &combo,
  1562.     ulong rights, bool revoke_grant)
  1563. {
  1564.   uint i;
  1565.   ulong priv,store_rights;
  1566.   bool old_row_exists=0;
  1567.   int error;
  1568.   char what= (revoke_grant) ? 'N' : 'Y';
  1569.   DBUG_ENTER("replace_db_table");
  1570.   if (!initialized)
  1571.   {
  1572.     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  1573.     DBUG_RETURN(-1);
  1574.   }
  1575.   /* Check if there is such a user in user table in memory? */
  1576.   if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
  1577.   {
  1578.     my_error(ER_PASSWORD_NO_MATCH,MYF(0));
  1579.     DBUG_RETURN(-1);
  1580.   }
  1581.   table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
  1582.   table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1583.   table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
  1584.   table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1585.   if (table->file->index_read_idx(table->record[0],0,
  1586.   (byte*) table->field[0]->ptr,
  1587.   table->key_info[0].key_length,
  1588.   HA_READ_KEY_EXACT))
  1589.   {
  1590.     if (what == 'N')
  1591.     { // no row, no revoke
  1592.       my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
  1593.       goto abort;
  1594.     }
  1595.     old_row_exists = 0;
  1596.     restore_record(table,default_values); // cp empty row from default_values
  1597.     table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
  1598.     table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1599.     table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
  1600.   }
  1601.   else
  1602.   {
  1603.     old_row_exists = 1;
  1604.     store_record(table,record[1]);
  1605.   }
  1606.   store_rights=get_rights_for_db(rights);
  1607.   for (i= 3, priv= 1; i < table->fields; i++, priv <<= 1)
  1608.   {
  1609.     if (priv & store_rights) // do it if priv is chosen
  1610.       table->field [i]->store(&what,1, &my_charset_latin1);// set requested privileges
  1611.   }
  1612.   rights=get_access(table,3);
  1613.   rights=fix_rights_for_db(rights);
  1614.   if (old_row_exists)
  1615.   {
  1616.     /* update old existing row */
  1617.     if (rights)
  1618.     {
  1619.       table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1620.       if ((error=table->file->update_row(table->record[1],table->record[0])))
  1621. goto table_error; /* purecov: deadcode */
  1622.     }
  1623.     else /* must have been a revoke of all privileges */
  1624.     {
  1625.       if ((error = table->file->delete_row(table->record[1])))
  1626. goto table_error; /* purecov: deadcode */
  1627.     }
  1628.   }
  1629.   else if (rights && (error=table->file->write_row(table->record[0])))
  1630.   {
  1631.     if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
  1632.       goto table_error; /* purecov: deadcode */
  1633.   }
  1634.   acl_cache->clear(1); // Clear privilege cache
  1635.   if (old_row_exists)
  1636.     acl_update_db(combo.user.str,combo.host.str,db,rights);
  1637.   else
  1638.   if (rights)
  1639.     acl_insert_db(combo.user.str,combo.host.str,db,rights);
  1640.   DBUG_RETURN(0);
  1641.   /* This could only happen if the grant tables got corrupted */
  1642. table_error:
  1643.   table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1644. abort:
  1645.   DBUG_RETURN(-1);
  1646. }
  1647. class GRANT_COLUMN :public Sql_alloc
  1648. {
  1649. public:
  1650.   char *column;
  1651.   ulong rights;
  1652.   uint key_length;
  1653.   GRANT_COLUMN(String &c,  ulong y) :rights (y)
  1654.   {
  1655.     column= memdup_root(&memex,c.ptr(), key_length=c.length());
  1656.   }
  1657. };
  1658. static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
  1659.     my_bool not_used __attribute__((unused)))
  1660. {
  1661.   *length=buff->key_length;
  1662.   return (byte*) buff->column;
  1663. }
  1664. class GRANT_TABLE :public Sql_alloc
  1665. {
  1666. public:
  1667.   acl_host_and_ip host;
  1668.   char *db, *user, *tname, *hash_key;
  1669.   ulong privs, cols;
  1670.   ulong sort;
  1671.   uint key_length;
  1672.   HASH hash_columns;
  1673.   GRANT_TABLE(const char *h, const char *d,const char *u,
  1674.               const char *t, ulong p, ulong c);
  1675.   GRANT_TABLE (TABLE *form, TABLE *col_privs);
  1676.   bool ok() { return privs != 0 || cols != 0; }
  1677. };
  1678. GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
  1679.                          const char *t, ulong p, ulong c)
  1680.   :privs(p), cols(c)
  1681. {
  1682.   /* Host given by user */
  1683.   update_hostname(&host, strdup_root(&memex, h));
  1684.   db =   strdup_root(&memex,d);
  1685.   user = strdup_root(&memex,u);
  1686.   sort=  get_sort(3,host.hostname,db,user);
  1687.   tname= strdup_root(&memex,t);
  1688.   if (lower_case_table_names)
  1689.   {
  1690.     my_casedn_str(files_charset_info, db);
  1691.     my_casedn_str(files_charset_info, tname);
  1692.   }
  1693.   key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
  1694.   hash_key = (char*) alloc_root(&memex,key_length);
  1695.   strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  1696.   (void) hash_init(&hash_columns,system_charset_info,
  1697.                    0,0,0, (hash_get_key) get_key_column,0,0);
  1698. }
  1699. GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
  1700. {
  1701.   byte key[MAX_KEY_LENGTH];
  1702.   update_hostname(&host, get_field(&memex, form->field[0]));
  1703.   db=    get_field(&memex,form->field[1]);
  1704.   user=  get_field(&memex,form->field[2]);
  1705.   if (!user)
  1706.     user= (char*) "";
  1707.   sort=  get_sort(3, host.hostname, db, user);
  1708.   tname= get_field(&memex,form->field[3]);
  1709.   if (!db || !tname)
  1710.   {
  1711.     /* Wrong table row; Ignore it */
  1712.     privs = cols = 0; /* purecov: inspected */
  1713.     return; /* purecov: inspected */
  1714.   }
  1715.   if (lower_case_table_names)
  1716.   {
  1717.     my_casedn_str(files_charset_info, db);
  1718.     my_casedn_str(files_charset_info, tname);
  1719.   }
  1720.   key_length = ((uint) strlen(db) + (uint) strlen(user) +
  1721.                 (uint) strlen(tname) + 3);
  1722.   hash_key = (char*) alloc_root(&memex,key_length);
  1723.   strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  1724.   privs = (ulong) form->field[6]->val_int();
  1725.   cols  = (ulong) form->field[7]->val_int();
  1726.   privs = fix_rights_for_table(privs);
  1727.   cols =  fix_rights_for_column(cols);
  1728.   (void) hash_init(&hash_columns,system_charset_info,
  1729.                    0,0,0, (hash_get_key) get_key_column,0,0);
  1730.   if (cols)
  1731.   {
  1732.     int key_len;
  1733.     col_privs->field[0]->store(host.hostname,
  1734.                                host.hostname ? (uint) strlen(host.hostname) : 0,
  1735.                                system_charset_info);
  1736.     col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1737.     col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
  1738.     col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
  1739.     key_len=(col_privs->field[0]->pack_length()+
  1740.              col_privs->field[1]->pack_length()+
  1741.              col_privs->field[2]->pack_length()+
  1742.              col_privs->field[3]->pack_length());
  1743.     key_copy(key,col_privs,0,key_len);
  1744.     col_privs->field[4]->store("",0, &my_charset_latin1);
  1745.     col_privs->file->ha_index_init(0);
  1746.     if (col_privs->file->index_read(col_privs->record[0],
  1747.                                     (byte*) col_privs->field[0]->ptr,
  1748.                                     key_len, HA_READ_KEY_EXACT))
  1749.     {
  1750.       cols = 0; /* purecov: deadcode */
  1751.       col_privs->file->ha_index_end();
  1752.       return;
  1753.     }
  1754.     do
  1755.     {
  1756.       String *res,column_name;
  1757.       GRANT_COLUMN *mem_check;
  1758.       /* As column name is a string, we don't have to supply a buffer */
  1759.       res=col_privs->field[4]->val_str(&column_name);
  1760.       ulong priv= (ulong) col_privs->field[6]->val_int();
  1761.       if (!(mem_check = new GRANT_COLUMN(*res,
  1762.                                          fix_rights_for_column(priv))))
  1763.       {
  1764.         /* Don't use this entry */
  1765.         privs = cols = 0; /* purecov: deadcode */
  1766.         return; /* purecov: deadcode */
  1767.       }
  1768.       my_hash_insert(&hash_columns, (byte *) mem_check);
  1769.     } while (!col_privs->file->index_next(col_privs->record[0]) &&
  1770.              !key_cmp_if_same(col_privs,key,0,key_len));
  1771.     col_privs->file->ha_index_end();
  1772.   }
  1773. }
  1774. static byte* get_grant_table(GRANT_TABLE *buff,uint *length,
  1775.      my_bool not_used __attribute__((unused)))
  1776. {
  1777.   *length=buff->key_length;
  1778.   return (byte*) buff->hash_key;
  1779. }
  1780. void free_grant_table(GRANT_TABLE *grant_table)
  1781. {
  1782.   hash_free(&grant_table->hash_columns);
  1783. }
  1784. /* Search after a matching grant. Prefer exact grants before not exact ones */
  1785. static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
  1786.       const char *db,
  1787.       const char *user, const char *tname,
  1788.       bool exact)
  1789. {
  1790.   char helping [NAME_LEN*2+USERNAME_LENGTH+3];
  1791.   uint len;
  1792.   GRANT_TABLE *grant_table,*found=0;
  1793.   len  = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
  1794.   for (grant_table=(GRANT_TABLE*) hash_search(&column_priv_hash,
  1795.       (byte*) helping,
  1796.       len) ;
  1797.        grant_table ;
  1798.        grant_table= (GRANT_TABLE*) hash_next(&column_priv_hash,(byte*) helping,
  1799.      len))
  1800.   {
  1801.     if (exact)
  1802.     {
  1803.       if (compare_hostname(&grant_table->host, host, ip))
  1804. return grant_table;
  1805.     }
  1806.     else
  1807.     {
  1808.       if (compare_hostname(&grant_table->host, host, ip) &&
  1809.           (!found || found->sort < grant_table->sort))
  1810. found=grant_table; // Host ok
  1811.     }
  1812.   }
  1813.   return found;
  1814. }
  1815. inline GRANT_COLUMN *
  1816. column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
  1817. {
  1818.   return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length);
  1819. }
  1820. static int replace_column_table(GRANT_TABLE *g_t,
  1821. TABLE *table, const LEX_USER &combo,
  1822. List <LEX_COLUMN> &columns,
  1823. const char *db, const char *table_name,
  1824. ulong rights, bool revoke_grant)
  1825. {
  1826.   int error=0,result=0;
  1827.   uint key_length;
  1828.   byte key[MAX_KEY_LENGTH];
  1829.   DBUG_ENTER("replace_column_table");
  1830.   table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
  1831.   table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1832.   table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
  1833.   table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
  1834.   key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
  1835.       table->field[2]->pack_length()+ table->field[3]->pack_length());
  1836.   key_copy(key,table,0,key_length);
  1837.   rights &= COL_ACLS; // Only ACL for columns
  1838.   /* first fix privileges for all columns in column list */
  1839.   List_iterator <LEX_COLUMN> iter(columns);
  1840.   class LEX_COLUMN *xx;
  1841.   table->file->ha_index_init(0);
  1842.   while ((xx=iter++))
  1843.   {
  1844.     ulong privileges = xx->rights;
  1845.     bool old_row_exists=0;
  1846.     key_restore(table,key,0,key_length);
  1847.     table->field[4]->store(xx->column.ptr(),xx->column.length(),
  1848.                            system_charset_info);
  1849.     table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1850.     if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
  1851. table->key_info[0].key_length,
  1852. HA_READ_KEY_EXACT))
  1853.     {
  1854.       if (revoke_grant)
  1855.       {
  1856. my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  1857.                  combo.user.str, combo.host.str, table_name); /* purecov: inspected */
  1858. result= -1; /* purecov: inspected */
  1859. continue; /* purecov: inspected */
  1860.       }
  1861.       old_row_exists = 0;
  1862.       restore_record(table,default_values); // Get empty record
  1863.       key_restore(table,key,0,key_length);
  1864.       table->field[4]->store(xx->column.ptr(),xx->column.length(),
  1865.                              system_charset_info);
  1866.     }
  1867.     else
  1868.     {
  1869.       ulong tmp= (ulong) table->field[6]->val_int();
  1870.       tmp=fix_rights_for_column(tmp);
  1871.       if (revoke_grant)
  1872. privileges = tmp & ~(privileges | rights);
  1873.       else
  1874. privileges |= tmp;
  1875.       old_row_exists = 1;
  1876.       store_record(table,record[1]); // copy original row
  1877.     }
  1878.     table->field[6]->store((longlong) get_rights_for_column(privileges));
  1879.     if (old_row_exists)
  1880.     {
  1881.       if (privileges)
  1882. error=table->file->update_row(table->record[1],table->record[0]);
  1883.       else
  1884. error=table->file->delete_row(table->record[1]);
  1885.       if (error)
  1886.       {
  1887. table->file->print_error(error,MYF(0)); /* purecov: inspected */
  1888. result= -1; /* purecov: inspected */
  1889. goto end; /* purecov: inspected */
  1890.       }
  1891.       GRANT_COLUMN *grant_column = column_hash_search(g_t,
  1892.       xx->column.ptr(),
  1893.       xx->column.length());
  1894.       if (grant_column) // Should always be true
  1895. grant_column->rights = privileges; // Update hash
  1896.     }
  1897.     else // new grant
  1898.     {
  1899.       if ((error=table->file->write_row(table->record[0])))
  1900.       {
  1901. table->file->print_error(error,MYF(0)); /* purecov: inspected */
  1902. result= -1; /* purecov: inspected */
  1903. goto end; /* purecov: inspected */
  1904.       }
  1905.       GRANT_COLUMN *grant_column = new GRANT_COLUMN(xx->column,privileges);
  1906.       my_hash_insert(&g_t->hash_columns,(byte*) grant_column);
  1907.     }
  1908.   }
  1909.   /*
  1910.     If revoke of privileges on the table level, remove all such privileges
  1911.     for all columns
  1912.   */
  1913.   if (revoke_grant)
  1914.   {
  1915.     table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  1916.     if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,
  1917.                                 key_length,
  1918. HA_READ_KEY_EXACT))
  1919.       goto end;
  1920.     /* Scan through all rows with the same host,db,user and table */
  1921.     do
  1922.     {
  1923.       ulong privileges = (ulong) table->field[6]->val_int();
  1924.       privileges=fix_rights_for_column(privileges);
  1925.       store_record(table,record[1]);
  1926.       if (privileges & rights) // is in this record the priv to be revoked ??
  1927.       {
  1928. GRANT_COLUMN *grant_column = NULL;
  1929. char  colum_name_buf[HOSTNAME_LENGTH+1];
  1930. String column_name(colum_name_buf,sizeof(colum_name_buf),
  1931.                            system_charset_info);
  1932. privileges&= ~rights;
  1933. table->field[6]->store((longlong)
  1934.        get_rights_for_column(privileges));
  1935. table->field[4]->val_str(&column_name);
  1936. grant_column = column_hash_search(g_t,
  1937.   column_name.ptr(),
  1938.   column_name.length());
  1939. if (privileges)
  1940. {
  1941.   int tmp_error;
  1942.   if ((tmp_error=table->file->update_row(table->record[1],
  1943.  table->record[0])))
  1944.   { /* purecov: deadcode */
  1945.     table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  1946.     result= -1; /* purecov: deadcode */
  1947.     goto end; /* purecov: deadcode */
  1948.   }
  1949.   if (grant_column)
  1950.     grant_column->rights  = privileges; // Update hash
  1951. }
  1952. else
  1953. {
  1954.   int tmp_error;
  1955.   if ((tmp_error = table->file->delete_row(table->record[1])))
  1956.   { /* purecov: deadcode */
  1957.     table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  1958.     result= -1; /* purecov: deadcode */
  1959.     goto end; /* purecov: deadcode */
  1960.   }
  1961.   if (grant_column)
  1962.     hash_delete(&g_t->hash_columns,(byte*) grant_column);
  1963. }
  1964.       }
  1965.     } while (!table->file->index_next(table->record[0]) &&
  1966.      !key_cmp_if_same(table,key,0,key_length));
  1967.   }
  1968. end:
  1969.   table->file->ha_index_end();
  1970.   DBUG_RETURN(result);
  1971. }
  1972. static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
  1973.        TABLE *table, const LEX_USER &combo,
  1974.        const char *db, const char *table_name,
  1975.        ulong rights, ulong col_rights,
  1976.        bool revoke_grant)
  1977. {
  1978.   char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
  1979.   int old_row_exists = 1;
  1980.   int error=0;
  1981.   ulong store_table_rights, store_col_rights;
  1982.   DBUG_ENTER("replace_table_table");
  1983.   strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
  1984.   /*
  1985.     The following should always succeed as new users are created before
  1986.     this function is called!
  1987.   */
  1988.   if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
  1989.   {
  1990.     my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
  1991.     DBUG_RETURN(-1); /* purecov: deadcode */
  1992.   }
  1993.   restore_record(table,default_values); // Get empty record
  1994.   table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
  1995.   table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1996.   table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
  1997.   table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
  1998.   store_record(table,record[1]); // store at pos 1
  1999.   table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  2000.   if (table->file->index_read_idx(table->record[0],0,
  2001.   (byte*) table->field[0]->ptr,
  2002.   table->key_info[0].key_length,
  2003.   HA_READ_KEY_EXACT))
  2004.   {
  2005.     /*
  2006.       The following should never happen as we first check the in memory
  2007.       grant tables for the user.  There is however always a small change that
  2008.       the user has modified the grant tables directly.
  2009.     */
  2010.     if (revoke_grant)
  2011.     { // no row, no revoke
  2012.       my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  2013.                combo.user.str, combo.host.str,
  2014.                table_name); /* purecov: deadcode */
  2015.       DBUG_RETURN(-1); /* purecov: deadcode */
  2016.     }
  2017.     old_row_exists = 0;
  2018.     restore_record(table,record[1]); // Get saved record
  2019.   }
  2020.   store_table_rights= get_rights_for_table(rights);
  2021.   store_col_rights=   get_rights_for_column(col_rights);
  2022.   if (old_row_exists)
  2023.   {
  2024.     ulong j,k;
  2025.     store_record(table,record[1]);
  2026.     j = (ulong) table->field[6]->val_int();
  2027.     k = (ulong) table->field[7]->val_int();
  2028.     if (revoke_grant)
  2029.     {
  2030.       /* column rights are already fixed in mysql_table_grant */
  2031.       store_table_rights=j & ~store_table_rights;
  2032.     }
  2033.     else
  2034.     {
  2035.       store_table_rights|= j;
  2036.       store_col_rights|=   k;
  2037.     }
  2038.   }
  2039.   table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
  2040.   table->field[6]->store((longlong) store_table_rights);
  2041.   table->field[7]->store((longlong) store_col_rights);
  2042.   rights=fix_rights_for_table(store_table_rights);
  2043.   col_rights=fix_rights_for_column(store_col_rights);
  2044.   if (old_row_exists)
  2045.   {
  2046.     if (store_table_rights || store_col_rights)
  2047.     {
  2048.       if ((error=table->file->update_row(table->record[1],table->record[0])))
  2049. goto table_error; /* purecov: deadcode */
  2050.     }
  2051.     else if ((error = table->file->delete_row(table->record[1])))
  2052.       goto table_error; /* purecov: deadcode */
  2053.   }
  2054.   else
  2055.   {
  2056.     error=table->file->write_row(table->record[0]);
  2057.     if (error && error != HA_ERR_FOUND_DUPP_KEY)
  2058.       goto table_error; /* purecov: deadcode */
  2059.   }
  2060.   if (rights | col_rights)
  2061.   {
  2062.     grant_table->privs= rights;
  2063.     grant_table->cols= col_rights;
  2064.   }
  2065.   else
  2066.   {
  2067.     hash_delete(&column_priv_hash,(byte*) grant_table);
  2068.   }
  2069.   DBUG_RETURN(0);
  2070.   /* This should never happen */
  2071. table_error:
  2072.   table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  2073.   DBUG_RETURN(-1); /* purecov: deadcode */
  2074. }
  2075. /*
  2076.   Store table level and column level grants in the privilege tables
  2077.   SYNOPSIS
  2078.     mysql_table_grant()
  2079.     thd Thread handle
  2080.     table_list List of tables to give grant
  2081.     user_list List of users to give grant
  2082.     columns List of columns to give grant
  2083.     rights Table level grant
  2084.     revoke_grant Set to 1 if this is a REVOKE command
  2085.   RETURN
  2086.     0 ok
  2087.     1 error
  2088. */
  2089. int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
  2090.       List <LEX_USER> &user_list,
  2091.       List <LEX_COLUMN> &columns, ulong rights,
  2092.       bool revoke_grant)
  2093. {
  2094.   ulong column_priv= 0;
  2095.   List_iterator <LEX_USER> str_list (user_list);
  2096.   LEX_USER *Str;
  2097.   TABLE_LIST tables[3];
  2098.   bool create_new_users=0;
  2099.   DBUG_ENTER("mysql_table_grant");
  2100.   if (!initialized)
  2101.   {
  2102.     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
  2103.              "--skip-grant-tables"); /* purecov: inspected */
  2104.     DBUG_RETURN(-1); /* purecov: inspected */
  2105.   }
  2106.   if (rights & ~TABLE_ACLS)
  2107.   {
  2108.     my_error(ER_ILLEGAL_GRANT_FOR_TABLE,MYF(0));
  2109.     DBUG_RETURN(-1);
  2110.   }
  2111.   if (!revoke_grant)
  2112.   {
  2113.     if (columns.elements && !revoke_grant)
  2114.     {
  2115.       TABLE *table;
  2116.       class LEX_COLUMN *column;
  2117.       List_iterator <LEX_COLUMN> column_iter(columns);
  2118.       if (!(table=open_ltable(thd,table_list,TL_READ)))
  2119.         DBUG_RETURN(-1);
  2120.       while ((column = column_iter++))
  2121.       {
  2122.         uint unused_field_idx= NO_CACHED_FIELD_INDEX;
  2123.         Field *f= find_field_in_table(thd,table,column->column.ptr(),
  2124.                               column->column.length(),1,0,&unused_field_idx);
  2125.         if (!f)
  2126.         {
  2127.           my_error(ER_BAD_FIELD_ERROR, MYF(0),
  2128.                    column->column.c_ptr(), table_list->alias);
  2129.           DBUG_RETURN(-1);
  2130.         }
  2131.         if (f == (Field*)-1)
  2132.         {
  2133.           DBUG_RETURN(-1);
  2134.         }
  2135.         column_priv|= column->rights;
  2136.       }
  2137.       close_thread_tables(thd);
  2138.     }
  2139.     else
  2140.     {
  2141.       if (!(rights & CREATE_ACL))
  2142.       {
  2143.         char buf[FN_REFLEN];
  2144.         sprintf(buf,"%s/%s/%s.frm",mysql_data_home, table_list->db,
  2145.                 table_list->real_name);
  2146.         fn_format(buf,buf,"","",4+16+32);
  2147.         if (access(buf,F_OK))
  2148.         {
  2149.           my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
  2150.           DBUG_RETURN(-1);
  2151.         }
  2152.       }
  2153.       if (table_list->grant.want_privilege)
  2154.       {
  2155.         char command[128];
  2156.         get_privilege_desc(command, sizeof(command),
  2157.                            table_list->grant.want_privilege);
  2158.         my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
  2159.          command, thd->priv_user, thd->host_or_ip, table_list->alias);
  2160.         DBUG_RETURN(-1);
  2161.       }
  2162.     }
  2163.   }
  2164.   /* open the mysql.tables_priv and mysql.columns_priv tables */
  2165.   bzero((char*) &tables,sizeof(tables));
  2166.   tables[0].alias=tables[0].real_name= (char*) "user";
  2167.   tables[1].alias=tables[1].real_name= (char*) "tables_priv";
  2168.   tables[2].alias=tables[2].real_name= (char*) "columns_priv";
  2169.   tables[0].next=tables+1;
  2170.   /* Don't open column table if we don't need it ! */
  2171.   tables[1].next=((column_priv ||
  2172.    (revoke_grant && ((rights & COL_ACLS) || columns.elements)))
  2173.   ? tables+2 : 0);
  2174.   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
  2175.   tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
  2176. #ifdef HAVE_REPLICATION
  2177.   /*
  2178.     GRANT and REVOKE are applied the slave in/exclusion rules as they are
  2179.     some kind of updates to the mysql.% tables.
  2180.   */
  2181.   if (thd->slave_thread && table_rules_on)
  2182.   {
  2183.     /*
  2184.       The tables must be marked "updating" so that tables_ok() takes them into
  2185.       account in tests.
  2186.     */
  2187.     tables[0].updating= tables[1].updating= tables[2].updating= 1;
  2188.     if (!tables_ok(0, tables))
  2189.       DBUG_RETURN(0);
  2190.   }
  2191. #endif
  2192.   if (simple_open_n_lock_tables(thd,tables))
  2193.   { // Should never happen
  2194.     close_thread_tables(thd); /* purecov: deadcode */
  2195.     DBUG_RETURN(-1); /* purecov: deadcode */
  2196.   }
  2197.   if (!revoke_grant)
  2198.     create_new_users= test_if_create_new_users(thd);
  2199.   int result=0;
  2200.   rw_wrlock(&LOCK_grant);
  2201.   MEM_ROOT *old_root= thd->mem_root;
  2202.   thd->mem_root= &memex;
  2203.   while ((Str = str_list++))
  2204.   {
  2205.     int error;
  2206.     GRANT_TABLE *grant_table;
  2207.     if (Str->host.length > HOSTNAME_LENGTH ||
  2208. Str->user.length > USERNAME_LENGTH)
  2209.     {
  2210.       my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  2211.       result= -1;
  2212.       continue;
  2213.     }
  2214.     /* Create user if needed */
  2215.     pthread_mutex_lock(&acl_cache->lock);
  2216.     error=replace_user_table(thd, tables[0].table, *Str,
  2217.      0, revoke_grant, create_new_users);
  2218.     pthread_mutex_unlock(&acl_cache->lock);
  2219.     if (error)
  2220.     {
  2221.       result= -1; // Remember error
  2222.       continue; // Add next user
  2223.     }
  2224.     /* Find/create cached table grant */
  2225.     grant_table= table_hash_search(Str->host.str,NullS,table_list->db,
  2226.    Str->user.str,
  2227.    table_list->real_name,1);
  2228.     if (!grant_table)
  2229.     {
  2230.       if (revoke_grant)
  2231.       {
  2232. my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  2233.                  Str->user.str, Str->host.str, table_list->real_name);
  2234. result= -1;
  2235. continue;
  2236.       }
  2237.       grant_table = new GRANT_TABLE (Str->host.str,table_list->db,
  2238.      Str->user.str,
  2239.      table_list->real_name,
  2240.      rights,
  2241.      column_priv);
  2242.       if (!grant_table) // end of memory
  2243.       {
  2244. result= -1; /* purecov: deadcode */
  2245. continue; /* purecov: deadcode */
  2246.       }
  2247.       my_hash_insert(&column_priv_hash,(byte*) grant_table);
  2248.     }
  2249.     /* If revoke_grant, calculate the new column privilege for tables_priv */
  2250.     if (revoke_grant)
  2251.     {
  2252.       class LEX_COLUMN *column;
  2253.       List_iterator <LEX_COLUMN> column_iter(columns);
  2254.       GRANT_COLUMN *grant_column;
  2255.       /* Fix old grants */
  2256.       while ((column = column_iter++))
  2257.       {
  2258. grant_column = column_hash_search(grant_table,
  2259.   column->column.ptr(),
  2260.   column->column.length());
  2261. if (grant_column)
  2262.   grant_column->rights&= ~(column->rights | rights);
  2263.       }
  2264.       /* scan trough all columns to get new column grant */
  2265.       column_priv= 0;
  2266.       for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
  2267.       {
  2268. grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
  2269.    idx);
  2270. grant_column->rights&= ~rights; // Fix other columns
  2271. column_priv|= grant_column->rights;
  2272.       }
  2273.     }
  2274.     else
  2275.     {
  2276.       column_priv|= grant_table->cols;
  2277.     }
  2278.     /* update table and columns */
  2279.     if (replace_table_table(thd,grant_table,tables[1].table,*Str,
  2280.     table_list->db,
  2281.     table_list->real_name,
  2282.     rights, column_priv, revoke_grant))
  2283.     {
  2284.       /* Should only happen if table is crashed */
  2285.       result= -1;        /* purecov: deadcode */
  2286.     }
  2287.     else if (tables[2].table)
  2288.     {
  2289.       if ((replace_column_table(grant_table,tables[2].table, *Str,
  2290. columns,
  2291. table_list->db,
  2292. table_list->real_name,
  2293. rights, revoke_grant)))
  2294.       {
  2295. result= -1;
  2296.       }
  2297.     }
  2298.   }
  2299.   grant_option=TRUE;
  2300.   thd->mem_root= old_root;
  2301.   rw_unlock(&LOCK_grant);
  2302.   if (!result)
  2303.     send_ok(thd);
  2304.   /* Tables are automatically closed */
  2305.   DBUG_RETURN(result);
  2306. }
  2307. int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
  2308. ulong rights, bool revoke_grant)
  2309. {
  2310.   List_iterator <LEX_USER> str_list (list);
  2311.   LEX_USER *Str;
  2312.   char tmp_db[NAME_LEN+1];
  2313.   bool create_new_users=0;
  2314.   TABLE_LIST tables[2];
  2315.   DBUG_ENTER("mysql_grant");
  2316.   if (!initialized)
  2317.   {
  2318.     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
  2319.              "--skip-grant-tables"); /* purecov: tested */
  2320.     DBUG_RETURN(-1); /* purecov: tested */
  2321.   }
  2322.   if (lower_case_table_names && db)
  2323.   {
  2324.     strmov(tmp_db,db);
  2325.     my_casedn_str(files_charset_info, tmp_db);
  2326.     db=tmp_db;
  2327.   }
  2328.   /* open the mysql.user and mysql.db tables */
  2329.   bzero((char*) &tables,sizeof(tables));
  2330.   tables[0].alias=tables[0].real_name=(char*) "user";
  2331.   tables[1].alias=tables[1].real_name=(char*) "db";
  2332.   tables[0].next=tables+1;
  2333.   tables[1].next=0;
  2334.   tables[0].lock_type=tables[1].lock_type=TL_WRITE;
  2335.   tables[0].db=tables[1].db=(char*) "mysql";
  2336.   tables[0].table=tables[1].table=0;
  2337. #ifdef HAVE_REPLICATION
  2338.   /*
  2339.     GRANT and REVOKE are applied the slave in/exclusion rules as they are
  2340.     some kind of updates to the mysql.% tables.
  2341.   */
  2342.   if (thd->slave_thread && table_rules_on)
  2343.   {
  2344.     /*
  2345.       The tables must be marked "updating" so that tables_ok() takes them into
  2346.       account in tests.
  2347.     */
  2348.     tables[0].updating= tables[1].updating= 1;
  2349.     if (!tables_ok(0, tables))
  2350.       DBUG_RETURN(0);
  2351.   }
  2352. #endif
  2353.   if (simple_open_n_lock_tables(thd,tables))
  2354.   { // This should never happen
  2355.     close_thread_tables(thd); /* purecov: deadcode */
  2356.     DBUG_RETURN(-1); /* purecov: deadcode */
  2357.   }
  2358.   if (!revoke_grant)
  2359.     create_new_users= test_if_create_new_users(thd);
  2360.   /* go through users in user_list */
  2361.   rw_wrlock(&LOCK_grant);
  2362.   VOID(pthread_mutex_lock(&acl_cache->lock));
  2363.   grant_version++;
  2364.   int result=0;
  2365.   while ((Str = str_list++))
  2366.   {
  2367.     if (Str->host.length > HOSTNAME_LENGTH ||
  2368. Str->user.length > USERNAME_LENGTH)
  2369.     {
  2370.       my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  2371.       result= -1;
  2372.       continue;
  2373.     }
  2374.     if ((replace_user_table(thd,
  2375.     tables[0].table,
  2376.     *Str,
  2377.     (!db ? rights : 0), revoke_grant,
  2378.     create_new_users)))
  2379.       result= -1;
  2380.     else if (db)
  2381.     {
  2382.       ulong db_rights= rights & DB_ACLS;
  2383.       if (db_rights  == rights)
  2384.       {
  2385. if (replace_db_table(tables[1].table, db, *Str, db_rights,
  2386.      revoke_grant))
  2387.   result= -1;
  2388.       }
  2389.       else
  2390.       {
  2391. my_error(ER_WRONG_USAGE, MYF(0), "DB GRANT", "GLOBAL PRIVILEGES");
  2392. result= -1;
  2393.       }
  2394.     }
  2395.   }
  2396.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  2397.   rw_unlock(&LOCK_grant);
  2398.   close_thread_tables(thd);
  2399.   if (!result)
  2400.     send_ok(thd);
  2401.   DBUG_RETURN(result);
  2402. }
  2403. /* Free grant array if possible */
  2404. void  grant_free(void)
  2405. {
  2406.   DBUG_ENTER("grant_free");
  2407.   grant_option = FALSE;
  2408.   hash_free(&column_priv_hash);
  2409.   free_root(&memex,MYF(0));
  2410.   DBUG_VOID_RETURN;
  2411. }
  2412. /*
  2413.   Initialize structures responsible for table/column-level privilege checking
  2414.   and load information for them from tables in the 'mysql' database.
  2415.   SYNOPSIS
  2416.     grant_init()
  2417.   RETURN VALUES
  2418.     0 ok
  2419.     1 Could not initialize grant's
  2420. */
  2421. my_bool grant_init()
  2422. {
  2423.   THD  *thd;
  2424.   my_bool return_val;
  2425.   DBUG_ENTER("grant_init");
  2426.   if (!(thd= new THD))
  2427.     DBUG_RETURN(1); /* purecov: deadcode */
  2428.   thd->store_globals();
  2429.   return_val=  grant_reload(thd);
  2430.   delete thd;
  2431.   /* Remember that we don't have a THD */
  2432.   my_pthread_setspecific_ptr(THR_THD,  0);
  2433.   DBUG_RETURN(return_val);
  2434. }
  2435. /*
  2436.   Initialize structures responsible for table/column-level privilege
  2437.   checking and load information about grants from open privilege tables.
  2438.   SYNOPSIS
  2439.     grant_load()
  2440.       thd     Current thread
  2441.       tables  List containing open "mysql.tables_priv" and
  2442.               "mysql.columns_priv" tables.
  2443.   RETURN VALUES
  2444.     FALSE - success
  2445.     TRUE  - error
  2446. */
  2447. static my_bool grant_load(TABLE_LIST *tables)
  2448. {
  2449.   MEM_ROOT *memex_ptr;
  2450.   my_bool return_val= 1;
  2451.   TABLE *t_table, *c_table;
  2452.   bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
  2453.   MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
  2454.                                                            THR_MALLOC);
  2455.   DBUG_ENTER("grant_load");
  2456.   grant_option = FALSE;
  2457.   (void) hash_init(&column_priv_hash,system_charset_info,
  2458.    0,0,0, (hash_get_key) get_grant_table,
  2459.    (hash_free_key) free_grant_table,0);
  2460.   init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
  2461.   t_table = tables[0].table; c_table = tables[1].table;
  2462.   t_table->file->ha_index_init(0);
  2463.   if (t_table->file->index_first(t_table->record[0]))
  2464.   {
  2465.     return_val= 0;
  2466.     goto end_unlock;
  2467.   }
  2468.   grant_option= TRUE;
  2469.   memex_ptr= &memex;
  2470.   my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
  2471.   do
  2472.   {
  2473.     GRANT_TABLE *mem_check;
  2474.     if (!(mem_check=new GRANT_TABLE(t_table,c_table)))
  2475.     {
  2476.       /* This could only happen if we are out memory */
  2477.       grant_option= FALSE; /* purecov: deadcode */
  2478.       goto end_unlock;
  2479.     }
  2480.     if (check_no_resolve)
  2481.     {
  2482.       if (hostname_requires_resolving(mem_check->host.hostname))
  2483.       {
  2484.         sql_print_warning("'tables_priv' entry '%s %s@%s' "
  2485.                           "ignored in --skip-name-resolve mode.",
  2486.                           mem_check->tname, mem_check->user,
  2487.                           mem_check->host);
  2488. continue;
  2489.       }
  2490.     }
  2491.     if (mem_check->ok() && my_hash_insert(&column_priv_hash,(byte*) mem_check))
  2492.     {
  2493.       grant_option= FALSE;
  2494.       goto end_unlock;
  2495.     }
  2496.   }
  2497.   while (!t_table->file->index_next(t_table->record[0]));
  2498.   return_val=0; // Return ok
  2499. end_unlock:
  2500.   t_table->file->ha_index_end();
  2501.   my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
  2502.   DBUG_RETURN(return_val);
  2503. }
  2504. /*
  2505.   Reload information about table and column level privileges if possible.
  2506.   SYNOPSIS
  2507.     grant_reload()
  2508.       thd  Current thread
  2509.   NOTES
  2510.     Locked tables are checked by acl_reload() and doesn't have to be checked
  2511.     in this call.
  2512.     This function is also used for initialization of structures responsible
  2513.     for table/column-level privilege checking.
  2514.   RETURN VALUE
  2515.     FALSE Success
  2516.     TRUE  Error
  2517. */
  2518. my_bool grant_reload(THD *thd)
  2519. {
  2520.   TABLE_LIST tables[2];
  2521.   HASH old_column_priv_hash;
  2522.   bool old_grant_option;
  2523.   MEM_ROOT old_mem;
  2524.   my_bool return_val= 1;
  2525.   DBUG_ENTER("grant_reload");
  2526.   /* Don't do anything if running with --skip-grant-tables */
  2527.   if (!initialized)
  2528.     DBUG_RETURN(0);
  2529.   bzero((char*) tables, sizeof(tables));
  2530.   tables[0].alias=tables[0].real_name= (char*) "tables_priv";
  2531.   tables[1].alias=tables[1].real_name= (char*) "columns_priv";
  2532.   tables[0].db=tables[1].db= (char *) "mysql";
  2533.   tables[0].next=tables+1;
  2534.   tables[0].lock_type=tables[1].lock_type=TL_READ;
  2535.   /*
  2536.     To avoid deadlocks we should obtain table locks before
  2537.     obtaining LOCK_grant rwlock.
  2538.   */
  2539.   if (simple_open_n_lock_tables(thd, tables))
  2540.     goto end;
  2541.   rw_wrlock(&LOCK_grant);
  2542.   grant_version++;
  2543.   old_column_priv_hash= column_priv_hash;
  2544.   old_grant_option= grant_option;
  2545.   old_mem= memex;
  2546.   if ((return_val= grant_load(tables)))
  2547.   { // Error. Revert to old hash
  2548.     DBUG_PRINT("error",("Reverting to old privileges"));
  2549.     grant_free(); /* purecov: deadcode */
  2550.     column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
  2551.     grant_option= old_grant_option; /* purecov: deadcode */
  2552.     memex= old_mem; /* purecov: deadcode */
  2553.   }
  2554.   else
  2555.   {
  2556.     hash_free(&old_column_priv_hash);
  2557.     free_root(&old_mem,MYF(0));
  2558.   }
  2559.   rw_unlock(&LOCK_grant);
  2560. end:
  2561.   close_thread_tables(thd);
  2562.   DBUG_RETURN(return_val);
  2563. }
  2564. /****************************************************************************
  2565.   Check table level grants
  2566.   All errors are written directly to the client if no_errors is given !
  2567. ****************************************************************************/
  2568. bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
  2569.  uint show_table, uint number, bool no_errors)
  2570. {
  2571.   TABLE_LIST *table;
  2572.   char *user = thd->priv_user;
  2573.   DBUG_ENTER("check_grant");
  2574.   want_access &= ~thd->master_access;
  2575.   if (!want_access)
  2576.     DBUG_RETURN(0);                             // ok
  2577.   rw_rdlock(&LOCK_grant);
  2578.   for (table= tables; table && number--; table= table->next)
  2579.   {
  2580.     if (!(~table->grant.privilege & want_access) || table->derived)
  2581.     {
  2582.       table->grant.want_privilege=0;
  2583.       continue; // Already checked
  2584.     }
  2585.     GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
  2586.  table->db,user,
  2587.  table->real_name,0);
  2588.     if (!grant_table)
  2589.     {
  2590.       want_access &= ~table->grant.privilege;
  2591.       goto err; // No grants
  2592.     }
  2593.     if (show_table)
  2594.       continue; // We have some priv on this
  2595.     table->grant.grant_table=grant_table; // Remember for column test
  2596.     table->grant.version=grant_version;
  2597.     table->grant.privilege|= grant_table->privs;
  2598.     table->grant.want_privilege= ((want_access & COL_ACLS)
  2599.   & ~table->grant.privilege);
  2600.     if (!(~table->grant.privilege & want_access))
  2601.       continue;
  2602.     if (want_access & ~(grant_table->cols | table->grant.privilege))
  2603.     {
  2604.       want_access &= ~(grant_table->cols | table->grant.privilege);
  2605.       goto err; // impossible
  2606.     }
  2607.   }
  2608.   rw_unlock(&LOCK_grant);
  2609.   DBUG_RETURN(0);
  2610. err:
  2611.   rw_unlock(&LOCK_grant);
  2612.   if (!no_errors) // Not a silent skip of table
  2613.   {
  2614.     char command[128];
  2615.     get_privilege_desc(command, sizeof(command), want_access);
  2616.     net_printf(thd,ER_TABLEACCESS_DENIED_ERROR,
  2617.        command,
  2618.        thd->priv_user,
  2619.        thd->host_or_ip,
  2620.        table ? table->real_name : "unknown");
  2621.   }
  2622.   DBUG_RETURN(1);
  2623. }
  2624. bool check_grant_column(THD *thd,TABLE *table, const char *name,
  2625. uint length, uint show_tables)
  2626. {
  2627.   GRANT_TABLE *grant_table;
  2628.   GRANT_COLUMN *grant_column;
  2629.   ulong want_access=table->grant.want_privilege;
  2630.   if (!want_access)
  2631.     return 0; // Already checked
  2632.   rw_rdlock(&LOCK_grant);
  2633.   /* reload table if someone has modified any grants */
  2634.   if (table->grant.version != grant_version)
  2635.   {
  2636.     table->grant.grant_table=
  2637.       table_hash_search(thd->host, thd->ip, table->table_cache_key,
  2638. thd->priv_user,
  2639. table->real_name, 0); /* purecov: inspected */
  2640.     table->grant.version=grant_version; /* purecov: inspected */
  2641.   }
  2642.   if (!(grant_table=table->grant.grant_table))
  2643.     goto err; /* purecov: deadcode */
  2644.   grant_column=column_hash_search(grant_table, name, length);
  2645.   if (grant_column && !(~grant_column->rights & want_access))
  2646.   {
  2647.     rw_unlock(&LOCK_grant);
  2648.     return 0;
  2649.   }
  2650. #ifdef NOT_USED
  2651.   if (show_tables && (grant_column || table->grant.privilege & COL_ACLS))
  2652.   {
  2653.     rw_unlock(&LOCK_grant); /* purecov: deadcode */
  2654.     return 0; /* purecov: deadcode */
  2655.   }
  2656. #endif
  2657.   /* We must use my_printf_error() here! */
  2658. err:
  2659.   rw_unlock(&LOCK_grant);
  2660.   if (!show_tables)
  2661.   {
  2662.     char command[128];
  2663.     get_privilege_desc(command, sizeof(command), want_access);
  2664.     my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
  2665.     ER(ER_COLUMNACCESS_DENIED_ERROR),
  2666.     MYF(0),
  2667.     command,
  2668.     thd->priv_user,
  2669.     thd->host_or_ip,
  2670.     name,
  2671.     table ? table->real_name : "unknown");
  2672.   }
  2673.   return 1;
  2674. }
  2675. bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
  2676. {
  2677.   GRANT_TABLE *grant_table;
  2678.   GRANT_COLUMN *grant_column;
  2679.   Field *field=0,**ptr;
  2680.   want_access &= ~table->grant.privilege;
  2681.   if (!want_access)
  2682.     return 0; // Already checked
  2683.   if (!grant_option)
  2684.   {
  2685.     field= table->field[0]; // To give a meaningful error message
  2686.     goto err2;
  2687.   }
  2688.   rw_rdlock(&LOCK_grant);
  2689.   /* reload table if someone has modified any grants */
  2690.   if (table->grant.version != grant_version)
  2691.   {
  2692.     table->grant.grant_table=
  2693.       table_hash_search(thd->host, thd->ip, table->table_cache_key,
  2694. thd->priv_user,
  2695. table->real_name,0); /* purecov: inspected */
  2696.     table->grant.version=grant_version; /* purecov: inspected */
  2697.   }
  2698.   /* The following should always be true */
  2699.   if (!(grant_table=table->grant.grant_table))
  2700.     goto err; /* purecov: inspected */
  2701.   for (ptr=table->field; (field= *ptr) ; ptr++)
  2702.   {
  2703.     grant_column=column_hash_search(grant_table, field->field_name,
  2704.     (uint) strlen(field->field_name));
  2705.     if (!grant_column || (~grant_column->rights & want_access))
  2706.       goto err;
  2707.   }
  2708.   rw_unlock(&LOCK_grant);
  2709.   return 0;
  2710.   /* We must use my_printf_error() here! */
  2711. err:
  2712.   rw_unlock(&LOCK_grant);
  2713. err2:
  2714.   char command[128];
  2715.   get_privilege_desc(command, sizeof(command), want_access);
  2716.   my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
  2717.   ER(ER_COLUMNACCESS_DENIED_ERROR),
  2718.   MYF(0),
  2719.   command,
  2720.   thd->priv_user,
  2721.   thd->host_or_ip,
  2722.   field ? field->field_name : "unknown",
  2723.   table->real_name);
  2724.   return 1;
  2725. }
  2726. /*
  2727.   Check if a user has the right to access a database
  2728.   Access is accepted if he has a grant for any table in the database
  2729.   Return 1 if access is denied
  2730. */
  2731. bool check_grant_db(THD *thd,const char *db)
  2732. {
  2733.   char helping [NAME_LEN+USERNAME_LENGTH+2];
  2734.   uint len;
  2735.   bool error=1;
  2736.   len  = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
  2737.   rw_rdlock(&LOCK_grant);
  2738.   for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
  2739.   {
  2740.     GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
  2741.   idx);
  2742.     if (len < grant_table->key_length &&
  2743. !memcmp(grant_table->hash_key,helping,len) &&
  2744.         compare_hostname(&grant_table->host, thd->host, thd->ip))
  2745.     {
  2746.       error=0; // Found match
  2747.       break;
  2748.     }
  2749.   }
  2750.   rw_unlock(&LOCK_grant);
  2751.   return error;
  2752. }
  2753. /*****************************************************************************
  2754.   Functions to retrieve the grant for a table/column  (for SHOW functions)
  2755. *****************************************************************************/
  2756. ulong get_table_grant(THD *thd, TABLE_LIST *table)
  2757. {
  2758.   ulong privilege;
  2759.   char *user = thd->priv_user;
  2760.   const char *db = table->db ? table->db : thd->db;
  2761.   GRANT_TABLE *grant_table;
  2762.   rw_rdlock(&LOCK_grant);
  2763. #ifdef EMBEDDED_LIBRARY
  2764.   grant_table= NULL;
  2765. #else
  2766.   grant_table= table_hash_search(thd->host, thd->ip, db, user,
  2767.  table->real_name, 0);
  2768. #endif
  2769.   table->grant.grant_table=grant_table; // Remember for column test
  2770.   table->grant.version=grant_version;
  2771.   if (grant_table)
  2772.     table->grant.privilege|= grant_table->privs;
  2773.   privilege= table->grant.privilege;
  2774.   rw_unlock(&LOCK_grant);
  2775.   return privilege;
  2776. }
  2777. ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
  2778. {
  2779.   GRANT_TABLE *grant_table;
  2780.   GRANT_COLUMN *grant_column;
  2781.   ulong priv;
  2782.   rw_rdlock(&LOCK_grant);
  2783.   /* reload table if someone has modified any grants */
  2784.   if (table->grant.version != grant_version)
  2785.   {
  2786.     table->grant.grant_table=
  2787.       table_hash_search(thd->host, thd->ip, table->db,
  2788. thd->priv_user,
  2789. table->real_name,0); /* purecov: inspected */
  2790.     table->grant.version=grant_version; /* purecov: inspected */
  2791.   }
  2792.   if (!(grant_table=table->grant.grant_table))
  2793.     priv=table->grant.privilege;
  2794.   else
  2795.   {
  2796.     grant_column=column_hash_search(grant_table, field->field_name,
  2797.     (uint) strlen(field->field_name));
  2798.     if (!grant_column)
  2799.       priv=table->grant.privilege;
  2800.     else
  2801.       priv=table->grant.privilege | grant_column->rights;
  2802.   }
  2803.   rw_unlock(&LOCK_grant);
  2804.   return priv;
  2805. }
  2806. /* Help function for mysql_show_grants */
  2807. static void add_user_option(String *grant, ulong value, const char *name)
  2808. {
  2809.   if (value)
  2810.   {
  2811.     char buff[22], *p; // just as in int2str
  2812.     grant->append(' ');
  2813.     grant->append(name, strlen(name));
  2814.     grant->append(' ');
  2815.     p=int10_to_str(value, buff, 10);
  2816.     grant->append(buff,p-buff);
  2817.   }
  2818. }
  2819. static const char *command_array[]=
  2820. {
  2821.   "SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP", "RELOAD","SHUTDOWN",
  2822.   "PROCESS","FILE","GRANT","REFERENCES","INDEX", "ALTER", "SHOW DATABASES",
  2823.   "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE",
  2824.   "REPLICATION SLAVE", "REPLICATION CLIENT",
  2825. };
  2826. static uint command_lengths[]=
  2827. {
  2828.   6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18
  2829. };
  2830. /*
  2831.   SHOW GRANTS;  Send grants for a user to the client
  2832.   IMPLEMENTATION
  2833.    Send to client grant-like strings depicting user@host privileges
  2834. */
  2835. int mysql_show_grants(THD *thd,LEX_USER *lex_user)
  2836. {
  2837.   ulong want_access;
  2838.   uint counter,index;
  2839.   int  error = 0;
  2840.   ACL_USER *acl_user;
  2841.   ACL_DB *acl_db;
  2842.   char buff[1024];
  2843.   Protocol *protocol= thd->protocol;
  2844.   DBUG_ENTER("mysql_show_grants");
  2845.   LINT_INIT(acl_user);
  2846.   if (!initialized)
  2847.   {
  2848.     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  2849.     DBUG_RETURN(-1);
  2850.   }
  2851.   if (!lex_user->host.str)
  2852.   {
  2853.     lex_user->host.str= (char*) "%";
  2854.     lex_user->host.length=1;
  2855.   }
  2856.   if (lex_user->host.length > HOSTNAME_LENGTH ||
  2857.       lex_user->user.length > USERNAME_LENGTH)
  2858.   {
  2859.     my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  2860.     DBUG_RETURN(-1);
  2861.   }
  2862.   for (counter=0 ; counter < acl_users.elements ; counter++)
  2863.   {
  2864.     const char *user,*host;
  2865.     acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
  2866.     if (!(user=acl_user->user))
  2867.       user= "";
  2868.     if (!(host=acl_user->host.hostname))
  2869.       host= "";
  2870.     if (!strcmp(lex_user->user.str,user) &&
  2871. !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  2872.       break;
  2873.   }
  2874.   if (counter == acl_users.elements)
  2875.   {
  2876.     my_error(ER_NONEXISTING_GRANT, MYF(0),
  2877.              lex_user->user.str, lex_user->host.str);
  2878.     DBUG_RETURN(-1);
  2879.   }
  2880.   Item_string *field=new Item_string("",0,&my_charset_latin1);
  2881.   List<Item> field_list;
  2882.   field->name=buff;
  2883.   field->max_length=1024;
  2884.   strxmov(buff,"Grants for ",lex_user->user.str,"@",
  2885.   lex_user->host.str,NullS);
  2886.   field_list.push_back(field);
  2887.   if (protocol->send_fields(&field_list,1))
  2888.     DBUG_RETURN(-1);
  2889.   rw_wrlock(&LOCK_grant);
  2890.   VOID(pthread_mutex_lock(&acl_cache->lock));
  2891.   /* Add first global access grants */
  2892.   {
  2893.     String global(buff,sizeof(buff),system_charset_info);
  2894.     global.length(0);
  2895.     global.append("GRANT ",6);
  2896.     want_access= acl_user->access;
  2897.     if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
  2898.       global.append("ALL PRIVILEGES",14);
  2899.     else if (!(want_access & ~GRANT_ACL))
  2900.       global.append("USAGE",5);
  2901.     else
  2902.     {
  2903.       bool found=0;
  2904.       ulong j,test_access= want_access & ~GRANT_ACL;
  2905.       for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
  2906.       {
  2907. if (test_access & j)
  2908. {
  2909.   if (found)
  2910.     global.append(", ",2);
  2911.   found=1;
  2912.   global.append(command_array[counter],command_lengths[counter]);
  2913. }
  2914.       }
  2915.     }
  2916.     global.append (" ON *.* TO '",12);
  2917.     global.append(lex_user->user.str, lex_user->user.length,
  2918.   system_charset_info);
  2919.     global.append ("'@'",3);
  2920.     global.append(lex_user->host.str,lex_user->host.length);
  2921.     global.append (''');
  2922.     if (acl_user->salt_len)
  2923.     {
  2924.       char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
  2925.       if (acl_user->salt_len == SCRAMBLE_LENGTH)
  2926.         make_password_from_salt(passwd_buff, acl_user->salt);
  2927.       else
  2928.         make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
  2929.       global.append(" IDENTIFIED BY PASSWORD '",25);
  2930.       global.append(passwd_buff);
  2931.       global.append(''');
  2932.     }
  2933.     /* "show grants" SSL related stuff */
  2934.     if (acl_user->ssl_type == SSL_TYPE_ANY)
  2935.       global.append(" REQUIRE SSL",12);
  2936.     else if (acl_user->ssl_type == SSL_TYPE_X509)
  2937.       global.append(" REQUIRE X509",13);
  2938.     else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED)
  2939.     {
  2940.       int ssl_options = 0;
  2941.       global.append(" REQUIRE ",9);
  2942.       if (acl_user->x509_issuer)
  2943.       {
  2944. ssl_options++;
  2945. global.append("ISSUER '",8);
  2946. global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
  2947. global.append(''');
  2948.       }
  2949.       if (acl_user->x509_subject)
  2950.       {
  2951. if (ssl_options++)
  2952.   global.append(' ');
  2953. global.append("SUBJECT '",9);
  2954. global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
  2955. global.append(''');
  2956.       }
  2957.       if (acl_user->ssl_cipher)
  2958.       {
  2959. if (ssl_options++)
  2960.   global.append(' ');
  2961. global.append("CIPHER '",8);
  2962. global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
  2963. global.append(''');
  2964.       }
  2965.     }
  2966.     if ((want_access & GRANT_ACL) ||
  2967. (acl_user->user_resource.questions | acl_user->user_resource.updates |
  2968.  acl_user->user_resource.connections))
  2969.     {
  2970.       global.append(" WITH",5);
  2971.       if (want_access & GRANT_ACL)
  2972. global.append(" GRANT OPTION",13);
  2973.       add_user_option(&global, acl_user->user_resource.questions,
  2974.       "MAX_QUERIES_PER_HOUR");
  2975.       add_user_option(&global, acl_user->user_resource.updates,
  2976.       "MAX_UPDATES_PER_HOUR");
  2977.       add_user_option(&global, acl_user->user_resource.connections,
  2978.       "MAX_CONNECTIONS_PER_HOUR");
  2979.     }
  2980.     protocol->prepare_for_resend();
  2981.     protocol->store(global.ptr(),global.length(),global.charset());
  2982.     if (protocol->write())
  2983.     {
  2984.       error= -1;
  2985.       goto end;
  2986.     }
  2987.   }
  2988.   /* Add database access */
  2989.   for (counter=0 ; counter < acl_dbs.elements ; counter++)
  2990.   {
  2991.     const char *user, *host;
  2992.     acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  2993.     if (!(user=acl_db->user))
  2994.       user= "";
  2995.     if (!(host=acl_db->host.hostname))
  2996.       host= "";
  2997.     if (!strcmp(lex_user->user.str,user) &&
  2998. !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  2999.     {
  3000.       want_access=acl_db->access;
  3001.       if (want_access)
  3002.       {
  3003. String db(buff,sizeof(buff),system_charset_info);
  3004. db.length(0);
  3005. db.append("GRANT ",6);
  3006. if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
  3007.   db.append("ALL PRIVILEGES",14);
  3008. else if (!(want_access & ~GRANT_ACL))
  3009.   db.append("USAGE",5);
  3010. else
  3011. {
  3012.   int found=0, cnt;
  3013.   ulong j,test_access= want_access & ~GRANT_ACL;
  3014.   for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
  3015.   {
  3016.     if (test_access & j)
  3017.     {
  3018.       if (found)
  3019. db.append(", ",2);
  3020.       found = 1;
  3021.       db.append(command_array[cnt],command_lengths[cnt]);
  3022.     }
  3023.   }
  3024. }
  3025. db.append (" ON ",4);
  3026. append_identifier(thd, &db, acl_db->db, strlen(acl_db->db));
  3027. db.append (".* TO '",7);
  3028. db.append(lex_user->user.str, lex_user->user.length,
  3029.   system_charset_info);
  3030. db.append ("'@'",3);
  3031. db.append(lex_user->host.str, lex_user->host.length);
  3032. db.append (''');
  3033. if (want_access & GRANT_ACL)
  3034.   db.append(" WITH GRANT OPTION",18);
  3035. protocol->prepare_for_resend();
  3036. protocol->store(db.ptr(),db.length(),db.charset());
  3037. if (protocol->write())
  3038. {
  3039.   error= -1;
  3040.   goto end;
  3041. }
  3042.       }
  3043.     }
  3044.   }
  3045.   /* Add table & column access */
  3046.   for (index=0 ; index < column_priv_hash.records ; index++)
  3047.   {
  3048.     const char *user;
  3049.     GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
  3050.   index);
  3051.     if (!(user=grant_table->user))
  3052.       user= "";
  3053.     if (!strcmp(lex_user->user.str,user) &&
  3054. !my_strcasecmp(system_charset_info, lex_user->host.str,
  3055.                        grant_table->host.hostname))
  3056.     {
  3057.       ulong table_access= grant_table->privs;
  3058.       if ((table_access | grant_table->cols) != 0)
  3059.       {
  3060. String global(buff, sizeof(buff), system_charset_info);
  3061. ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
  3062. global.length(0);
  3063. global.append("GRANT ",6);
  3064. if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
  3065.   global.append("ALL PRIVILEGES",14);
  3066. else if (!test_access)
  3067.     global.append("USAGE",5);
  3068. else
  3069. {
  3070.           /* Add specific column access */
  3071.   int found= 0;
  3072.   ulong j;
  3073.   for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
  3074.   {
  3075.     if (test_access & j)
  3076.     {
  3077.       if (found)
  3078. global.append(", ",2);
  3079.       found= 1;
  3080.       global.append(command_array[counter],command_lengths[counter]);
  3081.       if (grant_table->cols)
  3082.       {
  3083. uint found_col= 0;
  3084. for (uint col_index=0 ;
  3085.      col_index < grant_table->hash_columns.records ;
  3086.      col_index++)
  3087. {
  3088.   GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
  3089.     hash_element(&grant_table->hash_columns,col_index);
  3090.   if (grant_column->rights & j)
  3091.   {
  3092.     if (!found_col)
  3093.     {
  3094.       found_col= 1;
  3095.       /*
  3096. If we have a duplicated table level privilege, we
  3097. must write the access privilege name again.
  3098.       */
  3099.       if (table_access & j)
  3100.       {
  3101. global.append(", ", 2);
  3102. global.append(command_array[counter],
  3103.       command_lengths[counter]);
  3104.       }
  3105.       global.append(" (",2);
  3106.     }
  3107.     else
  3108.       global.append(", ",2);
  3109.     global.append(grant_column->column,
  3110.   grant_column->key_length,
  3111.   system_charset_info);
  3112.   }
  3113. }
  3114. if (found_col)
  3115.   global.append(')');
  3116.       }
  3117.     }
  3118.   }
  3119. }
  3120. global.append(" ON ",4);
  3121. append_identifier(thd, &global, grant_table->db,
  3122.   strlen(grant_table->db));
  3123. global.append('.');
  3124. append_identifier(thd, &global, grant_table->tname,
  3125.   strlen(grant_table->tname));
  3126. global.append(" TO '",5);
  3127. global.append(lex_user->user.str, lex_user->user.length,
  3128.       system_charset_info);
  3129. global.append("'@'",3);
  3130. global.append(lex_user->host.str,lex_user->host.length);
  3131. global.append(''');
  3132. if (table_access & GRANT_ACL)
  3133.   global.append(" WITH GRANT OPTION",18);
  3134. protocol->prepare_for_resend();
  3135. protocol->store(global.ptr(),global.length(),global.charset());
  3136. if (protocol->write())
  3137. {
  3138.   error= -1;
  3139.   break;
  3140. }
  3141.       }
  3142.     }
  3143.   }
  3144. end:
  3145.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  3146.   rw_unlock(&LOCK_grant);
  3147.   send_eof(thd);
  3148.   DBUG_RETURN(error);
  3149. }
  3150. /*
  3151.   Make a clear-text version of the requested privilege.
  3152. */
  3153. void get_privilege_desc(char *to, uint max_length, ulong access)
  3154. {
  3155.   uint pos;
  3156.   char *start=to;
  3157.   DBUG_ASSERT(max_length >= 30); // For end ',' removal
  3158.   if (access)
  3159.   {
  3160.     max_length--; // Reserve place for end-zero
  3161.     for (pos=0 ; access ; pos++, access>>=1)
  3162.     {
  3163.       if ((access & 1) &&
  3164.   command_lengths[pos] + (uint) (to-start) < max_length)
  3165.       {
  3166. to= strmov(to, command_array[pos]);
  3167. *to++=',';
  3168.       }
  3169.     }
  3170.     to--; // Remove end ','
  3171.   }
  3172.   *to=0;
  3173. }
  3174. void get_mqh(const char *user, const char *host, USER_CONN *uc)
  3175. {
  3176.   ACL_USER *acl_user;
  3177.   if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
  3178.     uc->user_resources= acl_user->user_resource;
  3179.   else
  3180.     bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
  3181. }
  3182. int open_grant_tables(THD *thd, TABLE_LIST *tables)
  3183. {
  3184.   DBUG_ENTER("open_grant_tables");
  3185.   if (!initialized)
  3186.   {
  3187.     net_printf(thd,ER_OPTION_PREVENTS_STATEMENT, "--skip-grant-tables");
  3188.     DBUG_RETURN(-1);
  3189.   }
  3190.   bzero((char*) tables, 4*sizeof(*tables));
  3191.   tables->alias= tables->real_name= (char*) "user";
  3192.   (tables+1)->alias= (tables+1)->real_name= (char*) "db";
  3193.   (tables+2)->alias= (tables+2)->real_name= (char*) "tables_priv";
  3194.   (tables+3)->alias= (tables+3)->real_name= (char*) "columns_priv";
  3195.   tables->next= tables+1;
  3196.   (tables+1)->next= tables+2;
  3197.   (tables+2)->next= tables+3;
  3198.   (tables+3)->next= 0;
  3199.   tables->lock_type= (tables+1)->lock_type=
  3200.     (tables+2)->lock_type= (tables+3)->lock_type= TL_WRITE;
  3201.   tables->db= (tables+1)->db= (tables+2)->db= (tables+3)->db=(char*) "mysql";
  3202. #ifdef HAVE_REPLICATION
  3203.   /*
  3204.     GRANT and REVOKE are applied the slave in/exclusion rules as they are
  3205.     some kind of updates to the mysql.% tables.
  3206.   */
  3207.   if (thd->slave_thread && table_rules_on)
  3208.   {
  3209.     /*
  3210.       The tables must be marked "updating" so that tables_ok() takes them into
  3211.       account in tests.
  3212.     */
  3213.     tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=1;
  3214.     if (!tables_ok(0, tables))
  3215.       DBUG_RETURN(1);
  3216.     tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=0;
  3217.   }
  3218. #endif
  3219.   if (simple_open_n_lock_tables(thd, tables))
  3220.   { // This should never happen
  3221.     close_thread_tables(thd);
  3222.     DBUG_RETURN(-1);
  3223.   }
  3224.   DBUG_RETURN(0);
  3225. }
  3226. ACL_USER *check_acl_user(LEX_USER *user_name,
  3227.  uint *acl_acl_userdx)
  3228. {
  3229.   ACL_USER *acl_user= 0;
  3230.   uint counter;
  3231.   for (counter= 0 ; counter < acl_users.elements ; counter++)
  3232.   {
  3233.     const char *user,*host;
  3234.     acl_user= dynamic_element(&acl_users, counter, ACL_USER*);
  3235.     if (!(user=acl_user->user))
  3236.       user= "";
  3237.     if (!(host=acl_user->host.hostname))
  3238.       host= "%";
  3239.     if (!strcmp(user_name->user.str,user) &&
  3240. !my_strcasecmp(system_charset_info, user_name->host.str, host))
  3241.       break;
  3242.   }
  3243.   if (counter == acl_users.elements)
  3244.     return 0;
  3245.   *acl_acl_userdx= counter;
  3246.   return acl_user;
  3247. }
  3248. int mysql_drop_user(THD *thd, List <LEX_USER> &list)
  3249. {
  3250.   uint counter, acl_userd;
  3251.   int result;
  3252.   ACL_USER *acl_user;
  3253.   ACL_DB *acl_db;
  3254.   TABLE_LIST tables[4];
  3255.   DBUG_ENTER("mysql_drop_user");
  3256.   if ((result= open_grant_tables(thd, tables)))
  3257.     DBUG_RETURN(result == 1 ? 0 : 1);
  3258.   rw_wrlock(&LOCK_grant);
  3259.   VOID(pthread_mutex_lock(&acl_cache->lock));
  3260.   LEX_USER *user_name;
  3261.   List_iterator <LEX_USER> user_list(list);
  3262.   while ((user_name=user_list++))
  3263.   {
  3264.     if (!(acl_user= check_acl_user(user_name, &counter)))
  3265.     {
  3266.       sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; No such user",
  3267.       user_name->user.str,
  3268.       user_name->host.str);
  3269.       result= -1;
  3270.       continue;
  3271.     }
  3272.     if ((acl_user->access & ~0))
  3273.     {
  3274.       sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Global privileges exists",
  3275.       user_name->user.str,
  3276.       user_name->host.str);
  3277.       result= -1;
  3278.       continue;
  3279.     }
  3280.     acl_userd= counter;
  3281.     for (counter= 0 ; counter < acl_dbs.elements ; counter++)
  3282.     {
  3283.       const char *user,*host;
  3284.       acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  3285.       if (!(user= acl_db->user))
  3286. user= "";
  3287.       if (!(host= acl_db->host.hostname))
  3288. host= "";
  3289.       if (!strcmp(user_name->user.str,user) &&
  3290.   !my_strcasecmp(system_charset_info, user_name->host.str, host))
  3291. break;
  3292.     }
  3293.     if (counter != acl_dbs.elements)
  3294.     {
  3295.       sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Database privileges exists",
  3296.       user_name->user.str,
  3297.       user_name->host.str);
  3298.       result= -1;
  3299.       continue;
  3300.     }
  3301.     for (counter= 0 ; counter < column_priv_hash.records ; counter++)
  3302.     {
  3303.       const char *user,*host;
  3304.       GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
  3305.     counter);
  3306.       if (!(user=grant_table->user))
  3307. user= "";
  3308.       if (!(host=grant_table->host.hostname))
  3309. host= "";
  3310.       if (!strcmp(user_name->user.str,user) &&
  3311.   !my_strcasecmp(system_charset_info, user_name->host.str, host))
  3312. break;
  3313.     }
  3314.     if (counter != column_priv_hash.records)
  3315.     {
  3316.       sql_print_error("DROP USER: Can't drop user: '%s'@'%s';  Table privileges exists",
  3317.       user_name->user.str,
  3318.       user_name->host.str);
  3319.       result= -1;
  3320.       continue;
  3321.     }
  3322.     tables[0].table->field[0]->store(user_name->host.str,(uint)
  3323.      user_name->host.length,
  3324.      system_charset_info);
  3325.     tables[0].table->field[1]->store(user_name->user.str,(uint)
  3326.      user_name->user.length,
  3327.      system_charset_info);
  3328.     tables[0].table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  3329.     if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0,
  3330.        (byte*) tables[0].table->
  3331.        field[0]->ptr,
  3332.        tables[0].table->
  3333.        key_info[0].key_length,
  3334.        HA_READ_KEY_EXACT))
  3335.     {
  3336.       int error;
  3337.       if ((error = tables[0].table->file->delete_row(tables[0].table->
  3338.      record[0])))
  3339.       {
  3340. tables[0].table->file->print_error(error, MYF(0));
  3341. DBUG_RETURN(-1);
  3342.       }
  3343.       delete_dynamic_element(&acl_users, acl_userd);
  3344.     }
  3345.   }
  3346.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  3347.   rw_unlock(&LOCK_grant);
  3348.   close_thread_tables(thd);
  3349.   if (result)
  3350.     my_error(ER_DROP_USER, MYF(0));
  3351.   DBUG_RETURN(result);
  3352. }
  3353. int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
  3354. {
  3355.   uint counter, revoked;
  3356.   int result;
  3357.   ACL_DB *acl_db;
  3358.   TABLE_LIST tables[4];
  3359.   DBUG_ENTER("mysql_revoke_all");
  3360.   if ((result= open_grant_tables(thd, tables)))
  3361.     DBUG_RETURN(result == 1 ? 0 : 1);
  3362.   rw_wrlock(&LOCK_grant);
  3363.   VOID(pthread_mutex_lock(&acl_cache->lock));
  3364.   LEX_USER *lex_user;
  3365.   List_iterator <LEX_USER> user_list(list);
  3366.   while ((lex_user=user_list++))
  3367.   {
  3368.     if (!check_acl_user(lex_user, &counter))
  3369.     {
  3370.       sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' not exists",
  3371.       lex_user->user.str,
  3372.       lex_user->host.str);
  3373.       result= -1;
  3374.       continue;
  3375.     }
  3376.     if (replace_user_table(thd, tables[0].table,
  3377.    *lex_user, ~(ulong)0, 1, 0))
  3378.     {
  3379.       result= -1;
  3380.       continue;
  3381.     }
  3382.     /* Remove db access privileges */
  3383.     /*
  3384.       Because acl_dbs and column_priv_hash shrink and may re-order
  3385.       as privileges are removed, removal occurs in a repeated loop
  3386.       until no more privileges are revoked.
  3387.      */
  3388.     do
  3389.     {
  3390.       for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
  3391.       {
  3392. const char *user,*host;
  3393. acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  3394. if (!(user=acl_db->user))
  3395.   user= "";
  3396. if (!(host=acl_db->host.hostname))
  3397.   host= "";
  3398. if (!strcmp(lex_user->user.str,user) &&
  3399.     !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  3400. {
  3401.   if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
  3402.   {
  3403.     /*
  3404.       Don't increment counter as replace_db_table deleted the
  3405.       current element in acl_dbs.
  3406.      */
  3407.     revoked= 1;
  3408.     continue;
  3409.   }
  3410.   result= -1; // Something went wrong
  3411. }
  3412. counter++;
  3413.       }
  3414.     } while (revoked);
  3415.     /* Remove column access */
  3416.     do
  3417.     {
  3418.       for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; )
  3419.       {
  3420. const char *user,*host;
  3421. GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash,
  3422.      counter);
  3423. if (!(user=grant_table->user))
  3424.   user= "";
  3425. if (!(host=grant_table->host.hostname))
  3426.   host= "";
  3427. if (!strcmp(lex_user->user.str,user) &&
  3428.     !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  3429. {
  3430.   if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
  3431.   grant_table->db,
  3432.   grant_table->tname,
  3433.   ~(ulong)0, 0, 1))
  3434.   {
  3435.     result= -1;
  3436.   }
  3437.   else
  3438.   {
  3439.     if (!grant_table->cols)
  3440.     {
  3441.       revoked= 1;
  3442.       continue;
  3443.     }
  3444.     List<LEX_COLUMN> columns;
  3445.     if (!replace_column_table(grant_table,tables[3].table, *lex_user,
  3446.       columns,
  3447.       grant_table->db,
  3448.       grant_table->tname,
  3449.       ~(ulong)0, 1))
  3450.     {
  3451.       revoked= 1;
  3452.       continue;
  3453.     }
  3454.     result= -1;
  3455.   }
  3456. }
  3457. counter++;
  3458.       }
  3459.     } while (revoked);
  3460.   }
  3461.   
  3462.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  3463.   rw_unlock(&LOCK_grant);
  3464.   close_thread_tables(thd);
  3465.   
  3466.   if (result)
  3467.     my_error(ER_REVOKE_GRANTS, MYF(0));
  3468.   
  3469.   DBUG_RETURN(result);
  3470. }
  3471. /*****************************************************************************
  3472.   Instantiate used templates
  3473. *****************************************************************************/
  3474. #ifdef __GNUC__
  3475. template class List_iterator<LEX_COLUMN>;
  3476. template class List_iterator<LEX_USER>;
  3477. template class List<LEX_COLUMN>;
  3478. template class List<LEX_USER>;
  3479. #endif
  3480. #endif /*NO_EMBEDDED_ACCESS_CHECKS */
  3481. int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
  3482. {
  3483.   reg3 int flag;
  3484.   DBUG_ENTER("wild_case_compare");
  3485.   DBUG_PRINT("enter",("str: '%s'  wildstr: '%s'",str,wildstr));
  3486.   while (*wildstr)
  3487.   {
  3488.     while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
  3489.     {
  3490.       if (*wildstr == wild_prefix && wildstr[1])
  3491. wildstr++;
  3492.       if (my_toupper(cs, *wildstr++) !=
  3493.           my_toupper(cs, *str++)) DBUG_RETURN(1);
  3494.     }
  3495.     if (! *wildstr ) DBUG_RETURN (*str != 0);
  3496.     if (*wildstr++ == wild_one)
  3497.     {
  3498.       if (! *str++) DBUG_RETURN (1); /* One char; skip */
  3499.     }
  3500.     else
  3501.     { /* Found '*' */
  3502.       if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
  3503.       flag=(*wildstr != wild_many && *wildstr != wild_one);
  3504.       do
  3505.       {
  3506. if (flag)
  3507. {
  3508.   char cmp;
  3509.   if ((cmp= *wildstr) == wild_prefix && wildstr[1])
  3510.     cmp=wildstr[1];
  3511.   cmp=my_toupper(cs, cmp);
  3512.   while (*str && my_toupper(cs, *str) != cmp)
  3513.     str++;
  3514.   if (!*str) DBUG_RETURN (1);
  3515. }
  3516. if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
  3517.       } while (*str++);
  3518.       DBUG_RETURN(1);
  3519.     }
  3520.   }
  3521.   DBUG_RETURN (*str != '');
  3522. }