home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / sql_acl.cpp < prev    next >
C/C++ Source or Header  |  2000-10-06  |  73KB  |  2,549 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /*
  19.   The privileges are saved in the following tables:
  20.   mysql/user     ; super user who are allowed to do almoust anything
  21.   mysql/host     ; host priviliges. This is used if host is empty in mysql/db.
  22.   mysql/db     ; database privileges / user
  23.  
  24.   data in tables is sorted according to how many not-wild-cards there is
  25.   in the relevant fields. Empty strings comes last.
  26. */
  27.  
  28. #include "mysql_priv.h"
  29. #include "sql_acl.h"
  30. #include "hash_filo.h"
  31. #include <m_ctype.h>
  32. #include <stdarg.h>
  33.  
  34. /*
  35.  ACL_HOST is used if no host is specified
  36.  */
  37.  
  38. struct acl_host_and_ip
  39. {
  40.   char *hostname;
  41.   long ip,ip_mask;            // Used with masked ip:s
  42. };
  43.  
  44. class ACL_ACCESS {
  45. public:
  46.   ulong sort;
  47.   uint access;
  48. };
  49.  
  50. class ACL_HOST :public ACL_ACCESS
  51. {
  52. public:
  53.   acl_host_and_ip host;
  54.   char *db;
  55. };
  56.  
  57. class ACL_USER :public ACL_ACCESS
  58. {
  59. public:
  60.   acl_host_and_ip host;
  61.   uint hostname_length;
  62.   char *user,*password;
  63.   ulong salt[2];
  64. };
  65.  
  66. class ACL_DB :public ACL_ACCESS
  67. {
  68. public:
  69.   acl_host_and_ip host;
  70.   char *user,*db;
  71. };
  72.  
  73. class acl_entry :public hash_filo_element
  74. {
  75. public:
  76.   uint access;
  77.   uint16 length;
  78.   char key[1];                    // Key will be stored here
  79. };
  80.  
  81. static byte* acl_entry_get_key(acl_entry *entry,uint *length,
  82.                    my_bool not_used __attribute__((unused)))
  83. {
  84.   *length=(uint) entry->length;
  85.   return (byte*) entry->key;
  86. }
  87.  
  88. #define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17)
  89.  
  90. static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
  91. static MEM_ROOT mem, memex;
  92. static bool initialized=0;
  93. static bool allow_all_hosts=1;
  94. static HASH acl_check_hosts, hash_tables;
  95. static DYNAMIC_ARRAY acl_wild_hosts;
  96. static hash_filo *acl_cache;
  97. static uint grant_version=0;
  98. static uint get_access(TABLE *form,uint fieldnr);
  99. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
  100. static ulong get_sort(uint count,...);
  101. static void init_check_host(void);
  102. static ACL_USER *find_acl_user(const char *host, const char *user);
  103. static bool update_user_table(THD *thd, const char *host, const char *user,
  104.                   const char *new_password);
  105. static void update_hostname(acl_host_and_ip *host, const char *hostname);
  106. static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
  107.                  const char *ip);
  108.  
  109. int  acl_init(bool dont_read_acl_tables)
  110. {
  111.   THD  *thd;
  112.   TABLE_LIST tables[3];
  113.   TABLE *table;
  114.   READ_RECORD read_record_info;
  115.   DBUG_ENTER("acl_init");
  116.  
  117.   if (!acl_cache)
  118.     acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
  119.                 (hash_get_key) acl_entry_get_key,
  120.                 (void (*)(void*)) free);
  121.   if (dont_read_acl_tables)
  122.     DBUG_RETURN(0); /* purecov: tested */
  123.  
  124.   if (!(thd=new THD))
  125.     DBUG_RETURN(1); /* purecov: inspected */
  126.   acl_cache->clear(1);                // Clear locked hostname cache
  127.   thd->version=refresh_version;
  128.   thd->mysys_var=my_thread_var;
  129.   thd->current_tablenr=0;
  130.   thd->open_tables=0;
  131.   thd->db=my_strdup("mysql",MYF(0));
  132.   bzero((char*) &tables,sizeof(tables));
  133.   tables[0].name=tables[0].real_name=(char*) "host";
  134.   tables[1].name=tables[1].real_name=(char*) "user";
  135.   tables[2].name=tables[2].real_name=(char*) "db";
  136.   tables[0].next=tables+1;
  137.   tables[1].next=tables+2;
  138.   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
  139.   tables[0].db=tables[1].db=tables[2].db=thd->db;
  140.  
  141.   if (open_tables(thd,tables))
  142.   {
  143.     close_thread_tables(thd); /* purecov: inspected */
  144.     delete thd; /* purecov: inspected */
  145.     DBUG_RETURN(1); /* purecov: inspected */
  146.   }
  147.   TABLE *ptr[3];                // Lock tables for quick update
  148.   ptr[0]= tables[0].table;
  149.   ptr[1]= tables[1].table;
  150.   ptr[2]= tables[2].table;
  151.   MYSQL_LOCK *lock=mysql_lock_tables(thd,ptr,3);
  152.   if (!lock)
  153.   {
  154.     close_thread_tables(thd); /* purecov: inspected */
  155.     delete thd; /* purecov: inspected */
  156.     DBUG_RETURN(1); /* purecov: inspected */
  157.   }
  158.  
  159.   init_sql_alloc(&mem,1024,0);
  160.   init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
  161.   VOID(init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
  162.   while (!(read_record_info.read_record(&read_record_info)))
  163.   {
  164.     ACL_HOST host;
  165.     update_hostname(&host.host,get_field(&mem, table,0));
  166.     host.db=get_field(&mem, table,1);
  167.     host.access=get_access(table,2);
  168.     host.access=fix_rights_for_db(host.access);
  169.     host.sort=get_sort(2,host.host.hostname,host.db);
  170. #ifndef TO_BE_REMOVED
  171.     if (table->fields ==  8)
  172.     {                        // Without grant
  173.       if (host.access & CREATE_ACL)
  174.     host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  175.     }
  176. #endif
  177.     VOID(push_dynamic(&acl_hosts,(gptr) &host));
  178.   }
  179.   qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
  180.     sizeof(ACL_HOST),(qsort_cmp) acl_compare);
  181.   end_read_record(&read_record_info);
  182.   freeze_size(&acl_hosts);
  183.  
  184.   init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
  185.   VOID(init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
  186.   if (table->field[2]->field_length == 8 &&
  187.       protocol_version == PROTOCOL_VERSION)
  188.   {
  189.     sql_print_error(
  190.         "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
  191.     protocol_version=9; /* purecov: tested */
  192.   }
  193.  
  194.   allow_all_hosts=0;
  195.   while (!(read_record_info.read_record(&read_record_info)))
  196.   {
  197.     ACL_USER user;
  198.     uint length=0;
  199.     update_hostname(&user.host,get_field(&mem, table,0));
  200.     user.user=get_field(&mem, table,1);
  201.     user.password=get_field(&mem, table,2);
  202.     if (user.password && (length=(uint) strlen(user.password)) == 8 &&
  203.     protocol_version == PROTOCOL_VERSION)
  204.     {
  205.       sql_print_error(
  206.               "Found old style password for user '%s'. Ignoring user. (You may want to restart using --old-protocol)",
  207.               user.user ? user.user : ""); /* purecov: tested */
  208.     }
  209.     else if (length % 8)        // This holds true for passwords
  210.     {
  211.       sql_print_error(
  212.               "Found invalid password for user: '%s@%s'; Ignoring user",
  213.               user.user ? user.user : "",
  214.               user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
  215.       continue; /* purecov: tested */
  216.     }
  217.     get_salt_from_password(user.salt,user.password);
  218.     user.access=get_access(table,3);
  219.     user.sort=get_sort(2,user.host.hostname,user.user);
  220.     user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0;
  221. #ifndef TO_BE_REMOVED
  222.     if (table->fields <= 13)
  223.     {                        // Without grant
  224.       if (user.access & CREATE_ACL)
  225.     user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  226.     }
  227. #endif
  228.     VOID(push_dynamic(&acl_users,(gptr) &user));
  229.     if (!user.host.hostname || user.host.hostname[0] == wild_many &&
  230.     !user.host.hostname[1])
  231.       allow_all_hosts=1;            // Anyone can connect
  232.   }
  233.   qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  234.     sizeof(ACL_USER),(qsort_cmp) acl_compare);
  235.   end_read_record(&read_record_info);
  236.   freeze_size(&acl_users);
  237.  
  238.   init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
  239.   VOID(init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
  240.   while (!(read_record_info.read_record(&read_record_info)))
  241.   {
  242.     ACL_DB db;
  243.     update_hostname(&db.host,get_field(&mem, table,0));
  244.     db.db=get_field(&mem, table,1);
  245.     db.user=get_field(&mem, table,2);
  246.     db.access=get_access(table,3);
  247.     db.access=fix_rights_for_db(db.access);
  248.     db.sort=get_sort(3,db.host.hostname,db.db,db.user);
  249. #ifndef TO_BE_REMOVED
  250.     if (table->fields <=  9)
  251.     {                        // Without grant
  252.       if (db.access & CREATE_ACL)
  253.     db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  254.     }
  255. #endif
  256.     VOID(push_dynamic(&acl_dbs,(gptr) &db));
  257.   }
  258.   qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  259.     sizeof(ACL_DB),(qsort_cmp) acl_compare);
  260.   end_read_record(&read_record_info);
  261.   freeze_size(&acl_dbs);
  262.   init_check_host();
  263.  
  264.   mysql_unlock_tables(thd, lock);
  265.   thd->version--;                // Force close to free memory
  266.   close_thread_tables(thd);
  267.   delete thd;
  268.   initialized=1;
  269.   DBUG_RETURN(0);
  270. }
  271.  
  272.  
  273. void acl_free(bool end)
  274. {
  275.   free_root(&mem,MYF(0));
  276.   delete_dynamic(&acl_hosts);
  277.   delete_dynamic(&acl_users);
  278.   delete_dynamic(&acl_dbs);
  279.   delete_dynamic(&acl_wild_hosts);
  280.   hash_free(&acl_check_hosts);
  281.   if (!end)
  282.     acl_cache->clear(1); /* purecov: inspected */
  283.   else
  284.   {
  285.     delete acl_cache;
  286.     acl_cache=0;
  287.   }
  288. }
  289.  
  290.     /* Reload acl list if possible */
  291.  
  292. void acl_reload(void)
  293. {
  294.   DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
  295.   MEM_ROOT old_mem;
  296.   bool old_initialized;
  297.   DBUG_ENTER("acl_reload");
  298.  
  299.   if (current_thd && current_thd->locked_tables)
  300.   {                    // Can't have locked tables here
  301.     current_thd->lock=current_thd->locked_tables;
  302.     current_thd->locked_tables=0;
  303.     close_thread_tables(current_thd);
  304.   }
  305.   if ((old_initialized=initialized))
  306.     VOID(pthread_mutex_lock(&acl_cache->lock));
  307.  
  308.   old_acl_hosts=acl_hosts;
  309.   old_acl_users=acl_users;
  310.   old_acl_dbs=acl_dbs;
  311.   old_mem=mem;
  312.   delete_dynamic(&acl_wild_hosts);
  313.   hash_free(&acl_check_hosts);
  314.  
  315.   if (acl_init(0))
  316.   {                    // Error. Revert to old list
  317.     acl_free();                    /* purecov: inspected */
  318.     acl_hosts=old_acl_hosts;
  319.     acl_users=old_acl_users;
  320.     acl_dbs=old_acl_dbs;
  321.     mem=old_mem;
  322.     init_check_host();
  323.   }
  324.   else
  325.   {
  326.     free_root(&old_mem,MYF(0));
  327.     delete_dynamic(&old_acl_hosts);
  328.     delete_dynamic(&old_acl_users);
  329.     delete_dynamic(&old_acl_dbs);
  330.   }
  331.   if (old_initialized)
  332.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  333.   DBUG_VOID_RETURN;
  334. }
  335.  
  336.  
  337. /* Get all access bits from table after fieldnr */
  338.  
  339. static uint get_access(TABLE *form,uint fieldnr)
  340. {
  341.   uint access_bits=0,bit;
  342.   char buff[2];
  343.   String res(buff,sizeof(buff));
  344.   Field **pos;
  345.  
  346.   for (pos=form->field+fieldnr,bit=1 ; *pos ; pos++ , bit<<=1)
  347.   {
  348.     (*pos)->val_str(&res,&res);
  349.     if (toupper(res[0]) == 'Y')
  350.       access_bits|=bit;
  351.   }
  352.   return access_bits;
  353. }
  354.  
  355.  
  356. /*
  357.  return a number with if sorted put string in this order:
  358.  no wildcards
  359.  wildcards
  360.  empty string
  361.  */
  362.  
  363. static ulong get_sort(uint count,...)
  364. {
  365.   va_list args;
  366.   va_start(args,count);
  367.   ulong sort=0;
  368.  
  369.   while (count--)
  370.   {
  371.     char *str=va_arg(args,char*);
  372.     uint chars=0,wild=0;
  373.  
  374.     if (str)
  375.     {
  376.       for (; *str ; str++)
  377.       {
  378.     if (*str == wild_many || *str == wild_one || *str == wild_prefix)
  379.       wild++;
  380.     else
  381.       chars++;
  382.       }
  383.     }
  384.     sort= (sort << 8) + (wild ? 1 : chars ? 2 : 0);
  385.   }
  386.   va_end(args);
  387.   return sort;
  388. }
  389.  
  390.  
  391. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
  392. {
  393.   if (a->sort > b->sort)
  394.     return -1;
  395.   if (a->sort < b->sort)
  396.     return 1;
  397.   return 0;
  398. }
  399.  
  400.  
  401. /* Get master privilges for user (priviliges for all tables) */
  402.  
  403.  
  404. uint acl_getroot(const char *host, const char *ip, const char *user,
  405.          const char *password,const char *message,char **priv_user,
  406.          bool old_ver)
  407. {
  408.   uint user_access=NO_ACCESS;
  409.   *priv_user=(char*) user;
  410.  
  411.   if (!initialized)
  412.     return (uint) ~NO_ACCESS;            // If no data allow anything /* purecov: tested */
  413.   VOID(pthread_mutex_lock(&acl_cache->lock));
  414.  
  415.   /*
  416.     Get possible access from user_list. This is or'ed to others not
  417.     fully specified
  418.   */
  419.   for (uint i=0 ; i < acl_users.elements ; i++)
  420.   {
  421.     ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  422.     if (!acl_user->user || !strcmp(user,acl_user->user))
  423.     {
  424.       if (compare_hostname(&acl_user->host,host,ip))
  425.       {
  426.     if (!acl_user->password && !*password ||
  427.         (acl_user->password && *password &&
  428.          !check_scramble(password,message,acl_user->salt,
  429.                  (my_bool) old_ver)))
  430.     {
  431.       user_access=acl_user->access;
  432.       if (!acl_user->user)
  433.         *priv_user=(char*) "";    // Change to anonymous user /* purecov: inspected */
  434.       break;
  435.     }
  436. #ifndef ALLOW_DOWNGRADE_OF_USERS
  437.     break;                // Wrong password breaks loop /* purecov: inspected */
  438. #endif
  439.       }
  440.     }
  441.   }
  442.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  443.   return user_access;
  444. }
  445.  
  446.  
  447. /*
  448. ** Functions to add and change user and database privileges when one
  449. ** changes things with GRANT
  450. */
  451.  
  452. static byte* check_get_key(ACL_USER *buff,uint *length,
  453.                my_bool not_used __attribute__((unused)))
  454. {
  455.   *length=buff->hostname_length;
  456.   return (byte*) buff->host.hostname;
  457. }
  458.  
  459. static void acl_update_user(const char *user, const char *host,
  460.                 const char *password, uint privileges)
  461. {
  462.   for (uint i=0 ; i < acl_users.elements ; i++)
  463.   {
  464.     ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  465.     if (!acl_user->user && !user[0] ||
  466.     acl_user->user &&
  467.     !strcmp(user,acl_user->user))
  468.     {
  469.       if (!acl_user->host.hostname && !host[0] ||
  470.       acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
  471.       {
  472.     acl_user->access=privileges;
  473.     if (password)
  474.     {
  475.       if (!password[0])
  476.         acl_user->password=0;
  477.       else
  478.       {
  479.         acl_user->password=(char*) "";    // Just point at something
  480.         get_salt_from_password(acl_user->salt,password);
  481.       }
  482.     }
  483.     break;
  484.       }
  485.     }
  486.   }
  487. }
  488.  
  489.  
  490. static void acl_insert_user(const char *user, const char *host,
  491.                 const char *password,
  492.                 uint privileges)
  493. {
  494.   ACL_USER acl_user;
  495.   acl_user.user=strdup_root(&mem,user);
  496.   update_hostname(&acl_user.host,strdup_root(&mem,host));
  497.   acl_user.password=0;
  498.   acl_user.access=privileges;
  499.   acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
  500.   acl_user.hostname_length=(uint) strlen(acl_user.host.hostname);
  501.   if (password)
  502.   {
  503.     acl_user.password=(char*) "";        // Just point at something
  504.     get_salt_from_password(acl_user.salt,password);
  505.   }
  506.  
  507.   VOID(push_dynamic(&acl_users,(gptr) &acl_user));
  508.   if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
  509.       && !acl_user.host.hostname[1])
  510.     allow_all_hosts=1;            // Anyone can connect /* purecov: tested */
  511.   qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  512.     sizeof(ACL_USER),(qsort_cmp) acl_compare);
  513.  
  514.   /* We must free acl_check_hosts as its memory is mapped to acl_user */
  515.   delete_dynamic(&acl_wild_hosts);
  516.   hash_free(&acl_check_hosts);
  517.   init_check_host();
  518. }
  519.  
  520.  
  521. static void acl_update_db(const char *user, const char *host, const char *db,
  522.               uint privileges)
  523. {
  524.   for (uint i=0 ; i < acl_dbs.elements ; i++)
  525.   {
  526.     ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  527.     if (!acl_db->user && !user[0] ||
  528.     acl_db->user &&
  529.     !strcmp(user,acl_db->user))
  530.     {
  531.       if (!acl_db->host.hostname && !host[0] ||
  532.       acl_db->host.hostname && !strcmp(host,acl_db->host.hostname))
  533.       {
  534.     if (!acl_db->db && !db[0] ||
  535.         acl_db->db && !strcmp(db,acl_db->db))
  536.     {
  537.       if (privileges)
  538.         acl_db->access=privileges;
  539.       else
  540.         delete_dynamic_element(&acl_dbs,i);
  541.     }
  542.       }
  543.     }
  544.   }
  545. }
  546.  
  547.  
  548. static void acl_insert_db(const char *user, const char *host, const char *db,
  549.               uint privileges)
  550. {
  551.   ACL_DB acl_db;
  552.   /* The acl_cache mutex is locked by mysql_grant */
  553.   acl_db.user=strdup_root(&mem,user);
  554.   update_hostname(&acl_db.host,strdup_root(&mem,host));
  555.   acl_db.db=strdup_root(&mem,db);
  556.   acl_db.access=privileges;
  557.   acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
  558.   VOID(push_dynamic(&acl_dbs,(gptr) &acl_db));
  559.   qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  560.     sizeof(ACL_DB),(qsort_cmp) acl_compare);
  561. }
  562.  
  563.  
  564. /*****************************************************************************
  565. ** Get privilege for a host, user and db combination
  566. *****************************************************************************/
  567.  
  568. uint acl_get(const char *host, const char *ip, const char *bin_ip,
  569.          const char *user, const char *db)
  570. {
  571.   uint host_access,db_access,i,key_length;
  572.   db_access=0; host_access= ~0;
  573.   char key[ACL_KEY_LENGTH],*end;
  574.   acl_entry *entry;
  575.  
  576.   VOID(pthread_mutex_lock(&acl_cache->lock));
  577.   memcpy_fixed(&key,bin_ip,sizeof(struct in_addr));
  578.   end=strmov(strmov(key+sizeof(struct in_addr),user)+1,db);
  579.   key_length=(uint) (end-key);
  580.   if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
  581.   {
  582.     db_access=entry->access;
  583.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  584.     return db_access;
  585.   }
  586.  
  587.   /*
  588.     Check if there are some access rights for database and user
  589.   */
  590.   for (i=0 ; i < acl_dbs.elements ; i++)
  591.   {
  592.     ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  593.     if (!acl_db->user || !strcmp(user,acl_db->user))
  594.     {
  595.       if (compare_hostname(&acl_db->host,host,ip))
  596.       {
  597.     if (!acl_db->db || !wild_compare(db,acl_db->db))
  598.     {
  599.       db_access=acl_db->access;
  600.       if (acl_db->host.hostname)
  601.         goto exit;                // Fully specified. Take it
  602.       break; /* purecov: tested */
  603.     }
  604.       }
  605.     }
  606.   }
  607.   if (!db_access)
  608.     goto exit;                    // Can't be better
  609.  
  610.   /*
  611.     No host specified for user. Get hostdata from host table
  612.   */
  613.   host_access=0;                // Host must be found
  614.   for (i=0 ; i < acl_hosts.elements ; i++)
  615.   {
  616.     ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
  617.     if (compare_hostname(&acl_host->host,host,ip))
  618.     {
  619.       if (!acl_host->db || !wild_compare(db,acl_host->db))
  620.       {
  621.     host_access=acl_host->access;        // Fully specified. Take it
  622.     break;
  623.       }
  624.     }
  625.   }
  626. exit:
  627.   /* Save entry in cache for quick retrieval */
  628.   if ((entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
  629.   {
  630.     entry->access=(db_access & host_access);
  631.     entry->length=key_length;
  632.     memcpy((gptr) entry->key,key,key_length);
  633.     acl_cache->add(entry);
  634.   }
  635.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  636.   return (db_access & host_access);
  637. }
  638.  
  639.  
  640. int wild_case_compare(const char *str,const char *wildstr)
  641. {
  642.   reg3 int flag;
  643.   DBUG_ENTER("wild_case_compare");
  644.  
  645.   while (*wildstr)
  646.   {
  647.     while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
  648.     {
  649.       if (*wildstr == wild_prefix && wildstr[1])
  650.     wildstr++;
  651.       if (toupper(*wildstr++) != toupper(*str++)) DBUG_RETURN(1);
  652.     }
  653.     if (! *wildstr ) DBUG_RETURN (*str != 0);
  654.     if (*wildstr++ == wild_one)
  655.     {
  656.       if (! *str++) DBUG_RETURN (1);    /* One char; skipp */
  657.     }
  658.     else
  659.     {                        /* Found '*' */
  660.       if (!*wildstr) DBUG_RETURN(0);        /* '*' as last char: OK */
  661.       flag=(*wildstr != wild_many && *wildstr != wild_one);
  662.       do
  663.       {
  664.     if (flag)
  665.     {
  666.       char cmp;
  667.       if ((cmp= *wildstr) == wild_prefix && wildstr[1])
  668.         cmp=wildstr[1];
  669.       cmp=toupper(cmp);
  670.       while (*str && toupper(*str) != cmp)
  671.         str++;
  672.       if (!*str) DBUG_RETURN (1);
  673.     }
  674.     if (wild_case_compare(str,wildstr) == 0) DBUG_RETURN (0);
  675.       } while (*str++);
  676.       DBUG_RETURN(1);
  677.     }
  678.   }
  679.   DBUG_RETURN (*str != '\0');
  680. }
  681.  
  682. /*****************************************************************************
  683. ** check if there are any possible matching entries for this host
  684. ** All host names without wild cards are stored in a hash table,
  685. ** entries with wildcards are stored in a dynamic array
  686. *****************************************************************************/
  687.  
  688. static void init_check_host(void)
  689. {
  690.   DBUG_ENTER("init_check_host");
  691.   VOID(init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
  692.               acl_users.elements,1));
  693.   VOID(hash_init(&acl_check_hosts,acl_users.elements,0,0,
  694.          (hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
  695.   if (!allow_all_hosts)
  696.   {
  697.     for (uint i=0 ; i < acl_users.elements ; i++)
  698.     {
  699.       ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  700.       if (strchr(acl_user->host.hostname,wild_many) ||
  701.       strchr(acl_user->host.hostname,wild_one) ||
  702.       acl_user->host.ip_mask)
  703.       {                        // Has wildcard
  704.     uint j;
  705.     for (j=0 ; j < acl_wild_hosts.elements ; j++)
  706.     {                    // Check if host already exists
  707.       acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
  708.                            acl_host_and_ip *);
  709.       if (!my_strcasecmp(acl_user->host.hostname,acl->hostname))
  710.         break;                // already stored
  711.     }
  712.     if (j == acl_wild_hosts.elements)    // If new
  713.       (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
  714.       }
  715.       else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
  716.                 (uint) strlen(acl_user->host.hostname)))
  717.       {
  718.     if (hash_insert(&acl_check_hosts,(byte*) acl_user))
  719.     {                    // End of memory
  720.       allow_all_hosts=1;            // Should never happen
  721.       DBUG_VOID_RETURN;
  722.     }
  723.       }
  724.     }
  725.   }
  726.   freeze_size(&acl_wild_hosts);
  727.   freeze_size(&acl_check_hosts.array);
  728.   DBUG_VOID_RETURN;
  729. }
  730.  
  731.  
  732. /* Return true if there is no users that can match the given host */
  733.  
  734. bool acl_check_host(const char *host, const char *ip)
  735. {
  736.   if (allow_all_hosts)
  737.     return 0;
  738.   VOID(pthread_mutex_lock(&acl_cache->lock));
  739.  
  740.   if (host && hash_search(&acl_check_hosts,(byte*) host,(uint) strlen(host)) ||
  741.       ip && hash_search(&acl_check_hosts,(byte*) ip,(uint) strlen(ip)))
  742.   {
  743.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  744.     return 0;                    // Found host
  745.   }
  746.   for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
  747.   {
  748.     acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
  749.     if (compare_hostname(acl, host, ip))
  750.     {
  751.       VOID(pthread_mutex_unlock(&acl_cache->lock));
  752.       return 0;                    // Host ok
  753.     }
  754.   }
  755.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  756.   return 1;                    // Host is not allowed
  757. }
  758.  
  759. /*****************************************************************************
  760. ** Change password for the user if it's not an anonymous user
  761. ** Note: This should write the error directly to the client!
  762. *****************************************************************************/
  763.  
  764. bool change_password(THD *thd, const char *host, const char *user,
  765.              char *new_password)
  766. {
  767.   uint length=0;
  768.   if (!user[0])
  769.   {
  770.     send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
  771.     return 1;
  772.   }
  773.   if (!initialized)
  774.   {
  775.     send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
  776.     return 1; /* purecov: inspected */
  777.   }
  778.   if (!host)
  779.     host=thd->ip; /* purecov: tested */
  780.   /* password should always be 0 or 16 chars; simple hack to avoid cracking */
  781.   length=(uint) strlen(new_password);
  782.   new_password[length & 16]=0;
  783.  
  784.   if (!thd || strcmp(thd->user,user) ||
  785.       my_strcasecmp(host,thd->host ? thd->host : thd->ip))
  786.   {
  787.     if (check_access(thd, UPDATE_ACL, "mysql",0,1))
  788.       return 1;
  789.   }
  790.   VOID(pthread_mutex_lock(&acl_cache->lock));
  791.   ACL_USER *acl_user;
  792.   if (!(acl_user= find_acl_user(host,user)) || !acl_user->user)
  793.   {
  794.     send_error(&thd->net, ER_PASSWORD_NO_MATCH);
  795.     VOID(pthread_mutex_unlock(&acl_cache->lock));
  796.     return 1;
  797.   }
  798.   if (update_user_table(thd,
  799.             acl_user->host.hostname ? acl_user->host.hostname : "",
  800.             acl_user->user, new_password))
  801.   {
  802.     VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
  803.     send_error(&thd->net,0); /* purecov: deadcode */
  804.     return 1; /* purecov: deadcode */
  805.   }
  806.   get_salt_from_password(acl_user->salt,new_password);
  807.   if (!new_password[0])
  808.     acl_user->password=0;
  809.   else
  810.     acl_user->password=(char*) "";        // Point at something
  811.   acl_cache->clear(1);                // Clear locked hostname cache
  812.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  813.  
  814.   char buff[460];
  815.   
  816.   Query_log_event qinfo(thd, buff);
  817.   qinfo.q_len =
  818.     my_sprintf(buff,
  819.            (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
  820.         acl_user->user,
  821.         acl_user->host.hostname ? acl_user->host.hostname : "",
  822.         new_password));
  823.   mysql_update_log.write(thd,buff,qinfo.q_len);
  824.   mysql_bin_log.write(&qinfo);
  825.   return 0;
  826. }
  827.  
  828.  
  829. /*
  830.   Find first entry that matches the current user
  831. */
  832.  
  833. static ACL_USER *
  834. find_acl_user(const char *host, const char *user)
  835. {
  836.   for (uint i=0 ; i < acl_users.elements ; i++)
  837.   {
  838.     ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  839.     if (!acl_user->user && !user[0] ||
  840.     acl_user->user && !strcmp(user,acl_user->user))
  841.     {
  842.       if (compare_hostname(&acl_user->host,host,host))
  843.     return acl_user;
  844.     }
  845.   }
  846.   return 0;
  847. }
  848.  
  849. /*****************************************************************************
  850.     Handle comparing of hostname
  851.     A hostname may be of type:
  852.     hostname   (May include wildcards);   monty.pp.sci.fi
  853.     ip       (May include wildcards);   192.168.0.0
  854.     ip/netmask                  192.168.0.0/255.255.255.0
  855.  
  856.     A net mask of 0.0.0.0 is not allowed.
  857. *****************************************************************************/
  858.  
  859. static const char *calc_ip(const char *ip, long *val, char end)
  860. {
  861.   long ip_val,tmp;
  862.   if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
  863.     return 0;
  864.   ip_val<<=24;
  865.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  866.     return 0;
  867.   ip_val+=tmp<<16;
  868.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  869.     return 0;
  870.   ip_val+=tmp<<8;
  871.   if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
  872.     return 0;
  873.   *val=ip_val+tmp;
  874.   return ip;
  875. }
  876.  
  877.  
  878. static void update_hostname(acl_host_and_ip *host, const char *hostname)
  879. {
  880.   host->hostname=(char*) hostname;        // This will not be modified!
  881.   if (hostname &&
  882.       (!(hostname=calc_ip(hostname,&host->ip,'/')) ||
  883.        !(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
  884.   {
  885.     host->ip=host->ip_mask=0;            // Not a masked ip
  886.   }
  887. }
  888.  
  889.  
  890. static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
  891.                  const char *ip)
  892. {
  893.   long tmp;
  894.   if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0'))
  895.   {
  896.     return (tmp & host->ip_mask) == host->ip;
  897.   }
  898.   return (!host->hostname ||
  899.       (hostname && !wild_case_compare(hostname,host->hostname)) ||
  900.       (ip && !wild_compare(ip,host->hostname)));
  901. }
  902.  
  903.  
  904. /****************************************************************************
  905. ** Code to update grants in the user and database privilege tables
  906. ****************************************************************************/
  907.  
  908. static bool update_user_table(THD *thd, const char *host, const char *user,
  909.                   const char *new_password)
  910. {
  911.   TABLE_LIST tables;
  912.   TABLE *table;
  913.   bool error=1;
  914.   DBUG_ENTER("update_user_table");
  915.   DBUG_PRINT("enter",("user: %s  host: %s",user,host));
  916.  
  917.   bzero((char*) &tables,sizeof(tables));
  918.   tables.name=tables.real_name=(char*) "user";
  919.   tables.db=(char*) "mysql";
  920.   if (!(table=open_ltable(thd,&tables,TL_WRITE)))
  921.     DBUG_RETURN(1); /* purecov: deadcode */
  922.   table->field[0]->store(host,(uint) strlen(host));
  923.   table->field[1]->store(user,(uint) strlen(user));
  924.  
  925.   if (table->file->index_read_idx(table->record[0],0,
  926.                   (byte*) table->field[0]->ptr,0,
  927.                   HA_READ_KEY_EXACT))
  928.   {
  929.     my_error(ER_PASSWORD_NO_MATCH,MYF(0));    /* purecov: deadcode */
  930.     DBUG_RETURN(1);                /* purecov: deadcode */
  931.   }
  932.   store_record(table,1);
  933.   table->field[2]->store(new_password,(uint) strlen(new_password));
  934.   if ((error=table->file->update_row(table->record[1],table->record[0])))
  935.   {
  936.     table->file->print_error(error,MYF(0));    /* purecov: deadcode */
  937.     goto end;                    /* purecov: deadcode */
  938.   }
  939.   error=0;                    // Record updated
  940.  
  941. end:
  942.   close_thread_tables(thd);
  943.   DBUG_RETURN(error);
  944. }
  945.  
  946. /****************************************************************************
  947. ** Handle GRANT commands
  948. ****************************************************************************/
  949.  
  950. static int replace_user_table(TABLE *table, const LEX_USER &combo,
  951.                   uint rights, char what)
  952. {
  953.   int error = -1;
  954.   uint i,j;
  955.   bool ima=0;
  956.   char *password,empty_string[1];
  957.   DBUG_ENTER("replace_user_table");
  958.  
  959.   if (combo.password.str && combo.password.str[0])
  960.     password=combo.password.str;
  961.   else
  962.   {
  963.     password=empty_string;
  964.     empty_string[0]=0;
  965.   }
  966.  
  967.   table->field[0]->store(combo.host.str,combo.host.length);
  968.   table->field[1]->store(combo.user.str,combo.user.length);
  969.   table->file->index_init(0);
  970.   if (table->file->index_read(table->record[0],
  971.                   (byte*) table->field[0]->ptr,0,
  972.                   HA_READ_KEY_EXACT))
  973.   {
  974.     if (what == 'N')
  975.     {
  976.       my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
  977.               MYF(0),combo.user.str,combo.host.str);
  978.       error= -1;
  979.       goto end;
  980.     }
  981.     ima = 0; // no row; ima on Serbian means 'there is something'
  982.     restore_record(table,2);            // cp empty row from record[2]
  983.     table->field[0]->store(combo.host.str,combo.host.length);
  984.     table->field[1]->store(combo.user.str,combo.user.length);
  985.     table->field[2]->store(password,(uint) strlen(password));
  986.   }
  987.   else
  988.   {
  989.     ima = 1;
  990.     store_record(table,1);            // Save copy for update
  991.     if (combo.password.str)            // If password given
  992.       table->field[2]->store(password,(uint) strlen(password));
  993.   }
  994.  
  995.   for (i = 3, j = SELECT_ACL;            // starting from reload
  996.        i < table->fields;
  997.        i++, j <<= 1)
  998.   {
  999.     if (j & rights)                 // set requested privileges
  1000.       table->field[i]->store(&what,1);
  1001.   }
  1002.   rights=get_access(table,3);
  1003.  
  1004.   if (ima)  // there is a row, therefore go to update, instead of insert
  1005.   {
  1006.     /*
  1007.       We should NEVER delete from the user table, as a uses can still
  1008.       use mysqld even if he doesn't have any privileges in the user table!
  1009.     */
  1010.     if (cmp_record(table,1) &&
  1011.     (error=table->file->update_row(table->record[1],table->record[0])))
  1012.     {                        // This should never happen
  1013.       table->file->print_error(error,MYF(0));    /* purecov: deadcode */
  1014.       error= -1;                /* purecov: deadcode */
  1015.       goto end;                    /* purecov: deadcode */
  1016.     }
  1017.   }
  1018.   else if ((error=table->file->write_row(table->record[0]))) // insert
  1019.   {                        // This should never happen
  1020.     if (error && error != HA_ERR_FOUND_DUPP_KEY &&
  1021.     error != HA_ERR_FOUND_DUPP_UNIQUE)    /* purecov: inspected */
  1022.     {
  1023.       table->file->print_error(error,MYF(0));    /* purecov: deadcode */
  1024.       error= -1;                /* purecov: deadcode */
  1025.       goto end;                    /* purecov: deadcode */
  1026.     }
  1027.   }
  1028.   error=0;                    // Privileges granted / revoked
  1029.  
  1030.  end:
  1031.   if (!error)
  1032.   {
  1033.     acl_cache->clear(1);            // Clear privilege cache
  1034.     if (!combo.password.str)
  1035.       password=0;                // No password given on command
  1036.     if (ima)
  1037.       acl_update_user(combo.user.str,combo.host.str,password,rights);
  1038.     else
  1039.       acl_insert_user(combo.user.str,combo.host.str,password,rights);
  1040.   }
  1041.   table->file->index_end();
  1042.   DBUG_RETURN(error);
  1043. }
  1044.  
  1045.  
  1046. /*
  1047. ** change grants in the mysql.db table
  1048. */
  1049.  
  1050. static int replace_db_table(TABLE *table, const char *db,
  1051.                 const LEX_USER &combo,
  1052.                 uint rights, char what)
  1053. {
  1054.   uint i,j,store_rights;
  1055.   bool ima=0;
  1056.   int error;
  1057.   DBUG_ENTER("replace_db_table");
  1058.  
  1059.   // is there such a user in user table in memory ????
  1060.   if (!initialized || !find_acl_user(combo.host.str,combo.user.str))
  1061.   {
  1062.     my_error(ER_PASSWORD_NO_MATCH,MYF(0));
  1063.     DBUG_RETURN(-1);
  1064.   }
  1065.  
  1066.   table->field[0]->store(combo.host.str,combo.host.length);
  1067.   table->field[1]->store(db,(uint) strlen(db));
  1068.   table->field[2]->store(combo.user.str,combo.user.length);
  1069.   table->file->index_init(0);
  1070.   if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
  1071.           HA_READ_KEY_EXACT))
  1072.   {
  1073.     if (what == 'N')
  1074.     { // no row, no revoke
  1075.       my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),MYF(0),
  1076.               combo.user.str,combo.host.str);
  1077.       goto abort;
  1078.     }
  1079.     ima = 0; // no row
  1080.     restore_record(table,2);            // cp empty row from record[2]
  1081.     table->field[0]->store(combo.host.str,combo.host.length);
  1082.     table->field[1]->store(db,(uint) strlen(db));
  1083.     table->field[2]->store(combo.user.str,combo.user.length);
  1084.   }
  1085.   else
  1086.   {
  1087.     ima = 1;
  1088.     store_record(table,1);
  1089.   }
  1090.  
  1091.   store_rights=get_rights_for_db(rights);
  1092.   for (i = 3, j = 1; i < table->fields; i++, j <<= 1)
  1093.   {
  1094.     if (j & store_rights)            // do it if priv is chosen
  1095.       table->field [i]->store(&what,1);        // set requested privileges
  1096.   }
  1097.   rights=get_access(table,3);
  1098.   rights=fix_rights_for_db(rights);
  1099.  
  1100.   if (ima) // there is a row, therefore go update, else insert
  1101.   {
  1102.     if (rights)
  1103.     {
  1104.       if ((error=table->file->update_row(table->record[1],table->record[0])))
  1105.     goto table_error;            /* purecov: deadcode */
  1106.     }
  1107.     else    /* must have been a revoke of all privileges */
  1108.     {
  1109.       if ((error = table->file->delete_row(table->record[1])))
  1110.     goto table_error;            /* purecov: deadcode */
  1111.     }
  1112.   }
  1113.   else if ((error=table->file->write_row(table->record[0])))
  1114.   {
  1115.     if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
  1116.       goto table_error; /* purecov: deadcode */
  1117.   }
  1118.  
  1119.   acl_cache->clear(1);                // Clear privilege cache
  1120.   if (ima)
  1121.     acl_update_db(combo.user.str,combo.host.str,db,rights);
  1122.   else
  1123.     acl_insert_db(combo.user.str,combo.host.str,db,rights);
  1124.   table->file->index_end();
  1125.   DBUG_RETURN(0);
  1126.  
  1127.   /* This could only happen if the grant tables got corrupted */
  1128.  table_error:
  1129.   table->file->print_error(error,MYF(0));    /* purecov: deadcode */
  1130.   table->file->index_end();
  1131.  
  1132.  abort:
  1133.   DBUG_RETURN(-1);
  1134. }
  1135.  
  1136.  
  1137. class GRANT_COLUMN :public Sql_alloc
  1138. {
  1139. public:
  1140.   char *column;
  1141.   uint rights, key_length;
  1142.   GRANT_COLUMN(String &c,  uint y) :rights (y)
  1143.   {
  1144.     column= memdup_root(&memex,c.ptr(),key_length=c.length());
  1145.   }
  1146. };
  1147.  
  1148. static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
  1149.                 my_bool not_used __attribute__((unused)))
  1150. {
  1151.   *length=buff->key_length;
  1152.   return (byte*) buff->column;
  1153. }
  1154.  
  1155. class GRANT_TABLE :public Sql_alloc
  1156. {
  1157. public:
  1158.   char *host,*db,*user,*tname, *hash_key;
  1159.   uint privs, cols, key_length;
  1160.   HASH hash_columns;
  1161.   GRANT_TABLE (const char *h, const char *d,const char *u, const char *t,
  1162.            uint p,uint c)
  1163.     : privs(p), cols(c)
  1164.   {
  1165.     host = strdup_root(&memex,h);
  1166.     db =   strdup_root(&memex,d);
  1167.     user = strdup_root(&memex,u);
  1168.     tname= strdup_root(&memex,t);
  1169.     key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
  1170.     hash_key = (char*) alloc_root(&memex,key_length);
  1171.     strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  1172.     (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
  1173.              HASH_CASE_INSENSITIVE);
  1174.   }
  1175.  
  1176.   GRANT_TABLE (TABLE *form, TABLE *col_privs)
  1177.   {
  1178.     byte key[MAX_KEY_LENGTH];
  1179.  
  1180.     host =  get_field(&memex,form,0);
  1181.     db =    get_field(&memex,form,1);
  1182.     user =  get_field(&memex,form,2);  if (!user) user=(char*) "";
  1183.     tname = get_field(&memex,form,3);
  1184.     if (!host || !db || !tname)
  1185.     {
  1186.       /* Wrong table row; Ignore it */
  1187.       privs = cols = 0;                /* purecov: inspected */
  1188.       return;                    /* purecov: inspected */
  1189.     }
  1190.     key_length = (uint) strlen(db) + (uint) strlen(user) + (uint) strlen (tname) + 3;
  1191.     hash_key = (char*) alloc_root(&memex,key_length);
  1192.     strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  1193.     privs = (uint) form->field[6]->val_int();
  1194.     cols  = (uint) form->field[7]->val_int();
  1195.     privs = fix_rights_for_table(privs);
  1196.     cols =  fix_rights_for_column(cols);
  1197.  
  1198.     (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
  1199.              HASH_CASE_INSENSITIVE);
  1200.     if (cols)
  1201.     {
  1202.       int key_len;
  1203.       col_privs->field[0]->store(host,(uint) strlen(host));
  1204.       col_privs->field[1]->store(db,(uint) strlen(db));
  1205.       col_privs->field[2]->store(user,(uint) strlen(user));
  1206.       col_privs->field[3]->store(tname,(uint) strlen(tname));
  1207.       key_len=(col_privs->field[0]->pack_length()+
  1208.            col_privs->field[1]->pack_length()+
  1209.            col_privs->field[2]->pack_length()+
  1210.            col_privs->field[3]->pack_length());
  1211.       key_copy(key,col_privs,0,key_len);
  1212.       col_privs->field[4]->store("",0);
  1213.       col_privs->file->index_init(0);
  1214.       if (col_privs->file->index_read(col_privs->record[0],
  1215.                       (byte*) col_privs->field[0]->ptr,
  1216.                       key_len, HA_READ_KEY_EXACT))
  1217.       {
  1218.     cols = 0; /* purecov: deadcode */
  1219.     return;
  1220.       }
  1221.       do
  1222.       {
  1223.     String *res,column_name;
  1224.     GRANT_COLUMN *mem_check;
  1225.     /* As column name is a string, we don't have to supply a buffer */
  1226.     res=col_privs->field[4]->val_str(&column_name,&column_name);
  1227.     uint priv= (uint) col_privs->field[6]->val_int();
  1228.     if (!(mem_check = new GRANT_COLUMN(*res,
  1229.                        fix_rights_for_column(priv))))
  1230.     {
  1231.       // Don't use this entry
  1232.       privs = cols = 0;            /* purecov: deadcode */
  1233.       return;                /* purecov: deadcode */
  1234.     }
  1235.     hash_insert(&hash_columns, (byte *) mem_check);
  1236.       } while (!col_privs->file->index_next(col_privs->record[0]) &&
  1237.            !key_cmp(col_privs,key,0,key_len));
  1238.     }
  1239.   }
  1240.   bool ok() { return privs != 0 || cols != 0; }
  1241. };
  1242.  
  1243. static byte* get_grant_table(GRANT_TABLE *buff,uint *length,
  1244.                  my_bool not_used __attribute__((unused)))
  1245. {
  1246.   *length=buff->key_length;
  1247.   return (byte*) buff->hash_key;
  1248. }
  1249.  
  1250. void free_grant_table(GRANT_TABLE *grant_table)
  1251. {
  1252.   hash_free(&grant_table->hash_columns);
  1253. }
  1254.  
  1255. /* Search after a matching grant. Prefer exact grants before not exact ones */
  1256.  
  1257. static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
  1258.                       const char *db,
  1259.                       const char *user, const char *tname,
  1260.                       bool exact)
  1261. {
  1262.   char helping [NAME_LEN*2+USERNAME_LENGTH+3];
  1263.   uint len;
  1264.   GRANT_TABLE *grant_table,*found=0;
  1265.  
  1266.   len  = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
  1267.   for (grant_table=(GRANT_TABLE*) hash_search(&hash_tables,(byte*) helping,
  1268.                           len) ;
  1269.        grant_table ;
  1270.        grant_table= (GRANT_TABLE*) hash_next(&hash_tables,(byte*) helping,len))
  1271.   {
  1272.     if (exact)
  1273.     {
  1274.       if ((host && !strcmp(host,grant_table->host)) ||
  1275.       (ip && !strcmp(ip,grant_table->host)))
  1276.     return grant_table;
  1277.     }
  1278.     else
  1279.     {
  1280.       if ((host && !wild_case_compare(host,grant_table->host)) ||
  1281.       (ip && !wild_case_compare(ip,grant_table->host)))
  1282.     found=grant_table;                    // Host ok
  1283.     }
  1284.   }
  1285.   return found;
  1286. }
  1287.  
  1288.  
  1289.  
  1290. static inline GRANT_COLUMN *
  1291. column_hash_search(GRANT_TABLE *t, const char *cname,
  1292.                     uint length)
  1293. {
  1294.   return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length);
  1295. }
  1296.  
  1297.  
  1298. static int replace_column_table(GRANT_TABLE *g_t,
  1299.                 TABLE *table, const LEX_USER &combo,
  1300.                 List <LEX_COLUMN> &columns,
  1301.                 const char *db, const char *table_name,
  1302.                 uint rights, bool revoke_grant)
  1303. {
  1304.   int error=0,result=0;
  1305.   uint key_length;
  1306.   byte key[MAX_KEY_LENGTH];
  1307.   DBUG_ENTER("replace_column_table");
  1308.  
  1309.   table->field[0]->store(combo.host.str,combo.host.length);
  1310.   table->field[1]->store(db,(uint) strlen(db));
  1311.   table->field[2]->store(combo.user.str,combo.user.length);
  1312.   table->field[3]->store(table_name,(uint) strlen(table_name));
  1313.   key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
  1314.           table->field[2]->pack_length()+ table->field[3]->pack_length());
  1315.   key_copy(key,table,0,key_length);
  1316.  
  1317.   rights &= COL_ACLS;                // Only ACL for columns
  1318.  
  1319.   /* first fix privileges for all columns in column list */
  1320.  
  1321.   List_iterator <LEX_COLUMN> iter(columns);
  1322.   class LEX_COLUMN *xx;
  1323.   table->file->index_init(0);
  1324.   while ((xx=iter++))
  1325.   {
  1326.     uint privileges = xx->rights;
  1327.     bool ima=0;
  1328.     key_restore(table,key,0,key_length);
  1329.     table->field[4]->store(xx->column.ptr(),xx->column.length());
  1330.  
  1331.     if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
  1332.                 0, HA_READ_KEY_EXACT))
  1333.     {
  1334.       if (revoke_grant)
  1335.       {
  1336.     my_printf_error(ER_NONEXISTING_TABLE_GRANT,
  1337.             ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
  1338.             combo.user.str, combo.host.str,table_name); /* purecov: inspected */
  1339.     result= -1; /* purecov: inspected */
  1340.     continue; /* purecov: inspected */
  1341.       }
  1342.       ima = 0;
  1343.       restore_record(table,2);            // Get empty record
  1344.       key_restore(table,key,0,key_length);
  1345.       table->field[4]->store(xx->column.ptr(),xx->column.length());
  1346.     }
  1347.     else
  1348.     {
  1349.       uint tmp= (uint) table->field[6]->val_int();
  1350.       tmp=fix_rights_for_column(tmp);
  1351.  
  1352.       if (revoke_grant)
  1353.     privileges = tmp & ~(privileges | rights);
  1354.       else
  1355.     privileges |= tmp;
  1356.       ima = 1;
  1357.       store_record(table,1);            // copy original row
  1358.     }
  1359.  
  1360.     table->field[6]->store((longlong) get_rights_for_column(privileges));
  1361.  
  1362.     if (ima) // there is a row, therefore go update, else insert
  1363.     {
  1364.       if (privileges)
  1365.     error=table->file->update_row(table->record[1],table->record[0]);
  1366.       else
  1367.     error=table->file->delete_row(table->record[1]);
  1368.       if (error)
  1369.       {
  1370.     table->file->print_error(error,MYF(0)); /* purecov: inspected */
  1371.     result= -1;                /* purecov: inspected */
  1372.     goto end;                /* purecov: inspected */
  1373.       }
  1374.       GRANT_COLUMN *grant_column = column_hash_search(g_t,
  1375.                               xx->column.ptr(),
  1376.                               xx->column.length());
  1377.       if (grant_column)                // Should always be true
  1378.     grant_column->rights = privileges;    // Update hash
  1379.     }
  1380.     else                    // new grant
  1381.     {
  1382.       if ((error=table->file->write_row(table->record[0])))
  1383.       {
  1384.     table->file->print_error(error,MYF(0)); /* purecov: inspected */
  1385.     result= -1;                /* purecov: inspected */
  1386.     goto end;                /* purecov: inspected */
  1387.       }
  1388.       GRANT_COLUMN *grant_column = new GRANT_COLUMN(xx->column,privileges);
  1389.       hash_insert(&g_t->hash_columns,(byte*) grant_column);
  1390.     }
  1391.   }
  1392.   table->file->index_end();
  1393.  
  1394.   /*
  1395.     If revoke of privileges on the table level, remove all such privileges
  1396.     for all columns
  1397.   */
  1398.  
  1399.   if (revoke_grant)
  1400.   {
  1401.     table->file->index_init(0);
  1402.     if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,
  1403.                 key_length, HA_READ_KEY_EXACT))
  1404.       goto end;
  1405.  
  1406.     // Scan trough all rows with the same host,db,user and table
  1407.     do
  1408.     {
  1409.       uint privileges = (uint) table->field[6]->val_int();
  1410.       privileges=fix_rights_for_column(privileges);
  1411.       store_record(table,1);
  1412.  
  1413.       if (privileges & rights)    // is in this record the priv to be revoked ??
  1414.       {
  1415.     GRANT_COLUMN *grant_column = NULL;
  1416.     char  colum_name_buf[HOSTNAME_LENGTH+1];
  1417.     String column_name(colum_name_buf,sizeof(colum_name_buf));
  1418.  
  1419.     privileges&= ~rights;
  1420.     table->field[6]->store((longlong)
  1421.                    get_rights_for_column(privileges));
  1422.     table->field[4]->val_str(&column_name,&column_name);
  1423.     grant_column = column_hash_search(g_t,
  1424.                       column_name.ptr(),
  1425.                       column_name.length());
  1426.     if (privileges)
  1427.     {
  1428.       int tmp_error;
  1429.       if ((tmp_error=table->file->update_row(table->record[1],
  1430.                          table->record[0])))
  1431.       {                    /* purecov: deadcode */
  1432.         table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  1433.         result= -1;                /* purecov: deadcode */
  1434.         goto end;                /* purecov: deadcode */
  1435.       }
  1436.       if (grant_column)
  1437.         grant_column->rights  = privileges; // Update hash
  1438.     }
  1439.     else
  1440.     {
  1441.       int tmp_error;
  1442.       if ((tmp_error = table->file->delete_row(table->record[1])))
  1443.       {                    /* purecov: deadcode */
  1444.         table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  1445.         result= -1;                /* purecov: deadcode */
  1446.         goto end;                /* purecov: deadcode */
  1447.       }
  1448.       if (grant_column)
  1449.         hash_delete(&g_t->hash_columns,(byte*) grant_column);
  1450.     }
  1451.       }
  1452.     } while (!table->file->index_next(table->record[0]) &&
  1453.          !key_cmp(table,key,0,key_length));
  1454.   }
  1455.  
  1456.  end:
  1457.   table->file->index_end();
  1458.   DBUG_RETURN(result);
  1459. }
  1460.  
  1461.  
  1462. static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
  1463.                    TABLE *table, const LEX_USER &combo,
  1464.                    const char *db, const char *table_name,
  1465.                    uint rights, uint kolone, bool revoke_grant)
  1466. {
  1467.   char grantor[HOSTNAME_LENGTH+1+USERNAME_LENGTH];
  1468.   int ima = 1;
  1469.   int error=0;
  1470.   uint store_table_rights,store_col_rights;
  1471.   DBUG_ENTER("replace_table_table");
  1472.  
  1473.   strxmov(grantor,thd->user,"@",thd->host ? thd->host : thd->ip ? thd->ip :"",
  1474.       NullS);
  1475.  
  1476.   // The following should always succeed as new users are created before
  1477.   // this function is called!
  1478.   if (!find_acl_user(combo.host.str,combo.user.str))
  1479.   {
  1480.     my_error(ER_PASSWORD_NO_MATCH,MYF(0));    /* purecov: deadcode */
  1481.     DBUG_RETURN(-1);                /* purecov: deadcode */
  1482.   }
  1483.  
  1484.   restore_record(table,2);            // Get empty record
  1485.   table->field[0]->store(combo.host.str,combo.host.length);
  1486.   table->field[1]->store(db,(uint) strlen(db));
  1487.   table->field[2]->store(combo.user.str,combo.user.length);
  1488.   table->field[3]->store(table_name,(uint) strlen(table_name));
  1489.   store_record(table,1);            // store at pos 1
  1490.  
  1491.   if (table->file->index_read_idx(table->record[0],0,
  1492.                   (byte*) table->field[0]->ptr,0,
  1493.                   HA_READ_KEY_EXACT))
  1494.   {
  1495.     /*
  1496.       The following should never happen as we first check the in memory
  1497.       grant tables for the user.  There is however always a small change that
  1498.       the user has modified the grant tables directly.
  1499.     */
  1500.     if (revoke_grant)
  1501.     { // no row, no revoke
  1502.       my_printf_error(ER_NONEXISTING_TABLE_GRANT,
  1503.               ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
  1504.               combo.user.str,combo.host.str,
  1505.               table_name);        /* purecov: deadcode */
  1506.       DBUG_RETURN(-1);                /* purecov: deadcode */
  1507.     }
  1508.     ima = 0;                    // no row
  1509.     restore_record(table,1);            // Get saved record
  1510.   }
  1511.  
  1512.   store_table_rights=get_rights_for_table(rights);
  1513.   store_col_rights=get_rights_for_column(kolone);
  1514.   if (ima)
  1515.   {
  1516.     uint j,k;
  1517.     store_record(table,1);
  1518.     j = (uint) table->field[6]->val_int();
  1519.     k = (uint) table->field[7]->val_int();
  1520.  
  1521.     if (revoke_grant)
  1522.     {
  1523.       // column rights are already fixed in mysql_table_grant !
  1524.       store_table_rights=j & ~store_table_rights;
  1525.     }
  1526.     else
  1527.     {
  1528.       store_table_rights|=j;
  1529.       store_col_rights|=k;
  1530.     }
  1531.   }
  1532.  
  1533.   table->field[4]->store(grantor,(uint) strlen(grantor));
  1534.   table->field[6]->store((longlong) store_table_rights);
  1535.   table->field[7]->store((longlong) store_col_rights);
  1536.   rights=fix_rights_for_table(store_table_rights);
  1537.   kolone=fix_rights_for_column(store_col_rights);
  1538.  
  1539.   if (ima) // there is a row, therefore go update, else insert
  1540.   {
  1541.     if (store_table_rights || store_col_rights)
  1542.     {
  1543.       if ((error=table->file->update_row(table->record[1],table->record[0])))
  1544.     goto table_error;            /* purecov: deadcode */
  1545.     }
  1546.     else if ((error = table->file->delete_row(table->record[1])))
  1547.       goto table_error;                /* purecov: deadcode */
  1548.   }
  1549.   else
  1550.   {
  1551.     error=table->file->write_row(table->record[0]);
  1552.     if (error && error != HA_ERR_FOUND_DUPP_KEY)
  1553.       goto table_error;                /* purecov: deadcode */
  1554.   }
  1555.  
  1556.   if (rights | kolone)
  1557.   {
  1558.     grant_table->privs = rights;
  1559.     grant_table->cols = kolone;
  1560.   }
  1561.   else
  1562.   {
  1563.     hash_delete(&hash_tables,(byte*) grant_table);
  1564.   }
  1565.   DBUG_RETURN(0);
  1566.  
  1567.  /* This should never happen */
  1568.  table_error:
  1569.   table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1570.   DBUG_RETURN(-1); /* purecov: deadcode */
  1571. }
  1572.  
  1573.  
  1574. int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
  1575.                List <LEX_USER> &user_list,
  1576.                List <LEX_COLUMN> &columns, uint rights,
  1577.                bool revoke_grant)
  1578. {
  1579.   uint column_priv = 0;
  1580.   List_iterator <LEX_USER> str_list (user_list);
  1581.   LEX_USER *Str;
  1582.   TABLE_LIST tables[3];
  1583.   DBUG_ENTER("mysql_table_grant");
  1584.  
  1585.   if (!initialized)
  1586.   {
  1587.     send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: inspected */
  1588.     return 1;                    /* purecov: inspected */
  1589.   }
  1590.   if (rights & ~TABLE_ACLS)
  1591.   {
  1592.     my_error(ER_ILLEGAL_GRANT_FOR_TABLE,MYF(0));
  1593.     DBUG_RETURN(-1);
  1594.   }
  1595.  
  1596.   if (columns.elements && !revoke_grant)
  1597.   {
  1598.     TABLE *table;
  1599.     class LEX_COLUMN *check;
  1600.     List_iterator <LEX_COLUMN> iter(columns);
  1601.  
  1602.     if (!(table=open_ltable(thd,table_list,TL_READ)))
  1603.       DBUG_RETURN(-1);
  1604.     while ((check = iter++))
  1605.     {
  1606.       if (!find_field_in_table(thd,table,check->column.ptr(),
  1607.                    check->column.length(),0,0))
  1608.       {
  1609.     my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
  1610.             check->column.c_ptr(),table_list->name);
  1611.     DBUG_RETURN(-1);
  1612.       }
  1613.       column_priv |= check->rights | (rights & COL_ACLS);
  1614.     }
  1615.     close_thread_tables(thd);
  1616.   }
  1617.   else if (!(rights & CREATE_ACL) && !revoke_grant)
  1618.   {
  1619.     char buf[FN_REFLEN];
  1620.     sprintf(buf,"%s/%s/%s.frm",mysql_data_home,table_list->db,
  1621.         table_list->name);
  1622.     fn_format(buf,buf,"","",4+16+32);
  1623.     if (access(buf,F_OK))
  1624.     {
  1625.       my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db,table_list->name);
  1626.       DBUG_RETURN(-1);
  1627.     }
  1628.   }
  1629.  
  1630.   /* open the mysql.tables_priv and mysql.columns_priv tables */
  1631.  
  1632.   bzero((char*) &tables,sizeof(tables));
  1633.   tables[0].name=tables[0].real_name= (char*) "user";
  1634.   tables[1].name=tables[1].real_name= (char*) "tables_priv";
  1635.   tables[2].name=tables[2].real_name= (char*) "columns_priv";
  1636.   tables[0].next=tables+1;
  1637.   /* Don't open column table if we don't need it ! */
  1638.   tables[1].next=((column_priv ||
  1639.            (revoke_grant && ((rights & COL_ACLS) || columns.elements)))
  1640.           ? tables+2 : 0);
  1641.   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
  1642.   tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
  1643.  
  1644.   if (open_and_lock_tables(thd,tables))
  1645.   {                        // Should never happen
  1646.     close_thread_tables(thd);            /* purecov: deadcode */
  1647.     DBUG_RETURN(-1);                /* purecov: deadcode */
  1648.   }
  1649.  
  1650.   int result=0;
  1651.   pthread_mutex_lock(&LOCK_grant);
  1652.   MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
  1653.   my_pthread_setspecific_ptr(THR_MALLOC,&memex);
  1654.  
  1655.   while ((Str = str_list++))
  1656.   {
  1657.     GRANT_TABLE *grant_table;
  1658.     if (!Str->host.str)
  1659.     {
  1660.       Str->host.str=(char*) "%";
  1661.       Str->host.length=1;
  1662.     }
  1663.     if (Str->host.length > HOSTNAME_LENGTH ||
  1664.     Str->user.length > USERNAME_LENGTH)
  1665.     {
  1666.       my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  1667.       result= -1;
  1668.       continue;
  1669.     }
  1670.     /* Create user if needed */
  1671.     if ((replace_user_table(tables[0].table,
  1672.                 *Str,
  1673.                 0,
  1674.                 revoke_grant ? 'N' : 'Y')))
  1675.     {
  1676.       result= -1;                // Remember error
  1677.       continue;                    // Add next user
  1678.     }
  1679.  
  1680.     /* Find/create cached table grant */
  1681.     grant_table= table_hash_search(Str->host.str,NullS,table_list->db,
  1682.                    Str->user.str,
  1683.                    table_list->name,1);
  1684.     if (!grant_table)
  1685.     {
  1686.       if (revoke_grant)
  1687.       {
  1688.     my_printf_error(ER_NONEXISTING_TABLE_GRANT,
  1689.             ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
  1690.             Str->user.str, Str->host.str,table_list->name);
  1691.     result= -1;
  1692.     continue;
  1693.       }
  1694.       grant_table = new GRANT_TABLE (Str->host.str,table_list->db,
  1695.                      Str->user.str,
  1696.                      table_list->name,
  1697.                      rights,
  1698.                      column_priv);
  1699.       if (!grant_table)                // end of memory
  1700.       {
  1701.     result= -1;                /* purecov: deadcode */
  1702.     continue;                /* purecov: deadcode */
  1703.       }
  1704.       hash_insert(&hash_tables,(byte*) grant_table);
  1705.     }
  1706.  
  1707.     /* If revoke_grant, calculate the new column privilege for tables_priv */
  1708.     if (revoke_grant)
  1709.     {
  1710.       class LEX_COLUMN *check;
  1711.       List_iterator <LEX_COLUMN> iter(columns);
  1712.       GRANT_COLUMN *grant_column;
  1713.  
  1714.       /* Fix old grants */
  1715.       while ((check = iter++))
  1716.       {
  1717.     grant_column = column_hash_search(grant_table,
  1718.                       check->column.ptr(),
  1719.                       check->column.length());
  1720.     if (grant_column)
  1721.       grant_column->rights&= ~(check->rights | rights);
  1722.       }
  1723.       /* scan trough all columns to get new column grant */
  1724.       column_priv=0;
  1725.       for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
  1726.       {
  1727.     grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
  1728.                            idx);
  1729.     grant_column->rights&= ~rights;        // Fix other columns
  1730.     column_priv|= grant_column->rights;
  1731.       }
  1732.     }
  1733.     else
  1734.     {
  1735.       column_priv|= grant_table->cols;
  1736.     }
  1737.  
  1738.  
  1739.     /* update table and columns */
  1740.  
  1741.     if (replace_table_table(thd,grant_table,tables[1].table,*Str,
  1742.                 table_list->db,
  1743.                 table_list->name,
  1744.                 rights, column_priv, revoke_grant))
  1745.     {                        // Crashend table ??
  1746.       result= -1;                   /* purecov: deadcode */
  1747.     }
  1748.     else if (tables[2].table)
  1749.     {
  1750.       if ((replace_column_table(grant_table,tables[2].table, *Str,
  1751.                 columns,
  1752.                 table_list->db,
  1753.                 table_list->name,
  1754.                 rights, revoke_grant)))
  1755.       {
  1756.     result= -1;
  1757.       }
  1758.     }
  1759.   }
  1760.   grant_option=TRUE;
  1761.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  1762.   pthread_mutex_unlock(&LOCK_grant);
  1763.   if (!result)
  1764.     send_ok(&thd->net);
  1765.   /* Tables are automaticly closed */
  1766.   DBUG_RETURN(result);
  1767. }
  1768.  
  1769.  
  1770. int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
  1771.          bool revoke_grant)
  1772. {
  1773.   List_iterator <LEX_USER> str_list (list);
  1774.   LEX_USER *Str;
  1775.   char what;
  1776.   TABLE_LIST tables[2];
  1777.   DBUG_ENTER("mysql_grant");
  1778.  
  1779.   if (!initialized)
  1780.   {
  1781.     send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: tested */
  1782.     return 1; /* purecov: tested */
  1783.   }
  1784.  
  1785.   what = (revoke_grant) ? 'N' : 'Y';
  1786.  
  1787.   /* open the mysql.user and mysql.db tables */
  1788.  
  1789.   tables[0].name=tables[0].real_name=(char*) "user";
  1790.   tables[1].name=tables[1].real_name=(char*) "db";
  1791.   tables[0].next=tables+1;
  1792.   tables[1].next=0;
  1793.   tables[0].lock_type=tables[1].lock_type=TL_WRITE;
  1794.   tables[0].db=tables[1].db=(char*) "mysql";
  1795.   tables[0].table=tables[1].table=0;
  1796.   if (open_and_lock_tables(thd,tables))
  1797.   {                        // This should never happen
  1798.     close_thread_tables(thd);            /* purecov: deadcode */
  1799.     DBUG_RETURN(-1);                /* purecov: deadcode */
  1800.   }
  1801.  
  1802.  // go through users in user_list
  1803.  
  1804.   pthread_mutex_lock(&LOCK_grant);
  1805.   VOID(pthread_mutex_lock(&acl_cache->lock));
  1806.   grant_version++;
  1807.  
  1808.   int result=0;
  1809.   while ((Str = str_list++))
  1810.   {
  1811.     if (!Str->host.str)
  1812.     {
  1813.       Str->host.str=(char*) "%";
  1814.       Str->host.length=1;
  1815.     }
  1816.     if (Str->host.length > HOSTNAME_LENGTH ||
  1817.     Str->user.length > USERNAME_LENGTH)
  1818.     {
  1819.       my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  1820.       result= -1;
  1821.       continue;
  1822.     }
  1823.     if ((replace_user_table(tables[0].table,
  1824.                 *Str,
  1825.                 (!db ? rights : 0), what)))
  1826.       result= -1;
  1827.     if (db)
  1828.       if (( replace_db_table(tables[1].table, db, *Str, rights,
  1829.                  what)))
  1830.     result= -1;
  1831.   }
  1832.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  1833.   pthread_mutex_unlock(&LOCK_grant);
  1834.   close_thread_tables(thd);
  1835.  
  1836.   if (!result)
  1837.     send_ok(&thd->net);
  1838.   DBUG_RETURN(result);
  1839. }
  1840.  
  1841.  /* Free grant array if possible */
  1842.  
  1843. void  grant_free(void)
  1844. {
  1845.   DBUG_ENTER("grant_free");
  1846.   grant_option = FALSE;
  1847.   hash_free(&hash_tables);
  1848.   free_root(&memex,MYF(0));
  1849.   DBUG_VOID_RETURN;
  1850. }
  1851.  
  1852.  
  1853. /* Init grant array if possible */
  1854.  
  1855. int  grant_init (void)
  1856. {
  1857.   THD  *thd;
  1858.   TABLE_LIST tables[2];
  1859.   int error = 0;
  1860.   TABLE *t_table, *c_table;
  1861.   DBUG_ENTER("grant_init");
  1862.  
  1863.   grant_option = FALSE;
  1864.   (void) hash_init(&hash_tables,0,0,0, (hash_get_key) get_grant_table,
  1865.            (hash_free_key) free_grant_table,0);
  1866.   init_sql_alloc(&memex,1024,0);
  1867.  
  1868.   if (!initialized)
  1869.     DBUG_RETURN(0);                /* purecov: tested */
  1870.   if (!(thd=new THD))
  1871.     DBUG_RETURN(1);                /* purecov: deadcode */
  1872.  
  1873.   thd->version=refresh_version;
  1874.   thd->mysys_var=my_thread_var;
  1875.   thd->current_tablenr=0;
  1876.   thd->open_tables=0;
  1877.   thd->db=my_strdup("mysql",MYF(0));
  1878.   bzero((char*) &tables,sizeof(tables));
  1879.   tables[0].name=tables[0].real_name= (char*) "tables_priv";
  1880.   tables[1].name=tables[1].real_name= (char*) "columns_priv";
  1881.   tables[0].next=tables+1;
  1882.   tables[0].lock_type=tables[1].lock_type=TL_READ;
  1883.   tables[0].db=tables[1].db=thd->db;
  1884.  
  1885.   if (open_tables(thd,tables))
  1886.   {                        // No grant tables
  1887.     close_thread_tables(thd);            /* purecov: deadcode */
  1888.     delete thd;                    /* purecov: deadcode */
  1889.     DBUG_RETURN(1);                /* purecov: deadcode */
  1890.   }
  1891.   TABLE *ptr[2];                // Lock tables for quick update
  1892.   ptr[0]= tables[0].table;
  1893.   ptr[1]= tables[1].table;
  1894.   MYSQL_LOCK *lock=mysql_lock_tables(thd,ptr,2);
  1895.   if (!lock)
  1896.   {
  1897.     close_thread_tables(thd);            /* purecov: deadcode */
  1898.     delete thd;                    /* purecov: deadcode */
  1899.     DBUG_RETURN(1);                /* purecov: deadcode */
  1900.   }
  1901.  
  1902.   t_table = tables[0].table; c_table = tables[1].table;
  1903.   t_table->file->index_init(0);
  1904.   if (t_table->file->index_first(t_table->record[0]))
  1905.   {
  1906.     t_table->file->index_end();
  1907.     mysql_unlock_tables(thd, lock);
  1908.     thd->version--;                // Force close to free memory
  1909.     close_thread_tables(thd);
  1910.     delete thd;
  1911.     DBUG_RETURN(0);                // Empty table is ok!
  1912.   }
  1913.   grant_option = TRUE;
  1914.   t_table->file->index_end();
  1915.  
  1916.   MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
  1917.   my_pthread_setspecific_ptr(THR_MALLOC,&memex);
  1918.   while (!error)
  1919.   {
  1920.     GRANT_TABLE *mem_check;
  1921.     if (!(mem_check=new GRANT_TABLE(t_table,c_table)) ||
  1922.     mem_check->ok() && hash_insert(&hash_tables,(byte*) mem_check))
  1923.     {
  1924.       /* This could only happen if we are out memory */
  1925.       my_pthread_setspecific_ptr(THR_MALLOC,old_root); /* purecov: deadcode */
  1926.       grant_option = FALSE;            /* purecov: deadcode */
  1927.       mysql_unlock_tables(thd, lock);        /* purecov: deadcode */
  1928.       close_thread_tables(thd);            /* purecov: deadcode */
  1929.       delete thd;                /* purecov: deadcode */
  1930.       DBUG_RETURN(1);                /* purecov: deadcode */
  1931.     }
  1932.     error = t_table->file->index_next(t_table->record[0]);
  1933.   }
  1934.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  1935.   mysql_unlock_tables(thd, lock);
  1936.   thd->version--;                // Force close to free memory
  1937.   close_thread_tables(thd);
  1938.   delete thd;
  1939.   DBUG_RETURN(0);
  1940. }
  1941.  
  1942.  
  1943. /* Reload grant array if possible */
  1944.  
  1945. void grant_reload(void)
  1946. {
  1947.   HASH old_hash_tables;bool old_grant_option;
  1948.   MEM_ROOT old_mem;
  1949.   DBUG_ENTER("grant_reload");
  1950.  
  1951.   // Locked tables are checked by acl_init and doesn't have to be checked here
  1952.  
  1953.   pthread_mutex_lock(&LOCK_grant);
  1954.   grant_version++;
  1955.   old_hash_tables=hash_tables;
  1956.   old_grant_option = grant_option;
  1957.   old_mem = memex;
  1958.  
  1959.   if (grant_init())
  1960.   {                        // Error. Revert to old hash
  1961.     grant_free();                /* purecov: deadcode */
  1962.     hash_tables=old_hash_tables;        /* purecov: deadcode */
  1963.     grant_option = old_grant_option;        /* purecov: deadcode */
  1964.     memex = old_mem;                /* purecov: deadcode */
  1965.   }
  1966.   else
  1967.   {
  1968.     hash_free(&old_hash_tables);
  1969.     free_root(&old_mem,MYF(0));
  1970.   }
  1971.   pthread_mutex_unlock(&LOCK_grant);
  1972.   DBUG_VOID_RETURN;
  1973. }
  1974.  
  1975.  
  1976. /****************************************************************************
  1977. ** Check grants
  1978. ** All errors are written directly to the client if command name is given !
  1979. ****************************************************************************/
  1980.  
  1981. bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
  1982.          uint show_table)
  1983. {
  1984.   TABLE_LIST *table;
  1985.   char *user = thd->priv_user;
  1986.  
  1987.   want_access &= ~thd->master_access;
  1988.   if (!want_access)
  1989.     return 0;                    // ok
  1990.  
  1991.   pthread_mutex_lock(&LOCK_grant);
  1992.   for (table=tables; table ;table=table->next)
  1993.   {
  1994.     if (!(~table->grant.privilege & want_access))
  1995.     {
  1996.       table->grant.want_privilege=0;
  1997.       continue;                    // Already checked
  1998.     }
  1999.     const char *db = table->db ? table->db : thd->db;
  2000.     GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user,
  2001.                          table->real_name,0);
  2002.     if (!grant_table)
  2003.     {
  2004.       want_access &= ~table->grant.privilege;
  2005.       goto err;                    // No grants
  2006.     }
  2007.     if (show_table)
  2008.       continue;                    // We have some priv on this
  2009.  
  2010.     table->grant.grant_table=grant_table;    // Remember for column test
  2011.     table->grant.version=grant_version;
  2012.     table->grant.privilege|= grant_table->privs;
  2013.     table->grant.want_privilege= ((want_access & COL_ACLS)
  2014.                   & ~table->grant.privilege);
  2015.  
  2016.     if (!(~table->grant.privilege & want_access))
  2017.       continue;
  2018.  
  2019.     if (want_access & ~(grant_table->cols | table->grant.privilege))
  2020.     {
  2021.       want_access &= ~(grant_table->cols | table->grant.privilege);
  2022.       goto err;                    // impossible
  2023.     }
  2024.   }
  2025.   pthread_mutex_unlock(&LOCK_grant);
  2026.   return 0;
  2027.  
  2028.  err:
  2029.   pthread_mutex_unlock(&LOCK_grant);
  2030.   if (show_table != 1)                // Not a silent skip of table
  2031.   {
  2032.     const char *command="";
  2033.     if (want_access & SELECT_ACL)
  2034.        command ="select";
  2035.     else if (want_access & INSERT_ACL)
  2036.       command = "insert";
  2037.     else if (want_access & UPDATE_ACL)
  2038.       command = "update";
  2039.     else if (want_access & DELETE_ACL)
  2040.       command = "delete";
  2041.     else if (want_access & DROP_ACL)
  2042.       command = "drop";
  2043.     else if (want_access & CREATE_ACL)
  2044.       command = "create";
  2045.     else if (want_access & ALTER_ACL)
  2046.       command = "alter";
  2047.     else if (want_access & INDEX_ACL)
  2048.       command = "index";
  2049.     else if (want_access & GRANT_ACL)
  2050.       command = "grant";
  2051.     net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR,
  2052.            command,
  2053.            thd->priv_user,
  2054.            thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
  2055.            table ? table->real_name : "unknown");
  2056.   }
  2057.   return 1;
  2058. }
  2059.  
  2060.  
  2061. bool check_grant_column (THD *thd,TABLE *table, const char *name,
  2062.              uint length, uint show_tables)
  2063. {
  2064.   GRANT_TABLE *grant_table;
  2065.   GRANT_COLUMN *grant_column;
  2066.  
  2067.   uint want_access=table->grant.want_privilege;
  2068.   if (!want_access)
  2069.     return 0;                    // Already checked
  2070.  
  2071.   pthread_mutex_lock(&LOCK_grant);
  2072.  
  2073.   // reload table if someone has modified any grants
  2074.  
  2075.   if (table->grant.version != grant_version)
  2076.   {
  2077.     table->grant.grant_table=
  2078.       table_hash_search(thd->host,thd->ip,thd->db,
  2079.             thd->priv_user,
  2080.             table->real_name,0);    /* purecov: inspected */
  2081.     table->grant.version=grant_version;        /* purecov: inspected */
  2082.   }
  2083.   if (!(grant_table=table->grant.grant_table))
  2084.     goto err;                    /* purecov: deadcode */
  2085.  
  2086.   grant_column=column_hash_search(grant_table, name, length);
  2087.   if (grant_column && !(~grant_column->rights & want_access))
  2088.   {
  2089.     pthread_mutex_unlock(&LOCK_grant);
  2090.     return 0;
  2091.   }
  2092. #ifdef NOT_USED
  2093.   if (show_tables && (grant_column || table->grant.privilege & COL_ACLS))
  2094.   {
  2095.     pthread_mutex_unlock(&LOCK_grant);        /* purecov: deadcode */
  2096.     return 0;                    /* purecov: deadcode */
  2097.   }
  2098. #endif
  2099.  
  2100.   /* We must use my_printf_error() here! */
  2101.  err:
  2102.   pthread_mutex_unlock(&LOCK_grant);
  2103.   if (!show_tables)
  2104.   {
  2105.     const char *command="";
  2106.     if (want_access & SELECT_ACL)
  2107.        command ="select";
  2108.     else if (want_access & INSERT_ACL)
  2109.       command = "insert";
  2110.     else if (want_access & UPDATE_ACL)
  2111.       command = "update";
  2112.     my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
  2113.             ER(ER_COLUMNACCESS_DENIED_ERROR),
  2114.             MYF(0),
  2115.             command,
  2116.             thd->priv_user,
  2117.             thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
  2118.             name,
  2119.             table ? table->real_name : "unknown");
  2120.   }
  2121.   return 1;
  2122. }
  2123.  
  2124.  
  2125. bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table)
  2126. {
  2127.   GRANT_TABLE *grant_table;
  2128.   GRANT_COLUMN *grant_column;
  2129.   Field *field=0,**ptr;
  2130.  
  2131.   want_access &= ~table->grant.privilege;
  2132.   if (!want_access)
  2133.     return 0;                    // Already checked
  2134.  
  2135.   pthread_mutex_lock(&LOCK_grant);
  2136.  
  2137.   // reload table if someone has modified any grants
  2138.  
  2139.   if (table->grant.version != grant_version)
  2140.   {
  2141.     table->grant.grant_table=
  2142.       table_hash_search(thd->host,thd->ip,thd->db,
  2143.             thd->priv_user,
  2144.             table->real_name,0);    /* purecov: inspected */
  2145.     table->grant.version=grant_version;        /* purecov: inspected */
  2146.   }
  2147.   // The following should always be true
  2148.   if (!(grant_table=table->grant.grant_table))
  2149.     goto err;                    /* purecov: inspected */
  2150.  
  2151.   for (ptr=table->field; (field= *ptr) ; ptr++)
  2152.   {
  2153.     grant_column=column_hash_search(grant_table, field->field_name,
  2154.                     (uint) strlen(field->field_name));
  2155.     if (!grant_column || (~grant_column->rights & want_access))
  2156.       goto err;
  2157.   }
  2158.   pthread_mutex_unlock(&LOCK_grant);
  2159.   return 0;
  2160.  
  2161.   /* We must use my_printf_error() here! */
  2162.  err:
  2163.   pthread_mutex_unlock(&LOCK_grant);
  2164.  
  2165.   const char *command="";
  2166.   if (want_access & SELECT_ACL)
  2167.     command ="select";
  2168.   else if (want_access & INSERT_ACL)
  2169.     command = "insert";
  2170.   my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
  2171.           ER(ER_COLUMNACCESS_DENIED_ERROR),
  2172.           MYF(0),
  2173.           command,
  2174.           thd->priv_user,
  2175.           thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
  2176.           field ? field->field_name : "unknown",
  2177.           table->real_name);
  2178.   return 1;
  2179. }
  2180.  
  2181.  
  2182. /****************************************************************************
  2183. ** Check if a user has the right to access a database
  2184. ** Access is accepted if he has a grant for any table in the database
  2185. ** Return 1 if access is denied
  2186. ****************************************************************************/
  2187.  
  2188. bool check_grant_db(THD *thd,const char *db)
  2189. {
  2190.   char helping [NAME_LEN+USERNAME_LENGTH+2];
  2191.   uint len;
  2192.   bool error=1;
  2193.  
  2194.   len  = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
  2195.   pthread_mutex_lock(&LOCK_grant);
  2196.  
  2197.   for (uint idx=0 ; idx < hash_tables.records ; idx++)
  2198.   {
  2199.     GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
  2200.     if (len < grant_table->key_length &&
  2201.     !memcmp(grant_table->hash_key,helping,len) &&
  2202.     (thd->host && !wild_case_compare(thd->host,grant_table->host) ||
  2203.      (thd->ip && !wild_case_compare(thd->ip,grant_table->host))))
  2204.     {
  2205.       error=0;                    // Found match
  2206.       break;
  2207.     }
  2208.   }
  2209.   pthread_mutex_unlock(&LOCK_grant);
  2210.   return error;
  2211. }
  2212.  
  2213. /*****************************************************************************
  2214. ** Functions to retrieve the grant for a table/column  (for SHOW functions)
  2215. *****************************************************************************/
  2216.  
  2217. uint get_table_grant(THD *thd, TABLE_LIST *table)
  2218. {
  2219.   char *user = thd->priv_user;
  2220.   const char *db = table->db ? table->db : thd->db;
  2221.   GRANT_TABLE *grant_table;
  2222.  
  2223.   pthread_mutex_lock(&LOCK_grant);
  2224.   grant_table = table_hash_search(thd->host,thd->ip,db,user,
  2225.                        table->real_name,0);
  2226.   table->grant.grant_table=grant_table; // Remember for column test
  2227.   table->grant.version=grant_version;
  2228.   if (grant_table)
  2229.     table->grant.privilege|= grant_table->privs;
  2230.   pthread_mutex_unlock(&LOCK_grant);
  2231.   return table->grant.privilege;
  2232. }
  2233.  
  2234.  
  2235. uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
  2236. {
  2237.   GRANT_TABLE *grant_table;
  2238.   GRANT_COLUMN *grant_column;
  2239.   uint priv;
  2240.  
  2241.   pthread_mutex_lock(&LOCK_grant);
  2242.   // reload table if someone has modified any grants
  2243.   if (table->grant.version != grant_version)
  2244.   {
  2245.     table->grant.grant_table=
  2246.       table_hash_search(thd->host,thd->ip,thd->db,
  2247.             thd->priv_user,
  2248.             table->real_name,0);    /* purecov: inspected */
  2249.     table->grant.version=grant_version;        /* purecov: inspected */
  2250.   }
  2251.  
  2252.   if (!(grant_table=table->grant.grant_table))
  2253.     priv=table->grant.privilege;
  2254.   else
  2255.   {
  2256.     grant_column=column_hash_search(grant_table, field->field_name,
  2257.                     (uint) strlen(field->field_name));
  2258.     if (!grant_column)
  2259.       priv=table->grant.privilege;
  2260.     else
  2261.       priv=table->grant.privilege | grant_column->rights;
  2262.   }
  2263.   pthread_mutex_unlock(&LOCK_grant);
  2264.   return priv;
  2265. }
  2266.  
  2267.  
  2268. /*****************************************************************************
  2269. ** SHOW GRANTS : send to client grant-like strings depicting user@host
  2270. ** privileges
  2271. *****************************************************************************/
  2272.  
  2273. static const char *command_array[]=
  2274. {"SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP","RELOAD","SHUTDOWN",
  2275.  "PROCESS","FILE","GRANT","REFERENCES","INDEX","ALTER"};
  2276. static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,9,5,5};
  2277.  
  2278. int mysql_show_grants(THD *thd,LEX_USER *lex_user) 
  2279. {
  2280.   uint counter, want_access,index;
  2281.   int  error = 0;
  2282.   ACL_USER *acl_user; ACL_DB *acl_db;
  2283.   char buff[1024];
  2284.   DBUG_ENTER("mysql_grant");
  2285.  
  2286.   LINT_INIT(acl_user);
  2287.   if (!initialized)
  2288.   {
  2289.     send_error(&(thd->net), ER_UNKNOWN_COM_ERROR);
  2290.     DBUG_RETURN(-1);
  2291.   }
  2292.   if (!lex_user->host.str)
  2293.   {
  2294.     lex_user->host.str=(char*) "%";
  2295.     lex_user->host.length=1;
  2296.   }
  2297.   if (lex_user->host.length > HOSTNAME_LENGTH ||
  2298.       lex_user->user.length > USERNAME_LENGTH)
  2299.   {
  2300.     my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
  2301.     DBUG_RETURN(-1);
  2302.   }
  2303.  
  2304.   for (counter=0 ; counter < acl_users.elements ; counter++)
  2305.   {
  2306.     const char *user,*host;
  2307.     acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
  2308.     if (!(user=acl_user->user))
  2309.       user="";
  2310.     if (!(host=acl_user->host.hostname))
  2311.       host="%";
  2312.     if (!strcmp(lex_user->user.str,user) &&
  2313.     !strcmp(lex_user->host.str,host))
  2314.       break;
  2315.   }
  2316.   if (counter == acl_users.elements) 
  2317.   {
  2318.     my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
  2319.             MYF(0),lex_user->user.str,lex_user->host.str);
  2320.     DBUG_RETURN(-1);
  2321.   }
  2322.  
  2323.   Item_string *field=new Item_string("",0);
  2324.   List<Item> field_list;
  2325.   field->name=buff;
  2326.   field->max_length=1024;
  2327.   strxmov(buff,"Grants for ",lex_user->user.str,"@",
  2328.       lex_user->host.str,NullS);
  2329.   field_list.push_back(field);
  2330.   if (send_fields(thd,field_list,1))
  2331.     DBUG_RETURN(-1);
  2332.  
  2333.   VOID(pthread_mutex_lock(&acl_cache->lock));
  2334.  
  2335.   /* Add first global access grants */
  2336.   if (acl_user->access || acl_user->password)
  2337.   {
  2338.     want_access=acl_user->access;
  2339.     String global(buff,sizeof(buff));
  2340.     global.length(0);
  2341.     global.append("GRANT ",6);
  2342.  
  2343.     if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
  2344.       global.append("ALL PRIVILEGES",14);
  2345.     else if (!(want_access & ~GRANT_ACL))
  2346.       global.append("USAGE",5);
  2347.     else 
  2348.     {
  2349.       bool found=0;
  2350.       uint j,test_access= want_access & ~GRANT_ACL;
  2351.       for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
  2352.       {
  2353.     if (test_access & j) 
  2354.     {
  2355.       if (found)
  2356.         global.append(", ",2);
  2357.       found=1;
  2358.       global.append(command_array[counter],command_lengths[counter]);
  2359.     }
  2360.       }
  2361.     }
  2362.     global.append (" ON *.* TO '",12);
  2363.     global.append(lex_user->user.str,lex_user->user.length); 
  2364.     global.append ("'@'",3);
  2365.     global.append(lex_user->host.str,lex_user->host.length);
  2366.     global.append ('\'');
  2367.     if (acl_user->password)
  2368.     {
  2369.       char passd_buff[HASH_PASSWORD_LENGTH+1];
  2370.       make_password_from_salt(passd_buff,acl_user->salt);
  2371.       global.append(" IDENTIFIED BY PASSWORD '",25);
  2372.       global.append(passd_buff);
  2373.       global.append('\'');
  2374.     }
  2375.     if (want_access & GRANT_ACL)
  2376.       global.append(" WITH GRANT OPTION",18); 
  2377.     thd->packet.length(0);
  2378.     net_store_data(&thd->packet,global.ptr(),global.length());
  2379.     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
  2380.              thd->packet.length()))
  2381.     {
  2382.       error=-1; goto end;
  2383.     }
  2384.   }
  2385.  
  2386.   /* Add database access */
  2387.   for (counter=0 ; counter < acl_dbs.elements ; counter++)
  2388.   {
  2389.     const char *user,*host;
  2390.  
  2391.     acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  2392.     if (!(user=acl_db->user))
  2393.       user="";
  2394.     if (!(host=acl_db->host.hostname))
  2395.       host="";
  2396.  
  2397.     if (!strcmp(lex_user->user.str,user) &&
  2398.     !strcmp(lex_user->host.str,host))
  2399.     {
  2400.       want_access=acl_db->access;
  2401.       if (want_access) 
  2402.       {
  2403.     String db(buff,sizeof(buff));
  2404.     db.length(0);
  2405.     db.append("GRANT ",6);
  2406.  
  2407.     if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
  2408.       db.append("ALL PRIVILEGES",14);
  2409.     else
  2410.     {
  2411.       int found=0, cnt;
  2412.       uint j,test_access= want_access & ~GRANT_ACL;
  2413.       for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
  2414.       {
  2415.         if (test_access & j)
  2416.         {
  2417.           if (found)
  2418.         db.append(", ",2);
  2419.           found = 1;
  2420.           db.append(command_array[cnt],command_lengths[cnt]);
  2421.         }
  2422.       }
  2423.     }
  2424.     db.append (" ON ",4);
  2425.     db.append(acl_db->db);
  2426.     db.append (".* TO '",7);
  2427.     db.append(lex_user->user.str,lex_user->user.length); 
  2428.     db.append ("'@'",3);
  2429.     db.append(lex_user->host.str, lex_user->host.length);
  2430.     db.append ('\'');    
  2431.     if (want_access & GRANT_ACL)
  2432.       db.append(" WITH GRANT OPTION",18); 
  2433.     thd->packet.length(0);
  2434.     net_store_data(&thd->packet,db.ptr(),db.length());
  2435.     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
  2436.              thd->packet.length()))
  2437.     {
  2438.       error=-1;
  2439.       goto end;
  2440.     }
  2441.       }
  2442.     }
  2443.   }
  2444.  
  2445.   /* Add column access */
  2446.   for (index=0 ; index < hash_tables.records ; index++)
  2447.   {
  2448.     const char *user,*host;
  2449.     GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index); 
  2450.  
  2451.     if (!(user=grant_table->user))
  2452.       user="";
  2453.     if (!(host=grant_table->host))
  2454.       host="";
  2455.  
  2456.     if (!strcmp(lex_user->user.str,user) &&
  2457.     !strcmp(lex_user->host.str,host))
  2458.     {
  2459.       want_access=grant_table->privs;
  2460.       if ((want_access | grant_table->cols) != 0)
  2461.       {
  2462.     String global(buff,sizeof(buff));
  2463.     global.length(0);
  2464.     global.append("GRANT ",6);
  2465.  
  2466.     if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL)))
  2467.       global.append("ALL PRIVILEGES",14);
  2468.     else 
  2469.     {
  2470.       int found=0;
  2471.       uint j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL;
  2472.  
  2473.       for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
  2474.       {
  2475.         if (test_access & j) 
  2476.         {
  2477.           if (found)
  2478.         global.append(", ",2);
  2479.           found = 1;
  2480.           global.append(command_array[counter],command_lengths[counter]);
  2481.  
  2482.           if (grant_table->cols) 
  2483.           {
  2484.         uint found_col=0;
  2485.         for (uint col_index=0 ;
  2486.              col_index < grant_table->hash_columns.records ;
  2487.              col_index++)
  2488.         {
  2489.           GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
  2490.             hash_element(&grant_table->hash_columns,col_index);
  2491.           if (grant_column->rights & j) 
  2492.           {
  2493.             if (!found_col) 
  2494.             {
  2495.               global.append(" (",2);
  2496.               found_col=1;
  2497.             }
  2498.             else
  2499.               global.append(", ",2);
  2500.             global.append(grant_column->column,
  2501.                   grant_column->key_length);
  2502.           }
  2503.         }
  2504.         if (found_col)
  2505.           global.append(')');
  2506.           }
  2507.         }
  2508.       }
  2509.     }
  2510.     global.append(" ON ",4);
  2511.     global.append(grant_table->db);
  2512.     global.append(".",1);
  2513.     global.append(grant_table->tname);
  2514.     global.append(" TO '",5);
  2515.     global.append(lex_user->user.str,lex_user->user.length); 
  2516.     global.append("'@'",3);
  2517.     global.append(lex_user->host.str,lex_user->host.length); 
  2518.     global.append('\'');
  2519.     if (want_access & GRANT_ACL)
  2520.       global.append(" WITH GRANT OPTION",18); 
  2521.     thd->packet.length(0);
  2522.     net_store_data(&thd->packet,global.ptr(),global.length());
  2523.     if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
  2524.              thd->packet.length()))
  2525.     {
  2526.       error=-1;
  2527.       goto end;
  2528.     }
  2529.       }
  2530.     }
  2531.   }
  2532.  end:
  2533.   VOID(pthread_mutex_unlock(&acl_cache->lock));
  2534.   send_eof(&thd->net);
  2535.   DBUG_RETURN(error);
  2536. }
  2537.  
  2538.  
  2539. /*****************************************************************************
  2540. ** Instantiate used templates
  2541. *****************************************************************************/
  2542.  
  2543. #ifdef __GNUC__
  2544. template class List_iterator<LEX_COLUMN>;
  2545. template class List_iterator<LEX_USER>;
  2546. template class List<LEX_COLUMN>;
  2547. template class List<LEX_USER>;
  2548. #endif
  2549.