sql_acl.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:71k
源码类别:

MySQL数据库

开发平台:

Visual C++

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