1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "sql_show.h"                   /* append_identifier */
24 #include "log.h"                        /* sql_print_warning */
25 #include "sql_base.h"                   /* MYSQL_LOCK_IGNORE_TIMEOUT */
26 #include "key.h"                        /* key_copy, key_cmp_if_same */
27                                         /* key_restore */
28 
29 #include "auth_internal.h"
30 #include "sql_auth_cache.h"
31 #include "sql_authentication.h"
32 #include "sql_time.h"
33 #include "my_user.h"                    /* parse_user */
34 #include "password.h"                   /* my_make_scrambled_password_sha1 */
35 #include "sql_plugin.h"                         // lock_plugin_data etc.
36 #include "debug_sync.h"
37 #include "sql_user_table.h"
38 
39 #define INVALID_DATE "0000-00-00 00:00:00"
40 
41 #include <algorithm>
42 #include <functional>
43 using std::min;
44 
45 struct ACL_internal_schema_registry_entry
46 {
47   const LEX_STRING *m_name;
48   const ACL_internal_schema_access *m_access;
49 };
50 /**
51   Internal schema registered.
52   Currently, this is only:
53   - performance_schema
54   - information_schema,
55   This can be reused later for:
56   - mysql
57 */
58 static ACL_internal_schema_registry_entry registry_array[2];
59 static uint m_registry_array_size= 0;
60 
61 #ifndef NO_EMBEDDED_ACCESS_CHECKS
62 MEM_ROOT global_acl_memory;
63 MEM_ROOT memex;
64 Prealloced_array<ACL_USER, ACL_PREALLOC_SIZE> *acl_users= NULL;
65 Prealloced_array<ACL_PROXY_USER, ACL_PREALLOC_SIZE> *acl_proxy_users= NULL;
66 Prealloced_array<ACL_DB, ACL_PREALLOC_SIZE> *acl_dbs= NULL;
67 Prealloced_array<ACL_HOST_AND_IP, ACL_PREALLOC_SIZE> *acl_wild_hosts= NULL;
68 
69 HASH column_priv_hash, proc_priv_hash, func_priv_hash;
70 hash_filo *acl_cache;
71 HASH acl_check_hosts;
72 
73 bool initialized=0;
74 bool allow_all_hosts=1;
75 uint grant_version=0; /* Version of priv tables */
76 my_bool validate_user_plugins= TRUE;
77 /**
78   Flag to track if rwlocks in ACL subsystem were initialized.
79   Necessary because acl_free() can be called in some error scenarios
80   without prior call to acl_init().
81 */
82 bool rwlocks_initialized= false;
83 
84 const uint LOCK_GRANT_PARTITIONS= 32;
85 Partitioned_rwlock LOCK_grant;
86 
87 #define FIRST_NON_YN_FIELD 26
88 
89 #define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
90 #define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
91                         1 + USERNAME_LENGTH + 1)
92 
93 ACL_USER acl_utility_user;
94 static LEX_STRING acl_utility_user_name, acl_utility_user_host_name;
95 static bool acl_utility_user_initialized= false;
96 static std::vector<std::string> acl_utility_user_schema_access;
97 
98 static void acl_free_utility_user();
99 
100 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
101 
102 /**
103   Check if the given host name is equal to "localhost".
104 
105   @return a flag telling if the given host name is equal to "localhost".
106   @retval TRUE the given host name is equal to "localhost".
107   @retval FALSE the given host name is not equal to "localhost".
108 }
109 */
is_localhost_string(const char * hostname)110 static bool is_localhost_string(const char *hostname)
111 {
112   if (!hostname) return false;
113 
114   return !strcmp(hostname, "localhost");
115 }
116 
117 /**
118   Add an internal schema to the registry.
119   @param name the schema name
120   @param access the schema ACL specific rules
121 */
register_schema(const LEX_STRING & name,const ACL_internal_schema_access * access)122 void ACL_internal_schema_registry::register_schema
123   (const LEX_STRING &name, const ACL_internal_schema_access *access)
124 {
125   assert(m_registry_array_size < array_elements(registry_array));
126 
127   /* Not thread safe, and does not need to be. */
128   registry_array[m_registry_array_size].m_name= &name;
129   registry_array[m_registry_array_size].m_access= access;
130   m_registry_array_size++;
131 }
132 
133 
134 /**
135   Search per internal schema ACL by name.
136   @param name a schema name
137   @return per schema rules, or NULL
138 */
139 const ACL_internal_schema_access *
lookup(const char * name)140 ACL_internal_schema_registry::lookup(const char *name)
141 {
142   assert(name != NULL);
143 
144   uint i;
145 
146   for (i= 0; i<m_registry_array_size; i++)
147   {
148     if (my_strcasecmp(system_charset_info, registry_array[i].m_name->str,
149                       name) == 0)
150       return registry_array[i].m_access;
151   }
152   return NULL;
153 }
154 
155 
156 const char *
calc_ip(const char * ip_arg,long * val,char end)157 ACL_HOST_AND_IP::calc_ip(const char *ip_arg, long *val, char end)
158 {
159   long ip_val,tmp;
160   if (!(ip_arg=str2int(ip_arg,10,0,255,&ip_val)) || *ip_arg != '.')
161     return 0;
162   ip_val<<=24;
163   if (!(ip_arg=str2int(ip_arg+1,10,0,255,&tmp)) || *ip_arg != '.')
164     return 0;
165   ip_val+=tmp<<16;
166   if (!(ip_arg=str2int(ip_arg+1,10,0,255,&tmp)) || *ip_arg != '.')
167     return 0;
168   ip_val+=tmp<<8;
169   if (!(ip_arg=str2int(ip_arg+1,10,0,255,&tmp)) || *ip_arg != end)
170     return 0;
171   *val=ip_val+tmp;
172   return ip_arg;
173 }
174 
175 /**
176   @brief Update the hostname. Updates ip and ip_mask accordingly.
177 
178   @param host_arg Value to be stored
179  */
180 void
update_hostname(const char * host_arg)181 ACL_HOST_AND_IP::update_hostname(const char *host_arg)
182 {
183   hostname=(char*) host_arg;     // This will not be modified!
184   hostname_length= hostname ? strlen( hostname ) : 0;
185   if (!host_arg ||
186       (!(host_arg=(char*) calc_ip(host_arg,&ip,'/')) ||
187        !(host_arg=(char*) calc_ip(host_arg+1,&ip_mask,'\0'))))
188   {
189     ip= ip_mask=0;               // Not a masked ip
190   }
191 }
192 
193 /*
194    @brief Comparing of hostnames
195 
196    @param  host_arg    Hostname to be compared with
197    @param  ip_arg      IP address to be compared with
198 
199    @notes
200    A hostname may be of type:
201    1) hostname   (May include wildcards);   monty.pp.sci.fi
202    2) ip     (May include wildcards);   192.168.0.0
203    3) ip/netmask                        192.168.0.0/255.255.255.0
204    A net mask of 0.0.0.0 is not allowed.
205 
206    @return
207    true   if matched
208    false  if not matched
209  */
210 
211 bool
compare_hostname(const char * host_arg,const char * ip_arg)212 ACL_HOST_AND_IP::compare_hostname(const char *host_arg, const char *ip_arg)
213 {
214   long tmp;
215   if (ip_mask && ip_arg && calc_ip(ip_arg,&tmp,'\0'))
216   {
217     return (tmp & ip_mask) == ip;
218   }
219   return (!hostname ||
220       (host_arg &&
221        !wild_case_compare(system_charset_info, host_arg, hostname)) ||
222       (ip_arg && !wild_compare(ip_arg, hostname, 0)));
223 }
224 
225 ACL_USER *
copy(MEM_ROOT * root)226 ACL_USER::copy(MEM_ROOT *root)
227 {
228   ACL_USER *dst= (ACL_USER *) alloc_root(root, sizeof(ACL_USER));
229   if (!dst)
230     return 0;
231   *dst= *this;
232   dst->user= safe_strdup_root(root, user);
233   dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
234   dst->x509_issuer= safe_strdup_root(root, x509_issuer);
235   dst->x509_subject= safe_strdup_root(root, x509_subject);
236   /*
237      If the plugin is built in we don't need to reallocate the name of the
238      plugin.
239    */
240   if (auth_plugin_is_built_in(dst->plugin.str))
241     dst->plugin= plugin;
242   else
243   {
244     dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
245     dst->plugin.length= plugin.length;
246   }
247   dst->auth_string.str= safe_strdup_root(root, auth_string.str);
248   dst->host.update_hostname(host.is_null() ? NULL : strdup_root(root, host.get_host()));
249   return dst;
250 }
251 
252 void
init(const char * host_arg,const char * user_arg,const char * proxied_host_arg,const char * proxied_user_arg,bool with_grant_arg)253 ACL_PROXY_USER::init(const char *host_arg, const char *user_arg,
254                      const char *proxied_host_arg,
255                      const char *proxied_user_arg, bool with_grant_arg)
256 {
257   user= (user_arg && *user_arg) ? user_arg : NULL;
258   host.update_hostname ((host_arg && *host_arg) ? host_arg : NULL);
259   proxied_user= (proxied_user_arg && *proxied_user_arg) ?
260     proxied_user_arg : NULL;
261   proxied_host.update_hostname ((proxied_host_arg && *proxied_host_arg) ?
262       proxied_host_arg : NULL);
263   with_grant= with_grant_arg;
264   sort= get_sort(4, host.get_host(), user,
265       proxied_host.get_host(), proxied_user);
266 }
267 
268 void
init(MEM_ROOT * mem,const char * host_arg,const char * user_arg,const char * proxied_host_arg,const char * proxied_user_arg,bool with_grant_arg)269 ACL_PROXY_USER::init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
270                      const char *proxied_host_arg,
271                      const char *proxied_user_arg, bool with_grant_arg)
272 {
273   init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
274       (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
275       (proxied_host_arg && *proxied_host_arg) ?
276       strdup_root (mem, proxied_host_arg) : NULL,
277       (proxied_user_arg && *proxied_user_arg) ?
278       strdup_root (mem, proxied_user_arg) : NULL,
279       with_grant_arg);
280 }
281 
282 void
init(TABLE * table,MEM_ROOT * mem)283 ACL_PROXY_USER::init(TABLE *table, MEM_ROOT *mem)
284 {
285   init (get_field(mem, table->field[MYSQL_PROXIES_PRIV_HOST]),
286         get_field(mem, table->field[MYSQL_PROXIES_PRIV_USER]),
287         get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]),
288         get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]),
289                   table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->val_int() != 0);
290 }
291 
292 void
check_validity(bool check_no_resolve)293 ACL_PROXY_USER::check_validity(bool check_no_resolve)
294 {
295   if (check_no_resolve &&
296       (hostname_requires_resolving(host.get_host()) ||
297        hostname_requires_resolving(proxied_host.get_host())) &&
298        !is_localhost_string(host.get_host())) {
299     sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
300                       "ignored in --skip-name-resolve mode.",
301                       proxied_user ? proxied_user : "",
302                       proxied_host.get_host(),
303                       user ? user : "",
304                       host.get_host());
305   }
306 }
307 
308 bool
matches(const char * host_arg,const char * user_arg,const char * ip_arg,const char * proxied_user_arg,bool any_proxy_user)309 ACL_PROXY_USER::matches(const char *host_arg, const char *user_arg,
310                         const char *ip_arg, const char *proxied_user_arg,
311 						bool any_proxy_user)
312 {
313   DBUG_ENTER("ACL_PROXY_USER::matches");
314   DBUG_PRINT("info", ("compare_hostname(%s,%s,%s) &&"
315              "compare_hostname(%s,%s,%s) &&"
316              "wild_compare (%s,%s) &&"
317              "wild_compare (%s,%s)",
318              host.get_host(),
319              host_arg ? host_arg : "<NULL>",
320              ip_arg ? ip_arg : "<NULL>",
321              proxied_host.get_host(),
322              host_arg ? host_arg : "<NULL>",
323              ip_arg ? ip_arg : "<NULL>",
324              user_arg ? user_arg : "<NULL>",
325              user ? user : "<NULL>",
326              proxied_user_arg ? proxied_user_arg : "<NULL>",
327              proxied_user ? proxied_user : "<NULL>"));
328   DBUG_RETURN(host.compare_hostname(host_arg, ip_arg) &&
329               proxied_host.compare_hostname(host_arg, ip_arg) &&
330               (!user ||
331                (user_arg && !wild_compare(user_arg, user, TRUE))) &&
332               (any_proxy_user || !proxied_user ||
333                (proxied_user && !wild_compare(proxied_user_arg, proxied_user,
334                                               TRUE))));
335 }
336 
337 bool
pk_equals(ACL_PROXY_USER * grant)338 ACL_PROXY_USER::pk_equals(ACL_PROXY_USER *grant)
339 {
340   DBUG_ENTER("pk_equals");
341   DBUG_PRINT("info", ("strcmp(%s,%s) &&"
342              "strcmp(%s,%s) &&"
343              "wild_compare (%s,%s) &&"
344              "wild_compare (%s,%s)",
345              user ? user : "<NULL>",
346              grant->user ? grant->user : "<NULL>",
347              proxied_user ? proxied_user : "<NULL>",
348              grant->proxied_user ? grant->proxied_user : "<NULL>",
349              host.get_host(),
350              grant->host.get_host(),
351              proxied_host.get_host(),
352              grant->proxied_host.get_host()));
353 
354   DBUG_RETURN(auth_element_equals(user, grant->user) &&
355               auth_element_equals(proxied_user, grant->proxied_user) &&
356               auth_element_equals(host.get_host(), grant->host.get_host()) &&
357               auth_element_equals(proxied_host.get_host(),
358                                   grant->proxied_host.get_host()));
359 }
360 
361 void
print_grant(THD * thd,String * str)362 ACL_PROXY_USER::print_grant(THD *thd, String *str)
363 {
364   str->append(STRING_WITH_LEN("GRANT PROXY ON "));
365   String proxied_user_str(proxied_user, get_proxied_user_length(),
366                           system_charset_info);
367   append_query_string(thd, system_charset_info, &proxied_user_str, str);
368   str->append(STRING_WITH_LEN("@"));
369   String proxied_host_str(proxied_host.get_host(), proxied_host.get_host_len(),
370                           system_charset_info);
371   append_query_string(thd, system_charset_info, &proxied_host_str, str);
372   str->append(STRING_WITH_LEN(" TO "));
373   String user_str(user, get_user_length(), system_charset_info);
374   append_query_string(thd, system_charset_info, &user_str, str);
375   str->append(STRING_WITH_LEN("@"));
376   String host_str(host.get_host(), host.get_host_len(), system_charset_info);
377   append_query_string(thd, system_charset_info, &host_str, str);
378   if (with_grant)
379     str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
380 }
381 
382 int
store_pk(TABLE * table,const LEX_CSTRING & host,const LEX_CSTRING & user,const LEX_CSTRING & proxied_host,const LEX_CSTRING & proxied_user)383 ACL_PROXY_USER::store_pk(TABLE *table,
384                          const LEX_CSTRING &host,
385                          const LEX_CSTRING &user,
386                          const LEX_CSTRING &proxied_host,
387                          const LEX_CSTRING &proxied_user)
388 {
389   DBUG_ENTER("ACL_PROXY_USER::store_pk");
390   DBUG_PRINT("info", ("host=%s, user=%s, proxied_host=%s, proxied_user=%s",
391                       host.str ? host.str : "<NULL>",
392                       user.str ? user.str : "<NULL>",
393                       proxied_host.str ? proxied_host.str : "<NULL>",
394                       proxied_user.str ? proxied_user.str : "<NULL>"));
395   if (table->field[MYSQL_PROXIES_PRIV_HOST]->store(host.str,
396                                                    host.length,
397                                                    system_charset_info))
398     DBUG_RETURN(TRUE);
399   if (table->field[MYSQL_PROXIES_PRIV_USER]->store(user.str,
400                                                    user.length,
401                                                    system_charset_info))
402     DBUG_RETURN(TRUE);
403   if (table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]->store(proxied_host.str,
404                                                            proxied_host.length,
405                                                            system_charset_info))
406     DBUG_RETURN(TRUE);
407   if (table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]->store(proxied_user.str,
408                                                            proxied_user.length,
409                                                            system_charset_info))
410     DBUG_RETURN(TRUE);
411 
412   DBUG_RETURN(FALSE);
413 }
414 
415 int
store_with_grant(TABLE * table,bool with_grant)416 ACL_PROXY_USER::store_with_grant(TABLE * table,
417                                  bool with_grant)
418 {
419   DBUG_ENTER("ACL_PROXY_USER::store_with_grant");
420   DBUG_PRINT("info", ("with_grant=%s", with_grant ? "TRUE" : "FALSE"));
421   if (table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->store(with_grant ? 1 : 0,
422                                                          TRUE))
423     DBUG_RETURN(TRUE);
424 
425   DBUG_RETURN(FALSE);
426 }
427 
428 int
store_data_record(TABLE * table,const LEX_CSTRING & host,const LEX_CSTRING & user,const LEX_CSTRING & proxied_host,const LEX_CSTRING & proxied_user,bool with_grant,const char * grantor)429 ACL_PROXY_USER::store_data_record(TABLE *table,
430                                   const LEX_CSTRING &host,
431                                   const LEX_CSTRING &user,
432                                   const LEX_CSTRING &proxied_host,
433                                   const LEX_CSTRING &proxied_user,
434                                   bool with_grant,
435                                   const char *grantor)
436 {
437   DBUG_ENTER("ACL_PROXY_USER::store_pk");
438   if (store_pk(table,  host, user, proxied_host, proxied_user))
439     DBUG_RETURN(TRUE);
440   if (store_with_grant(table, with_grant))
441     DBUG_RETURN(TRUE);
442   if (table->field[MYSQL_PROXIES_PRIV_GRANTOR]->store(grantor,
443                                                       strlen(grantor),
444                                                       system_charset_info))
445     DBUG_RETURN(TRUE);
446 
447   DBUG_RETURN(FALSE);
448 }
449 
450 
wild_case_compare(CHARSET_INFO * cs,const char * str,const char * wildstr)451 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
452 {
453   int flag;
454   DBUG_ENTER("wild_case_compare");
455   DBUG_PRINT("enter",("str: '%s'  wildstr: '%s'",str,wildstr));
456   while (*wildstr)
457   {
458     while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
459     {
460       if (*wildstr == wild_prefix && wildstr[1])
461         wildstr++;
462       if (my_toupper(cs, *wildstr++) !=
463           my_toupper(cs, *str++)) DBUG_RETURN(1);
464     }
465     if (! *wildstr ) DBUG_RETURN (*str != 0);
466     if (*wildstr++ == wild_one)
467     {
468       if (! *str++) DBUG_RETURN (1);    /* One char; skip */
469     }
470     else
471     {                                           /* Found '*' */
472       if (!*wildstr) DBUG_RETURN(0);            /* '*' as last char: OK */
473       flag=(*wildstr != wild_many && *wildstr != wild_one);
474       do
475       {
476         if (flag)
477         {
478           char cmp;
479           if ((cmp= *wildstr) == wild_prefix && wildstr[1])
480             cmp=wildstr[1];
481           cmp=my_toupper(cs, cmp);
482           while (*str && my_toupper(cs, *str) != cmp)
483             str++;
484           if (!*str) DBUG_RETURN (1);
485         }
486         if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
487       } while (*str++);
488       DBUG_RETURN(1);
489     }
490   }
491   DBUG_RETURN (*str != '\0');
492 }
493 
494 
495 /*
496   Return a number which, if sorted 'desc', puts strings in this order:
497     no wildcards
498     strings containg wildcards and non-wildcard characters
499     single muilt-wildcard character('%')
500     empty string
501 */
502 
get_sort(uint count,...)503 ulong get_sort(uint count,...)
504 {
505   va_list args;
506   va_start(args,count);
507   ulong sort=0;
508 
509   /* Should not use this function with more than 4 arguments for compare. */
510   assert(count <= 4);
511 
512   while (count--)
513   {
514     char *start, *str= va_arg(args,char*);
515     uint chars= 0;
516     uint wild_pos= 0;
517 
518     /*
519       wild_pos
520         0                            if string is empty
521         1                            if string is a single muilt-wildcard
522                                      character('%')
523         first wildcard position + 1  if string containg wildcards and
524                                      non-wildcard characters
525     */
526 
527     if ((start= str))
528     {
529       for (; *str ; str++)
530       {
531         if (*str == wild_prefix && str[1])
532           str++;
533         else if (*str == wild_many || *str == wild_one)
534         {
535           wild_pos= (uint) (str - start) + 1;
536           if (!(wild_pos == 1 && *str == wild_many && *(++str) == '\0'))
537             wild_pos++;
538           break;
539         }
540         chars= 128;                             // Marker that chars existed
541       }
542     }
543     sort= (sort << 8) + (wild_pos ? min(wild_pos, 127U) : chars);
544   }
545   va_end(args);
546   return sort;
547 }
548 
549 
550 /**
551   Check if the given host name needs to be resolved or not.
552   Host name has to be resolved if it actually contains *name*.
553 
554   For example:
555     192.168.1.1               --> FALSE
556     192.168.1.0/255.255.255.0 --> FALSE
557     %                         --> FALSE
558     192.168.1.%               --> FALSE
559     AB%                       --> FALSE
560 
561     AAAAFFFF                  --> TRUE (Hostname)
562     AAAA:FFFF:1234:5678       --> FALSE
563     ::1                       --> FALSE
564 
565   This function does not check if the given string is a valid host name or
566   not. It assumes that the argument is a valid host name.
567 
568   @param hostname   the string to check.
569 
570   @return a flag telling if the argument needs to be resolved or not.
571   @retval TRUE the argument is a host name and needs to be resolved.
572   @retval FALSE the argument is either an IP address, or a patter and
573           should not be resolved.
574 */
575 
hostname_requires_resolving(const char * hostname)576 bool hostname_requires_resolving(const char *hostname)
577 {
578 
579   /* called only for --skip-name-resolve */
580   assert(specialflag & SPECIAL_NO_RESOLVE);
581 
582   if (!hostname)
583     return FALSE;
584 
585   /*
586     If the string contains any of {':', '%', '_', '/'}, it is definitely
587     not a host name:
588       - ':' means that the string is an IPv6 address;
589       - '%' or '_' means that the string is a pattern;
590       - '/' means that the string is an IPv4 network address;
591   */
592 
593   for (const char *p= hostname; *p; ++p)
594   {
595     switch (*p) {
596       case ':':
597       case '%':
598       case '_':
599       case '/':
600         return FALSE;
601     }
602   }
603 
604   /*
605     Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
606     (12.34.56.78). The assumption is that if the string contains only
607     digits and dots, it is an IPv4 address. Otherwise -- a host name.
608   */
609 
610   for (const char *p= hostname; *p; ++p)
611   {
612     if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
613       return TRUE; /* a "letter" has been found. */
614   }
615 
616   return FALSE; /* all characters are either dots or digits. */
617 }
618 
619 
620 #ifndef NO_EMBEDDED_ACCESS_CHECKS
621 
622 
get_key_column(GRANT_COLUMN * buff,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))623 static uchar* get_key_column(GRANT_COLUMN *buff, size_t *length,
624                              my_bool not_used MY_ATTRIBUTE((unused)))
625 {
626   *length=buff->key_length;
627   return (uchar*) buff->column;
628 }
629 
630 
get_grant_table(GRANT_NAME * buff,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))631 uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
632                        my_bool not_used MY_ATTRIBUTE((unused)))
633 {
634   *length=buff->key_length;
635   return (uchar*) buff->hash_key;
636 }
637 
638 
GRANT_COLUMN(String & c,ulong y)639 GRANT_COLUMN::GRANT_COLUMN(String &c,  ulong y) :rights (y)
640 {
641   column= (char*) memdup_root(&memex,c.ptr(), key_length=c.length());
642 }
643 
644 
set_user_details(const char * h,const char * d,const char * u,const char * t,bool is_routine)645 void GRANT_NAME::set_user_details(const char *h, const char *d,
646                                   const char *u, const char *t,
647                                   bool is_routine)
648 {
649   /* Host given by user */
650   host.update_hostname(strdup_root(&memex, h));
651   if (db != d)
652   {
653     db= strdup_root(&memex, d);
654     if (lower_case_table_names)
655       my_casedn_str(files_charset_info, db);
656   }
657   user = strdup_root(&memex,u);
658   sort=  get_sort(3,host.get_host(),db,user);
659   if (tname != t)
660   {
661     tname= strdup_root(&memex, t);
662     if (lower_case_table_names || is_routine)
663       my_casedn_str(files_charset_info, tname);
664   }
665   key_length= strlen(d) + strlen(u)+ strlen(t)+3;
666   hash_key=   (char*) alloc_root(&memex,key_length);
667   my_stpcpy(my_stpcpy(my_stpcpy(hash_key,user)+1,db)+1,tname);
668 }
669 
GRANT_NAME(const char * h,const char * d,const char * u,const char * t,ulong p,bool is_routine)670 GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
671                        const char *t, ulong p, bool is_routine)
672   :db(0), tname(0), privs(p)
673 {
674   set_user_details(h, d, u, t, is_routine);
675 }
676 
GRANT_TABLE(const char * h,const char * d,const char * u,const char * t,ulong p,ulong c)677 GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
678                          const char *t, ulong p, ulong c)
679   :GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
680 {
681   (void) my_hash_init2(&hash_columns,4,system_charset_info,
682                    0,0,0, (my_hash_get_key) get_key_column,0,0,
683                    key_memory_acl_memex);
684 }
685 
686 
GRANT_NAME(TABLE * form,bool is_routine)687 GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
688 {
689   host.update_hostname(get_field(&memex, form->field[0]));
690   db=    get_field(&memex,form->field[1]);
691   user=  get_field(&memex,form->field[2]);
692   if (!user)
693     user= (char*) "";
694   sort=  get_sort(3, host.get_host(), db, user);
695   tname= get_field(&memex,form->field[3]);
696   if (!db || !tname) {
697     /* Wrong table row; Ignore it */
698     privs= 0;
699     return;                                     /* purecov: inspected */
700   }
701   if (lower_case_table_names)
702   {
703     my_casedn_str(files_charset_info, db);
704   }
705   if (lower_case_table_names || is_routine)
706   {
707     my_casedn_str(files_charset_info, tname);
708   }
709   key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
710   hash_key=   (char*) alloc_root(&memex, key_length);
711   my_stpcpy(my_stpcpy(my_stpcpy(hash_key,user)+1,db)+1,tname);
712 
713   if (form->field[MYSQL_TABLES_PRIV_FIELD_TABLE_PRIV])
714   {
715     privs = (ulong) form->field[MYSQL_TABLES_PRIV_FIELD_TABLE_PRIV]->val_int();
716     privs = fix_rights_for_table(privs);
717   }
718 }
719 
720 
GRANT_TABLE(TABLE * form)721 GRANT_TABLE::GRANT_TABLE(TABLE *form)
722   :GRANT_NAME(form, false)
723 {
724   if (!db || !tname)
725   {
726     /* Wrong table row; Ignore it */
727     my_hash_clear(&hash_columns);               /* allow for destruction */
728     cols= 0;
729     return;
730   }
731 
732   if (form->field[MYSQL_TABLES_PRIV_FIELD_COLUMN_PRIV])
733   {
734     cols= (ulong) form->field[MYSQL_TABLES_PRIV_FIELD_COLUMN_PRIV]->val_int();
735     cols =  fix_rights_for_column(cols);
736   }
737   else
738     cols= 0;
739 
740   (void) my_hash_init2(&hash_columns,4,system_charset_info,
741                    0,0,0, (my_hash_get_key) get_key_column,0,0,
742                    key_memory_acl_memex);
743 }
744 
745 
~GRANT_TABLE()746 GRANT_TABLE::~GRANT_TABLE()
747 {
748   my_hash_free(&hash_columns);
749 }
750 
751 
init(TABLE * col_privs)752 bool GRANT_TABLE::init(TABLE *col_privs)
753 {
754   int error;
755 
756   if (cols)
757   {
758     uchar key[MAX_KEY_LENGTH];
759     uint key_prefix_len;
760 
761     if (!col_privs->key_info)
762     {
763       my_error(ER_MISSING_KEY, MYF(0), col_privs->s->db.str,
764                col_privs->s->table_name.str);
765       return true;
766     }
767 
768     KEY_PART_INFO *key_part= col_privs->key_info->key_part;
769     col_privs->field[0]->store(host.get_host(),
770                                host.get_host_len(),
771                                system_charset_info);
772     col_privs->field[1]->store(db, strlen(db), system_charset_info);
773     col_privs->field[2]->store(user, strlen(user), system_charset_info);
774     col_privs->field[3]->store(tname, strlen(tname), system_charset_info);
775 
776     key_prefix_len= (key_part[0].store_length +
777                      key_part[1].store_length +
778                      key_part[2].store_length +
779                      key_part[3].store_length);
780     key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len);
781     col_privs->field[4]->store("", 0, &my_charset_latin1);
782 
783     error= col_privs->file->ha_index_init(0, 1);
784     if (error)
785     {
786       acl_print_ha_error(col_privs, error);
787       return true;
788     }
789 
790     error=
791       col_privs->file->ha_index_read_map(col_privs->record[0], (uchar*) key,
792                                          (key_part_map)15, HA_READ_KEY_EXACT);
793     DBUG_EXECUTE_IF("se_error_grant_table_init_read",
794                     error= HA_ERR_LOCK_WAIT_TIMEOUT;);
795     if (error)
796     {
797       bool ret= false;
798       cols= 0;
799       if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
800       {
801         acl_print_ha_error(col_privs, error);
802         ret= true;
803       }
804       col_privs->file->ha_index_end();
805       return ret;
806     }
807 
808     do
809     {
810       String *res,column_name;
811       GRANT_COLUMN *mem_check;
812       /* As column name is a string, we don't have to supply a buffer */
813       res= col_privs->field[4]->val_str(&column_name);
814       ulong priv= (ulong) col_privs->field[6]->val_int();
815       if (!(mem_check= new GRANT_COLUMN(*res,
816                                         fix_rights_for_column(priv))) ||
817             my_hash_insert(&hash_columns, (uchar *) mem_check))
818       {
819         /* Don't use this entry */
820         col_privs->file->ha_index_end();
821         return true;
822       }
823 
824       error= col_privs->file->ha_index_next(col_privs->record[0]);
825       DBUG_EXECUTE_IF("se_error_grant_table_init_read_next",
826                       error= HA_ERR_LOCK_WAIT_TIMEOUT;);
827       if (error && error != HA_ERR_END_OF_FILE)
828       {
829         acl_print_ha_error(col_privs, error);
830         col_privs->file->ha_index_end();
831         return true;
832       }
833     }
834     while (!error && !key_cmp_if_same(col_privs,key,0,key_prefix_len));
835     col_privs->file->ha_index_end();
836   }
837 
838   return false;
839 }
840 
841 /*
842   Find first entry that matches the current user
843 */
844 
845 ACL_USER *
find_acl_user(const char * host,const char * user,my_bool exact)846 find_acl_user(const char *host, const char *user, my_bool exact)
847 {
848   DBUG_ENTER("find_acl_user");
849   DBUG_PRINT("enter",("host: '%s'  user: '%s'",host,user));
850 
851   mysql_mutex_assert_owner(&acl_cache->lock);
852 
853   if (likely(acl_users))
854   {
855     for (ACL_USER *acl_user= acl_users->begin();
856          acl_user != acl_users->end(); ++acl_user)
857     {
858       DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
859                          user, acl_user->user ? acl_user->user : "",
860                          host,
861                          acl_user->host.get_host()));
862       if ((!acl_user->user && !user[0]) ||
863           (acl_user->user && !strcmp(user,acl_user->user)))
864       {
865         if (exact ? !my_strcasecmp(system_charset_info, host,
866                                    acl_user->host.get_host()) :
867             acl_user->host.compare_hostname(host,host))
868         {
869           DBUG_RETURN(acl_user);
870         }
871       }
872     }
873   }
874   DBUG_RETURN(0);
875 }
876 
877 
878 /*
879   Find user in ACL
880 
881   SYNOPSIS
882     is_acl_user()
883     host                 host name
884     user                 user name
885 
886   RETURN
887    FALSE  user not fond
888    TRUE   there are such user
889 */
890 
is_acl_user(const char * host,const char * user)891 bool is_acl_user(const char *host, const char *user)
892 {
893   bool res;
894 
895   /* --skip-grants */
896   if (!initialized)
897     return TRUE;
898 
899   mysql_mutex_lock(&acl_cache->lock);
900   res= find_acl_user(host, user, TRUE) != NULL;
901   mysql_mutex_unlock(&acl_cache->lock);
902   return res;
903 }
904 
905 
906 /**
907   Validate if a user can proxy as another user
908 
909   @thd                     current thread
910   @param user              the logged in user (proxy user)
911   @param authenticated_as  the effective user a plugin is trying to
912                            impersonate as (proxied user)
913   @return                  proxy user definition
914     @retval NULL           proxy user definition not found or not applicable
915     @retval non-null       the proxy user data
916 */
917 
918 ACL_PROXY_USER *
acl_find_proxy_user(const char * user,const char * host,const char * ip,char * authenticated_as,bool * proxy_used)919 acl_find_proxy_user(const char *user, const char *host, const char *ip,
920                     char *authenticated_as, bool *proxy_used)
921 {
922   /* if the proxied and proxy user are the same return OK */
923   DBUG_ENTER("acl_find_proxy_user");
924   DBUG_PRINT("info", ("user=%s host=%s ip=%s authenticated_as=%s",
925                       user, host, ip, authenticated_as));
926 
927   if (!strcmp(authenticated_as, user))
928   {
929     DBUG_PRINT ("info", ("user is the same as authenticated_as"));
930     DBUG_RETURN (NULL);
931   }
932 
933   bool find_any = check_proxy_users && !*authenticated_as;
934 
935   if(!find_any)
936     *proxy_used= TRUE;
937   for (ACL_PROXY_USER *proxy= acl_proxy_users->begin();
938        proxy != acl_proxy_users->end(); ++proxy)
939   {
940 	if (proxy->matches(host, user, ip, authenticated_as, find_any))
941 	{
942       DBUG_PRINT("info", ("proxy matched=%s@%s",
943 		proxy->get_proxied_user(),
944 		proxy->get_proxied_host()));
945       if (!find_any)
946 	  {
947         DBUG_PRINT("info", ("returning specific match as authenticated_as was specified"));
948         *proxy_used = TRUE;
949         DBUG_RETURN(proxy);
950       }
951       else
952       {
953         // we never use anonymous users when mapping
954         // proxy users for internal plugins:
955         if (strcmp(proxy->get_proxied_user() ?
956           proxy->get_proxied_user() : "", ""))
957         {
958           if (find_acl_user(
959             proxy->get_proxied_host(),
960             proxy->get_proxied_user(),
961             TRUE))
962           {
963             DBUG_PRINT("info", ("setting proxy_used to true, as \
964               find_all search matched real user=%s host=%s",
965               proxy->get_proxied_user(),
966               proxy->get_proxied_host()));
967             *proxy_used = TRUE;
968             strcpy(authenticated_as, proxy->get_proxied_user());
969           }
970           else
971           {
972             DBUG_PRINT("info", ("skipping match because ACL user \
973               does not exist, looking for next match to map"));
974           }
975           if (*proxy_used)
976           {
977             DBUG_PRINT("info", ("returning matching user"));
978             DBUG_RETURN(proxy);
979           }
980         }
981       }
982 	}
983   }
984   DBUG_PRINT("info", ("No matching users found, returning null"));
985   DBUG_RETURN(NULL);
986 }
987 
988 
acl_entry_get_key(acl_entry * entry,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))989 static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
990                                 my_bool not_used MY_ATTRIBUTE((unused)))
991 {
992   *length=(uint) entry->length;
993   return (uchar*) entry->key;
994 }
995 
996 
check_get_key(ACL_USER * buff,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))997 static uchar* check_get_key(ACL_USER *buff, size_t *length,
998                             my_bool not_used MY_ATTRIBUTE((unused)))
999 {
1000   *length=buff->host.get_host_len();
1001   return (uchar*) buff->host.get_host();
1002 }
1003 
1004 
1005 /*
1006   Get privilege for a host, user and db combination
1007 
1008   as db_is_pattern changes the semantics of comparison,
1009   acl_cache is not used if db_is_pattern is set.
1010 */
1011 
acl_get(const char * host,const char * ip,const char * user,const char * db,my_bool db_is_pattern)1012 ulong acl_get(const char *host, const char *ip,
1013               const char *user, const char *db, my_bool db_is_pattern)
1014 {
1015   ulong host_access= ~(ulong)0, db_access= 0;
1016   size_t key_length, copy_length;
1017   char key[ACL_KEY_LENGTH],*tmp_db,*end;
1018   acl_entry *entry;
1019   DBUG_ENTER("acl_get");
1020 
1021   copy_length= (strlen(ip ? ip : "") +
1022                 strlen(user ? user : "") +
1023                 strlen(db ? db : "")) + 2; /* Added 2 at the end to avoid
1024                                               buffer overflow at strmov()*/
1025   /*
1026     Make sure that my_stpcpy() operations do not result in buffer overflow.
1027   */
1028   if (copy_length >= ACL_KEY_LENGTH)
1029     DBUG_RETURN(0);
1030 
1031   mysql_mutex_lock(&acl_cache->lock);
1032   end=my_stpcpy((tmp_db=my_stpcpy(my_stpcpy(key, ip ? ip : "")+1,user)+1),db);
1033   if (lower_case_table_names)
1034   {
1035     my_casedn_str(files_charset_info, tmp_db);
1036     db=tmp_db;
1037   }
1038   key_length= (size_t) (end-key);
1039   if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
1040                                                               key_length)))
1041   {
1042     db_access=entry->access;
1043     mysql_mutex_unlock(&acl_cache->lock);
1044     DBUG_PRINT("exit", ("access: 0x%lx", db_access));
1045     DBUG_RETURN(db_access);
1046   }
1047 
1048   /* Check to see if the inquiry is for the utility_user */
1049   if (acl_is_utility_user(user, host, ip))
1050   {
1051     /* Check to see if database is within the schema access list */
1052     std::vector<std::string>::const_iterator it=
1053       std::find(acl_utility_user_schema_access.begin(),
1054                 acl_utility_user_schema_access.end(), db);
1055     if (it != acl_utility_user_schema_access.end())
1056       db_access= host_access= GLOBAL_ACLS;
1057     goto exit;
1058   }
1059 
1060   /*
1061     Check if there are some access rights for database and user
1062   */
1063   for (ACL_DB *acl_db= acl_dbs->begin(); acl_db != acl_dbs->end(); ++acl_db)
1064   {
1065     if (!acl_db->user || !strcmp(user,acl_db->user))
1066     {
1067       if (acl_db->host.compare_hostname(host,ip))
1068       {
1069         if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
1070         {
1071           db_access=acl_db->access;
1072           if (!acl_db->host.is_null())
1073             goto exit;                          // Fully specified. Take it
1074           break; /* purecov: tested */
1075         }
1076       }
1077     }
1078   }
1079   if (!db_access)
1080     goto exit;                                  // Can't be better
1081 
1082 exit:
1083   /* Save entry in cache for quick retrieval */
1084   if (!db_is_pattern &&
1085       (entry= (acl_entry*) my_malloc(key_memory_acl_cache,
1086                                      sizeof(acl_entry)+key_length,
1087                                      MYF(0))))
1088   {
1089     entry->access=(db_access & host_access);
1090     entry->length=key_length;
1091     memcpy((uchar*) entry->key,key,key_length);
1092     acl_cache->add(entry);
1093   }
1094   mysql_mutex_unlock(&acl_cache->lock);
1095   DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
1096   DBUG_RETURN(db_access & host_access);
1097 }
1098 
1099 
1100 /**
1101   Check if the user is allowed to change password
1102 
1103  @param thd THD
1104  @param host Hostname for the user
1105  @param user User name
1106  @param new_password new password
1107 
1108  new_password cannot be NULL
1109 
1110  @return Error status
1111    @retval 0 OK
1112    @retval 1 ERROR; In this case the error is sent to the client.
1113 */
1114 
1115 /*
1116   Check if there are any possible matching entries for this host
1117 
1118   NOTES
1119     All host names without wild cards are stored in a hash table,
1120     entries with wildcards are stored in a dynamic array
1121 */
1122 
init_check_host(void)1123 static void init_check_host(void)
1124 {
1125   DBUG_ENTER("init_check_host");
1126   if (acl_wild_hosts != NULL)
1127     acl_wild_hosts->clear();
1128   else
1129     acl_wild_hosts=
1130       new Prealloced_array<ACL_HOST_AND_IP, ACL_PREALLOC_SIZE>(key_memory_acl_mem);
1131 
1132   size_t acl_users_size= acl_users ? acl_users->size() : 0;
1133 
1134   (void) my_hash_init(&acl_check_hosts,system_charset_info,
1135                       acl_users_size, 0, 0,
1136                       (my_hash_get_key) check_get_key, 0, 0,
1137                       key_memory_acl_mem);
1138   if (acl_users_size && !allow_all_hosts)
1139   {
1140     for (ACL_USER *acl_user= acl_users->begin();
1141          acl_user != acl_users->end(); ++acl_user)
1142     {
1143       if (acl_user->host.has_wildcard())
1144       {                                         // Has wildcard
1145         ACL_HOST_AND_IP *acl= NULL;
1146         for (acl= acl_wild_hosts->begin(); acl != acl_wild_hosts->end(); ++acl)
1147         {                                       // Check if host already exists
1148           if (!my_strcasecmp(system_charset_info,
1149                              acl_user->host.get_host(), acl->get_host()))
1150             break;                              // already stored
1151         }
1152         if (acl == acl_wild_hosts->end())       // If new
1153           acl_wild_hosts->push_back(acl_user->host);
1154       }
1155       else if (!my_hash_search(&acl_check_hosts,(uchar*)
1156                                acl_user->host.get_host(),
1157                                acl_user->host.get_host_len()))
1158       {
1159         if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
1160         {                                       // End of memory
1161           allow_all_hosts=1;                    // Should never happen
1162           DBUG_VOID_RETURN;
1163         }
1164       }
1165     }
1166   }
1167   acl_wild_hosts->shrink_to_fit();
1168   freeze_size(&acl_check_hosts.array);
1169   DBUG_VOID_RETURN;
1170 }
1171 
1172 
1173 /*
1174   Rebuild lists used for checking of allowed hosts
1175 
1176   We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
1177   dropping or renaming user, since they contain pointers to elements of
1178   'acl_user' array, which are invalidated by drop operation, and use
1179   ACL_USER::host::hostname as a key, which is changed by rename.
1180 */
rebuild_check_host(void)1181 void rebuild_check_host(void)
1182 {
1183   delete acl_wild_hosts;
1184   acl_wild_hosts= NULL;
1185   my_hash_free(&acl_check_hosts);
1186   init_check_host();
1187 }
1188 
1189 
1190 /*
1191   Gets user credentials without authentication and resource limit checks.
1192 
1193   SYNOPSIS
1194     acl_getroot()
1195       sctx               Context which should be initialized
1196       user               user name
1197       host               host name
1198       ip                 IP
1199       db                 current data base name
1200 
1201   RETURN
1202     FALSE  OK
1203     TRUE   Error
1204 */
1205 
acl_getroot(Security_context * sctx,char * user,char * host,char * ip,const char * db)1206 bool acl_getroot(Security_context *sctx, char *user, char *host,
1207                  char *ip, const char *db)
1208 {
1209   int res= 1;
1210   ACL_USER *acl_user= 0;
1211   DBUG_ENTER("acl_getroot");
1212 
1213   DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
1214                        (host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
1215                        user, (db ? db : "(NULL)")));
1216   sctx->set_user_ptr(user, user ? strlen(user) : 0);
1217   sctx->set_host_ptr(host, host ? strlen(host) : 0);
1218   sctx->set_ip_ptr(ip, ip? strlen(ip) : 0);
1219   sctx->set_host_or_ip_ptr();
1220 
1221   if (!initialized)
1222   {
1223     /*
1224       here if mysqld's been started with --skip-grant-tables option.
1225     */
1226     sctx->skip_grants();
1227     DBUG_RETURN(FALSE);
1228   }
1229 
1230   mysql_mutex_lock(&acl_cache->lock);
1231 
1232   sctx->set_master_access(0);
1233   sctx->set_db_access(0);
1234   sctx->assign_priv_user("", 0);
1235   sctx->assign_priv_host("", 0);
1236 
1237   /*
1238      Find acl entry in user database.
1239      This is specially tailored to suit the check we do for CALL of
1240      a stored procedure; user is set to what is actually a
1241      priv_user, which can be ''.
1242   */
1243   for (ACL_USER *acl_user_tmp= acl_users->begin();
1244        acl_user_tmp != acl_users->end(); ++acl_user_tmp)
1245   {
1246     if ((!acl_user_tmp->user && !user[0]) ||
1247         (acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0))
1248     {
1249       if (acl_user_tmp->host.compare_hostname(host, ip))
1250       {
1251         acl_user= acl_user_tmp;
1252         res= 0;
1253         break;
1254       }
1255     }
1256   }
1257 
1258   if (acl_user)
1259   {
1260     for (ACL_DB *acl_db= acl_dbs->begin(); acl_db != acl_dbs->end(); ++acl_db)
1261     {
1262       if (!acl_db->user ||
1263           (user && user[0] && !strcmp(user, acl_db->user)))
1264       {
1265         if (acl_db->host.compare_hostname(host, ip))
1266         {
1267           if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
1268           {
1269             sctx->set_db_access(acl_db->access);
1270             break;
1271           }
1272         }
1273       }
1274     }
1275     sctx->set_master_access(acl_user->access);
1276     sctx->assign_priv_user(user, user ? strlen(user) : 0);
1277 
1278     sctx->assign_priv_host(acl_user->host.get_host(),
1279                            acl_user->host.get_host_len());
1280 
1281     sctx->set_password_expired(acl_user->password_expired);
1282   }
1283   mysql_mutex_unlock(&acl_cache->lock);
1284   DBUG_RETURN(res);
1285 }
1286 
1287 
1288 namespace {
1289 
1290 class ACL_compare :
1291   public std::binary_function<ACL_ACCESS, ACL_ACCESS, bool>
1292 {
1293 public:
operator ()(const ACL_ACCESS & a,const ACL_ACCESS & b)1294   bool operator()(const ACL_ACCESS &a, const ACL_ACCESS &b)
1295   {
1296     return a.sort > b.sort;
1297   }
1298 };
1299 
1300 } // namespace
1301 
1302 
1303 /**
1304   Convert scrambled password to binary form, according to scramble type,
1305   Binary form is stored in user.salt.
1306 
1307   @param acl_user The object where to store the salt
1308 
1309   Despite the name of the function it is used when loading ACLs from disk
1310   to store the password hash in the ACL_USER object.
1311   Note that it works only for native and "old" mysql authentication built-in
1312   plugins.
1313 
1314   Assumption : user's authentication plugin information is available.
1315 
1316   @return Password hash validation
1317     @retval false Hash is of suitable length
1318     @retval true Hash is of wrong length or format
1319 */
1320 
set_user_salt(ACL_USER * acl_user)1321 bool set_user_salt(ACL_USER *acl_user)
1322 {
1323   bool result= false;
1324   plugin_ref plugin= NULL;
1325 
1326   plugin= my_plugin_lock_by_name(0, acl_user->plugin,
1327                                  MYSQL_AUTHENTICATION_PLUGIN);
1328   if (plugin)
1329   {
1330     st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
1331     result=  auth->set_salt(acl_user->auth_string.str,
1332                             acl_user->auth_string.length,
1333                             acl_user->salt,
1334                             &acl_user->salt_len);
1335     plugin_unlock(0, plugin);
1336   }
1337   return result;
1338 }
1339 
1340 /**
1341   Iterate over the user records and check for irregularities.
1342   Currently this includes :
1343    - checking if the plugin referenced is present.
1344    - if there's sha256 users and there's neither SSL nor RSA configured
1345 */
1346 static void
validate_user_plugin_records()1347 validate_user_plugin_records()
1348 {
1349   DBUG_ENTER("validate_user_plugin_records");
1350   if (!validate_user_plugins)
1351     DBUG_VOID_RETURN;
1352 
1353   lock_plugin_data();
1354   for (ACL_USER *acl_user= acl_users->begin();
1355        acl_user != acl_users->end(); ++acl_user)
1356   {
1357     struct st_plugin_int *plugin;
1358 
1359     if (acl_user->plugin.length)
1360     {
1361       /* rule 1 : plugin does exit */
1362       if (!auth_plugin_is_built_in(acl_user->plugin.str))
1363       {
1364         plugin= plugin_find_by_type(acl_user->plugin,
1365                                     MYSQL_AUTHENTICATION_PLUGIN);
1366 
1367         if (!plugin)
1368         {
1369           sql_print_warning("The plugin '%.*s' used to authenticate "
1370                             "user '%s'@'%.*s' is not loaded."
1371                             " Nobody can currently login using this account.",
1372                             (int) acl_user->plugin.length, acl_user->plugin.str,
1373                             acl_user->user,
1374                             static_cast<int>(acl_user->host.get_host_len()),
1375                             acl_user->host.get_host());
1376         }
1377       }
1378       if (acl_user->plugin.str == sha256_password_plugin_name.str &&
1379           rsa_auth_status() && !ssl_acceptor_fd)
1380       {
1381           sql_print_warning("The plugin '%s' is used to authenticate "
1382                             "user '%s'@'%.*s', "
1383                             "but neither SSL nor RSA keys are "
1384                             "configured. "
1385                             "Nobody can currently login using this account.",
1386                             sha256_password_plugin_name.str,
1387                             acl_user->user,
1388                             static_cast<int>(acl_user->host.get_host_len()),
1389                             acl_user->host.get_host());
1390       }
1391     }
1392   }
1393   unlock_plugin_data();
1394   DBUG_VOID_RETURN;
1395 }
1396 
1397 
1398 /*
1399   Initialize structures responsible for user/db-level privilege checking and
1400   load privilege information for them from tables in the 'mysql' database.
1401 
1402   SYNOPSIS
1403     acl_init()
1404       dont_read_acl_tables  TRUE if we want to skip loading data from
1405                             privilege tables and disable privilege checking.
1406 
1407   NOTES
1408     This function is mostly responsible for preparatory steps, main work
1409     on initialization and grants loading is done in acl_reload().
1410 
1411   RETURN VALUES
1412     0   ok
1413     1   Could not initialize grant's
1414 */
1415 
acl_init(bool dont_read_acl_tables)1416 my_bool acl_init(bool dont_read_acl_tables)
1417 {
1418   THD  *thd;
1419   my_bool return_val;
1420   DBUG_ENTER("acl_init");
1421 
1422   acl_cache= new hash_filo(key_memory_acl_cache,
1423                            ACL_CACHE_SIZE, 0, 0,
1424                            (my_hash_get_key) acl_entry_get_key,
1425                            (my_hash_free_key) my_free,
1426                            &my_charset_utf8_bin);
1427 
1428   LOCK_grant.init(LOCK_GRANT_PARTITIONS
1429 #ifdef HAVE_PSI_INTERFACE
1430                   , key_rwlock_LOCK_grant
1431 #endif
1432                   );
1433   rwlocks_initialized= true;
1434 
1435   /*
1436     cache built-in native authentication plugins,
1437     to avoid hash searches and a global mutex lock on every connect
1438   */
1439   native_password_plugin= my_plugin_lock_by_name(0,
1440            native_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
1441   if (!native_password_plugin)
1442     DBUG_RETURN(1);
1443 
1444   if (dont_read_acl_tables)
1445   {
1446     DBUG_RETURN(0); /* purecov: tested */
1447   }
1448 
1449   /*
1450     To be able to run this from boot, we allocate a temporary THD
1451   */
1452   if (!(thd=new THD))
1453     DBUG_RETURN(1); /* purecov: inspected */
1454   thd->thread_stack= (char*) &thd;
1455   thd->store_globals();
1456   /*
1457     It is safe to call acl_reload() since acl_* arrays and hashes which
1458     will be freed there are global static objects and thus are initialized
1459     by zeros at startup.
1460   */
1461   return_val= acl_reload(thd);
1462 
1463   thd->release_resources();
1464   delete thd;
1465 
1466   DBUG_RETURN(return_val);
1467 }
1468 
1469 /*
1470   Set up the acl_utility_user and add it to the acl_user list.
1471 */
1472 static
1473 bool
acl_init_utility_user(bool check_no_resolve)1474 acl_init_utility_user(bool check_no_resolve)
1475 {
1476   bool ret= true;
1477 
1478   if (!utility_user)
1479     goto end;
1480 
1481   acl_free_utility_user();
1482 
1483   /* Allocate all initial resources necessary */
1484   acl_utility_user_name.str= (char *) my_malloc(key_memory_acl_mem,
1485                                                 USERNAME_LENGTH + 1,
1486                                                 MY_ZEROFILL);
1487   acl_utility_user_host_name.str= (char *) my_malloc(key_memory_acl_mem,
1488                                                      HOSTNAME_LENGTH+1,
1489                                                      MY_ZEROFILL);
1490 
1491   /* Buffer sizing here assumes that the utility user is using the
1492   mysql_native_password-style authentication. */
1493   acl_utility_user.auth_string.str=
1494       static_cast<char *>(my_malloc(key_memory_acl_mem,
1495                                     SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
1496                                     MYF(0)));
1497 
1498   acl_utility_user_initialized= true;
1499 
1500   /* parse out the option to its component user and host name parts */
1501   parse_user(utility_user, strlen(utility_user),
1502              acl_utility_user_name.str, &acl_utility_user_name.length,
1503              acl_utility_user_host_name.str,
1504              &acl_utility_user_host_name.length);
1505 
1506   /* Check to see if the username is anonymous */
1507   if (!acl_utility_user_name.str || acl_utility_user_name.str[0] == '\0')
1508   {
1509     sql_print_error("'utility user' specified as '%s' is anonymous"
1510                     " and not allowed.",
1511                     utility_user);
1512     ret= false;
1513     goto cleanup;
1514   }
1515 
1516   /* Check to see that a password was supplied */
1517   if (!utility_user_password || utility_user_password[0] == '\0')
1518   {
1519     sql_print_error("'utility user' specified as '%s' but has no "
1520                     "password. Please see --utility_user_password.",
1521                     utility_user);
1522     ret= false;
1523     goto cleanup;
1524   }
1525 
1526   /* set up some of the static utility user struct fields */
1527   acl_utility_user.user= acl_utility_user_name.str;
1528 
1529   acl_utility_user.host.update_hostname(acl_utility_user_host_name.str);
1530 
1531   acl_utility_user.sort= get_sort(2, acl_utility_user.host.get_host(),
1532                                   acl_utility_user.user);
1533 
1534   /* Check to see if the utility user matches any existing user */
1535   for (ACL_USER *user= acl_users->begin(); user != acl_users->end(); ++user)
1536   {
1537     if (user->user
1538         && strcmp(acl_utility_user_name.str, user->user) == 0)
1539     {
1540       if (user->sort == acl_utility_user.sort)
1541       {
1542         sql_print_error("'utility user' specification '%s' exactly"
1543                         " matches existing user in mysql.user table.",
1544                         utility_user);
1545         ret= false;
1546         goto cleanup;
1547       }
1548       else if (user->sort < acl_utility_user.sort)
1549       {
1550         sql_print_warning("'utility user' specification '%s' closely"
1551                           " matches more specific existing user '%s@%s' in"
1552                           " mysql.user table which may render the utility_user"
1553                           " inaccessable from certain hosts.", utility_user,
1554                           user->user ? user->user : "",
1555                           user->host.get_host());
1556       }
1557     }
1558   }
1559 
1560   if (check_no_resolve
1561       && hostname_requires_resolving(acl_utility_user.host.get_host()))
1562   {
1563     sql_print_warning("'utility user' entry '%s@%s' "
1564                       "ignored in --skip-name-resolve mode.",
1565                       acl_utility_user.user ? acl_utility_user.user : "",
1566                       acl_utility_user.host.get_host() ?
1567                       acl_utility_user.host.get_host() : "");
1568     ret= false;
1569     goto cleanup;
1570   }
1571 
1572   /* Fill out the rest of the static utility user struct, and add it into the
1573   acl_users list, then resort */
1574   my_make_scrambled_password_sha1(acl_utility_user.auth_string.str,
1575                                   utility_user_password,
1576                                   strlen(utility_user_password));
1577 
1578   acl_utility_user.auth_string.length=
1579     strlen(acl_utility_user.auth_string.str);
1580 
1581   acl_utility_user.plugin= native_password_plugin_name;
1582 
1583   if (set_user_salt(&acl_utility_user))
1584   {
1585     goto cleanup;
1586   }
1587 
1588   assert(utility_user_privileges <= UINT_MAX32);
1589   acl_utility_user.access= utility_user_privileges & UINT_MAX32;
1590   if (acl_utility_user.access)
1591   {
1592     char privilege_desc[512];
1593     get_privilege_desc(privilege_desc, array_elements(privilege_desc), acl_utility_user.access);
1594     sql_print_information("Utility user '%s'@'%s' in use with access rights "
1595                           "'%s'.",
1596                           acl_utility_user.user,
1597                           acl_utility_user.host.get_host(),
1598                           privilege_desc);
1599   }
1600   else
1601   {
1602     sql_print_information("Utility user '%s'@'%s' in use with basic "
1603                           "access rights.",
1604                           acl_utility_user.user,
1605                           acl_utility_user.host.get_host());
1606   }
1607 
1608   acl_utility_user.ssl_type= SSL_TYPE_NONE;
1609 
1610   acl_utility_user.can_authenticate= true;
1611 
1612   acl_users->push_back(acl_utility_user);
1613 
1614   /* initialize the schema access list if specified */
1615   if (utility_user_schema_access)
1616   {
1617     char *cur_pos= utility_user_schema_access;
1618     char *cur_db= cur_pos;
1619     do
1620     {
1621       if (*cur_pos == ',' || *cur_pos == '\0')
1622       {
1623 	if (cur_pos - cur_db > 0) {
1624           acl_utility_user_schema_access.push_back(std::string(cur_db,
1625                                                                cur_pos
1626                                                                - cur_db));
1627 	}
1628         cur_db= cur_pos+1;
1629         if (*cur_pos == '\0')
1630           break;
1631       }
1632       cur_pos++;
1633     } while(1);
1634 
1635     sql_print_information("Utility user '%s'@'%s' in use with full access to"
1636                           " schemas '%s'.",
1637                           acl_utility_user.user,
1638                           acl_utility_user.host.get_host(),
1639                           utility_user_schema_access);
1640   }
1641   else
1642   {
1643     sql_print_information("Utility user '%s'@'%s' in use with"
1644                           " no schema access",
1645                           acl_utility_user.user,
1646                           acl_utility_user.host.get_host());
1647   }
1648   goto end;
1649 
1650 cleanup:
1651   acl_free_utility_user();
1652 
1653 end:
1654   return ret;
1655 }
1656 
1657 /*
1658   Free up any resources allocated during acl_init_utility_user.
1659 */
1660 static
1661 void
acl_free_utility_user()1662 acl_free_utility_user()
1663 {
1664   if (acl_utility_user_initialized)
1665   {
1666     acl_utility_user_schema_access.clear();
1667     my_free(acl_utility_user_name.str);
1668     my_free(acl_utility_user_host_name.str);
1669     my_free(acl_utility_user.auth_string.str);
1670     memset(&acl_utility_user, 0, sizeof(acl_utility_user));
1671     acl_utility_user_initialized= false;
1672   }
1673 }
1674 
1675 /*
1676   Determines if the user specified by user, host, ip matches the utility user
1677 */
1678 bool
acl_is_utility_user(const char * user,const char * host,const char * ip)1679 acl_is_utility_user(const char *user, const char *host, const char *ip)
1680 {
1681   return (user && acl_utility_user.user
1682           && strcmp(user, acl_utility_user.user) == 0
1683           && acl_utility_user.host.compare_hostname(host, ip));
1684 }
1685 
1686 /*
1687   Initialize structures responsible for user/db-level privilege checking
1688   and load information about grants from open privilege tables.
1689 
1690   SYNOPSIS
1691     acl_load()
1692       thd     Current thread
1693       tables  List containing open "mysql.host", "mysql.user",
1694               "mysql.db" and "mysql.proxies_priv" tables in that order.
1695 
1696   RETURN VALUES
1697     FALSE  Success
1698     TRUE   Error
1699 */
1700 
acl_load(THD * thd,TABLE_LIST * tables)1701 static my_bool acl_load(THD *thd, TABLE_LIST *tables)
1702 {
1703   TABLE *table;
1704   READ_RECORD read_record_info;
1705   my_bool return_val= TRUE;
1706   bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
1707   char tmp_name[NAME_LEN+1];
1708   sql_mode_t old_sql_mode= thd->variables.sql_mode;
1709   bool password_expired= false;
1710   bool super_users_with_empty_plugin= false;
1711   Acl_load_user_table_schema_factory user_table_schema_factory;
1712   Acl_load_user_table_schema *table_schema = NULL;
1713   bool is_old_db_layout= false;
1714   DBUG_ENTER("acl_load");
1715 
1716   DBUG_EXECUTE_IF("wl_9262_set_max_length_hostname",
1717                     thd->security_context()->assign_priv_host(
1718                       "oh_my_gosh_this_is_a_long_"
1719                       "hostname_look_at_it_it_has_60"
1720                       "_char", 60);
1721                     thd->security_context()->assign_host(
1722                       "oh_my_gosh_this_is_a_long_"
1723                       "hostname_look_at_it_it_has_60"
1724                       "_char", 60);
1725                     thd->security_context()->set_host_or_ip_ptr();
1726                     );
1727 
1728   thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
1729 
1730   grant_version++; /* Privileges updated */
1731 
1732 
1733   acl_cache->clear(1);                          // Clear locked hostname cache
1734 
1735   init_sql_alloc(key_memory_acl_mem,
1736                  &global_acl_memory, ACL_ALLOC_BLOCK_SIZE, 0);
1737   /*
1738     Prepare reading from the mysql.user table
1739   */
1740   if (init_read_record(&read_record_info, thd, table=tables[0].table,
1741                        NULL, 1, 1, FALSE))
1742     goto end;
1743   table->use_all_columns();
1744   acl_users->clear();
1745   /*
1746    We need to check whether we are working with old database layout. This
1747    might be the case for instance when we are running mysql_upgrade.
1748   */
1749   if (user_table_schema_factory.user_table_schema_check(table))
1750   {
1751     table_schema= user_table_schema_factory.get_user_table_schema(table);
1752     is_old_db_layout= user_table_schema_factory.is_old_user_table_schema(table);
1753   }
1754   else
1755   {
1756     sql_print_error("[FATAL] mysql.user table is damaged. "
1757                     "Please run mysql_upgrade.");
1758     end_read_record(&read_record_info);
1759     goto end;
1760   }
1761 
1762   allow_all_hosts=0;
1763   int read_rec_errcode;
1764   while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
1765   {
1766     password_expired= false;
1767     /* Reading record from mysql.user */
1768     ACL_USER user;
1769     memset(&user, 0, sizeof(user));
1770 
1771     /*
1772       All accounts can authenticate per default. This will change when
1773       we add a new field to the user table.
1774 
1775       Currently this flag is only set to false when authentication is attempted
1776       using an unknown user name.
1777     */
1778     user.can_authenticate= true;
1779 
1780     /*
1781       Account is unlocked by default.
1782     */
1783     user.account_locked= false;
1784 
1785     user.host.update_hostname(get_field(&global_acl_memory,
1786                                       table->field[table_schema->host_idx()]));
1787     user.user= get_field(&global_acl_memory,
1788                          table->field[table_schema->user_idx()]);
1789   if (check_no_resolve && hostname_requires_resolving(user.host.get_host()) &&
1790       !is_localhost_string(user.host.get_host())) {
1791       sql_print_warning("'user' entry '%s@%s' "
1792                         "ignored in --skip-name-resolve mode.",
1793                         user.user ? user.user : "",
1794                         user.host.get_host());
1795     }
1796 
1797     /* Read password from authentication_string field */
1798     if (table->s->fields > table_schema->authentication_string_idx())
1799       user.auth_string.str=
1800         get_field(&global_acl_memory,
1801                   table->field[table_schema->authentication_string_idx()]);
1802     else
1803     {
1804       sql_print_error("Fatal error: mysql.user table is damaged. "
1805                       "Please run mysql_upgrade.");
1806 
1807       end_read_record(&read_record_info);
1808       goto end;
1809     }
1810     if(user.auth_string.str)
1811       user.auth_string.length= strlen(user.auth_string.str);
1812     else
1813       user.auth_string= EMPTY_STR;
1814 
1815     {
1816       uint next_field;
1817       user.access= get_access(table, table_schema->select_priv_idx(),
1818                               &next_field) & GLOBAL_ACLS;
1819       /*
1820         if it is pre 5.0.1 privilege table then map CREATE privilege on
1821         CREATE VIEW & SHOW VIEW privileges
1822       */
1823       if (table->s->fields <= 31 && (user.access & CREATE_ACL))
1824         user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
1825 
1826       /*
1827         if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
1828         CREATE PROCEDURE & ALTER PROCEDURE privileges
1829       */
1830       if (table->s->fields <= 33 && (user.access & CREATE_ACL))
1831         user.access|= CREATE_PROC_ACL;
1832       if (table->s->fields <= 33 && (user.access & ALTER_ACL))
1833         user.access|= ALTER_PROC_ACL;
1834 
1835       /*
1836         pre 5.0.3 did not have CREATE_USER_ACL
1837       */
1838       if (table->s->fields <= 36 && (user.access & GRANT_ACL))
1839         user.access|= CREATE_USER_ACL;
1840 
1841 
1842       /*
1843         if it is pre 5.1.6 privilege table then map CREATE privilege on
1844         CREATE|ALTER|DROP|EXECUTE EVENT
1845       */
1846       if (table->s->fields <= 37 && (user.access & SUPER_ACL))
1847         user.access|= EVENT_ACL;
1848 
1849       /*
1850         if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
1851       */
1852       if (table->s->fields <= 38 && (user.access & SUPER_ACL))
1853         user.access|= TRIGGER_ACL;
1854 
1855       user.sort= get_sort(2,user.host.get_host(),user.user);
1856 
1857       /* Starting from 4.0.2 we have more fields */
1858       if (table->s->fields >= 31)
1859       {
1860         char *ssl_type=
1861           get_field(thd->mem_root, table->field[table_schema->ssl_type_idx()]);
1862         if (!ssl_type)
1863           user.ssl_type=SSL_TYPE_NONE;
1864         else if (!strcmp(ssl_type, "ANY"))
1865           user.ssl_type=SSL_TYPE_ANY;
1866         else if (!strcmp(ssl_type, "X509"))
1867           user.ssl_type=SSL_TYPE_X509;
1868         else  /* !strcmp(ssl_type, "SPECIFIED") */
1869           user.ssl_type=SSL_TYPE_SPECIFIED;
1870 
1871         user.ssl_cipher=
1872           get_field(&global_acl_memory,
1873                     table->field[table_schema->ssl_cipher_idx()]);
1874         user.x509_issuer=
1875           get_field(&global_acl_memory,
1876                     table->field[table_schema->x509_issuer_idx()]);
1877         user.x509_subject=
1878           get_field(&global_acl_memory,
1879                     table->field[table_schema->x509_subject_idx()]);
1880 
1881         char *ptr= get_field(thd->mem_root,
1882                              table->field[table_schema->max_questions_idx()]);
1883         user.user_resource.questions=ptr ? atoi(ptr) : 0;
1884         ptr= get_field(thd->mem_root,
1885                        table->field[table_schema->max_updates_idx()]);
1886         user.user_resource.updates=ptr ? atoi(ptr) : 0;
1887         ptr= get_field(thd->mem_root,
1888                        table->field[table_schema->max_connections_idx()]);
1889         user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
1890         if (user.user_resource.questions || user.user_resource.updates ||
1891             user.user_resource.conn_per_hour)
1892           mqh_used=1;
1893 
1894         if (table->s->fields > table_schema->max_user_connections_idx())
1895         {
1896           /* Starting from 5.0.3 we have max_user_connections field */
1897           ptr= get_field(thd->mem_root,
1898                          table->field[table_schema->max_user_connections_idx()]);
1899           user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
1900         }
1901 
1902         if (table->s->fields >= 41)
1903         {
1904           /* We may have plugin & auth_String fields */
1905           const char *tmpstr=
1906             get_field(&global_acl_memory,
1907                       table->field[table_schema->plugin_idx()]);
1908 
1909           /* In case we are working with 5.6 db layout we need to make server
1910              aware of Password field and that the plugin column can be null.
1911              In case when plugin column is null we use native password plugin
1912              if we can.
1913           */
1914           if (is_old_db_layout && (tmpstr == NULL || strlen(tmpstr) == 0 ||
1915               my_strcasecmp(system_charset_info, tmpstr,
1916                             native_password_plugin_name.str) == 0))
1917           {
1918             char *password= get_field(&global_acl_memory,
1919                                     table->field[table_schema->password_idx()]);
1920 
1921             //We only support native hash, we do not support pre 4.1 hashes
1922             plugin_ref native_plugin= NULL;
1923             native_plugin= my_plugin_lock_by_name(0,
1924                                        native_password_plugin_name,
1925                                        MYSQL_AUTHENTICATION_PLUGIN);
1926             if (native_plugin)
1927             {
1928               uint password_len= password ? strlen(password) : 0;
1929               st_mysql_auth *auth=
1930                 (st_mysql_auth *) plugin_decl(native_plugin)->info;
1931               if (auth->validate_authentication_string(password,
1932                                                        password_len) == 0)
1933               {
1934                 //auth_string takes precedence over password
1935                 if (user.auth_string.length == 0)
1936                 {
1937                   user.auth_string.str= password;
1938                   user.auth_string.length= password_len;
1939                 }
1940                 if (tmpstr == NULL || strlen(tmpstr) == 0)
1941                   tmpstr= native_password_plugin_name.str;
1942               }
1943               else
1944               {
1945                 if ((user.access & SUPER_ACL) && !super_users_with_empty_plugin
1946                     && (tmpstr == NULL || strlen(tmpstr) == 0))
1947                   super_users_with_empty_plugin= true;
1948 
1949                 sql_print_warning("User entry '%s'@'%s' has a deprecated "
1950                 "pre-4.1 password. The user will be ignored and no one can "
1951                 "login with this user anymore.",
1952                 user.user ? user.user : "",
1953                 user.host.get_host());
1954                 plugin_unlock(0, native_plugin);
1955                 continue;
1956               }
1957               plugin_unlock(0, native_plugin);
1958             }
1959           }
1960 
1961           /*
1962             Check if the plugin string is blank or null.
1963             If it is, the user will be skipped.
1964           */
1965           if(tmpstr == NULL || strlen(tmpstr) == 0)
1966           {
1967             if ((user.access & SUPER_ACL) && !super_users_with_empty_plugin)
1968                       super_users_with_empty_plugin= true;
1969             sql_print_warning("User entry '%s'@'%s' has an empty plugin "
1970       			"value. The user will be ignored and no one can login "
1971       			"with this user anymore.",
1972       			user.user ? user.user : "",
1973                         user.host.get_host());
1974             continue;
1975           }
1976           /*
1977             By comparing the plugin with the built in plugins it is possible
1978             to optimize the string allocation and comparision.
1979           */
1980           if (my_strcasecmp(system_charset_info, tmpstr,
1981                             native_password_plugin_name.str) == 0)
1982             user.plugin= native_password_plugin_name;
1983 #if defined(HAVE_OPENSSL)
1984           else
1985             if (my_strcasecmp(system_charset_info, tmpstr,
1986                               sha256_password_plugin_name.str) == 0)
1987               user.plugin= sha256_password_plugin_name;
1988 #endif
1989           else
1990             {
1991               user.plugin.str= tmpstr;
1992               user.plugin.length= strlen(tmpstr);
1993             }
1994         }
1995 
1996         /* Validate the hash string. */
1997         plugin_ref plugin= NULL;
1998         plugin= my_plugin_lock_by_name(0, user.plugin,
1999                                        MYSQL_AUTHENTICATION_PLUGIN);
2000         if (plugin)
2001         {
2002           st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
2003           if (auth->validate_authentication_string(user.auth_string.str,
2004                                                    user.auth_string.length))
2005           {
2006             sql_print_warning("Found invalid password for user: '%s@%s'; "
2007                               "Ignoring user", user.user ? user.user : "",
2008                               user.host.get_host());
2009             plugin_unlock(0, plugin);
2010             continue;
2011           }
2012           plugin_unlock(0, plugin);
2013         }
2014 
2015         if (table->s->fields > table_schema->password_expired_idx())
2016         {
2017           char *tmpstr= get_field(&global_acl_memory,
2018                            table->field[table_schema->password_expired_idx()]);
2019           if (tmpstr && (*tmpstr == 'Y' || *tmpstr == 'y'))
2020           {
2021             user.password_expired= true;
2022 
2023             if (!auth_plugin_supports_expiration(user.plugin.str))
2024             {
2025               sql_print_warning("'user' entry '%s@%s' has the password ignore "
2026                                 "flag raised, but its authentication plugin "
2027                                 "doesn't support password expiration. "
2028                                 "The user id will be ignored.",
2029                                 user.user ? user.user : "",
2030                                 user.host.get_host());
2031               continue;
2032             }
2033             password_expired= true;
2034           }
2035         }
2036 
2037         if (table->s->fields > table_schema->account_locked_idx())
2038         {
2039           char *locked = get_field(&global_acl_memory,
2040                              table->field[table_schema->account_locked_idx()]);
2041 
2042           if (locked && (*locked == 'Y' || *locked == 'y'))
2043           {
2044             user.account_locked= true;
2045           }
2046         }
2047 
2048 	/*
2049 	   Initalize the values of timestamp and expire after day
2050 	   to error and true respectively.
2051 	*/
2052 	user.password_last_changed.time_type= MYSQL_TIMESTAMP_ERROR;
2053 	user.use_default_password_lifetime= true;
2054 	user.password_lifetime= 0;
2055 
2056 	if (table->s->fields > table_schema->password_last_changed_idx())
2057         {
2058 	  if (!table->field[table_schema->password_last_changed_idx()]->is_null())
2059 	  {
2060             char *password_last_changed= get_field(&global_acl_memory,
2061 	          table->field[table_schema->password_last_changed_idx()]);
2062 
2063 	    if (password_last_changed &&
2064 	        memcmp(password_last_changed, INVALID_DATE, sizeof(INVALID_DATE)))
2065 	    {
2066 	      String str(password_last_changed, &my_charset_bin);
2067               str_to_time_with_warn(&str,&(user.password_last_changed));
2068 	    }
2069 	  }
2070 	}
2071 
2072         if (table->s->fields > table_schema->password_lifetime_idx())
2073         {
2074           if (!table->
2075               field[table_schema->password_lifetime_idx()]->is_null())
2076 	  {
2077 	    char *ptr= get_field(&global_acl_memory,
2078 		table->field[table_schema->password_lifetime_idx()]);
2079 	    user.password_lifetime= ptr ? atoi(ptr) : 0;
2080 	    user.use_default_password_lifetime= false;
2081 	  }
2082 	}
2083 
2084       } // end if (table->s->fields >= 31)
2085       else
2086       {
2087         user.ssl_type=SSL_TYPE_NONE;
2088         if (table->s->fields <= 13)
2089         {                                               // Without grant
2090           if (user.access & CREATE_ACL)
2091             user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
2092         }
2093         /* Convert old privileges */
2094         user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
2095         if (user.access & FILE_ACL)
2096           user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
2097         if (user.access & PROCESS_ACL)
2098           user.access|= SUPER_ACL | EXECUTE_ACL;
2099       }
2100 
2101       set_user_salt(&user);
2102       user.password_expired= password_expired;
2103 
2104       acl_users->push_back(user);
2105       if (user.host.check_allow_all_hosts())
2106         allow_all_hosts=1;                      // Anyone can connect
2107     }
2108   } // END while reading records from the mysql.user table
2109 
2110   end_read_record(&read_record_info);
2111 
2112   DBUG_EXECUTE_IF("simulate_acl_init_failure",
2113                   read_rec_errcode= HA_ERR_WRONG_IN_RECORD;);
2114 
2115   if (read_rec_errcode > 0)
2116   {
2117     table->file->print_error(read_rec_errcode, MYF(ME_ERRORLOG));
2118     goto end;
2119   }
2120 
2121   if (!acl_init_utility_user(check_no_resolve))
2122     goto end;
2123 
2124   std::sort(acl_users->begin(), acl_users->end(), ACL_compare());
2125   acl_users->shrink_to_fit();
2126 
2127   if (super_users_with_empty_plugin)
2128   {
2129     sql_print_warning("Some of the user accounts with SUPER privileges were "
2130                       "disabled because of empty mysql.user.plugin value. "
2131                       "If you are upgrading from MySQL 5.6 to MySQL 5.7 it "
2132                       "means we were not able to substitute for empty plugin "
2133                       "column. Probably because of pre 4.1 password hash. "
2134                       "If your account is disabled you will need to:");
2135     sql_print_warning("1. Stop the server and restart it with "
2136                       "--skip-grant-tables.");
2137     sql_print_warning("2. Run mysql_upgrade.");
2138     sql_print_warning("3. Restart the server with the parameters you "
2139                       "normally use.");
2140     sql_print_warning("For complete instructions on how to upgrade MySQL "
2141                       "to a new version please see the 'Upgrading MySQL' "
2142                       "section from the MySQL manual");
2143   }
2144 
2145   /*
2146     Prepare reading from the mysql.db table
2147   */
2148   if (init_read_record(&read_record_info, thd, table=tables[1].table,
2149                        NULL, 1, 1, FALSE))
2150     goto end;
2151   table->use_all_columns();
2152   acl_dbs->clear();
2153 
2154   while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
2155   {
2156     /* Reading record in mysql.db */
2157     ACL_DB db;
2158     db.host.update_hostname(get_field(&global_acl_memory,
2159                             table->field[MYSQL_DB_FIELD_HOST]));
2160     db.db=get_field(&global_acl_memory, table->field[MYSQL_DB_FIELD_DB]);
2161     if (!db.db)
2162     {
2163       sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
2164       continue;
2165     }
2166     db.user=get_field(&global_acl_memory, table->field[MYSQL_DB_FIELD_USER]);
2167     if (check_no_resolve && hostname_requires_resolving(db.host.get_host()) &&
2168         !is_localhost_string(db.host.get_host())) {
2169       sql_print_warning("'db' entry '%s %s@%s' "
2170                         "ignored in --skip-name-resolve mode.",
2171                         db.db,
2172                         db.user ? db.user : "",
2173                         db.host.get_host());
2174     }
2175     db.access=get_access(table,3,0);
2176     db.access=fix_rights_for_db(db.access);
2177     if (lower_case_table_names)
2178     {
2179       /*
2180         convert db to lower case and give a warning if the db wasn't
2181         already in lower case
2182       */
2183       (void)my_stpcpy(tmp_name, db.db);
2184       my_casedn_str(files_charset_info, db.db);
2185       if (strcmp(db.db, tmp_name) != 0)
2186       {
2187         sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
2188                           "case that has been forced to lowercase because "
2189                           "lower_case_table_names is set. It will not be "
2190                           "possible to remove this privilege using REVOKE.",
2191                           db.db,
2192                           db.user ? db.user : "",
2193                           db.host.get_host());
2194       }
2195     }
2196     db.sort=get_sort(3,db.host.get_host(),db.db,db.user);
2197     if (table->s->fields <=  9)
2198     {                                           // Without grant
2199       if (db.access & CREATE_ACL)
2200         db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
2201     }
2202     acl_dbs->push_back(db);
2203   } // END reading records from mysql.db tables
2204 
2205   end_read_record(&read_record_info);
2206   if (read_rec_errcode > 0)
2207   {
2208     table->file->print_error(read_rec_errcode, MYF(ME_ERRORLOG));
2209     goto end;
2210   }
2211 
2212   std::sort(acl_dbs->begin(), acl_dbs->end(), ACL_compare());
2213   acl_dbs->shrink_to_fit();
2214 
2215   /* Prepare to read records from the mysql.proxies_priv table */
2216   acl_proxy_users->clear();
2217 
2218   if (tables[2].table)
2219   {
2220     if (init_read_record(&read_record_info, thd, table= tables[2].table,
2221                          NULL, 1, 1, FALSE))
2222       goto end;
2223     table->use_all_columns();
2224     while (!(read_rec_errcode= read_record_info.read_record(&read_record_info)))
2225     {
2226       /* Reading record in mysql.proxies_priv */
2227       ACL_PROXY_USER proxy;
2228       proxy.init(table, &global_acl_memory);
2229       proxy.check_validity(check_no_resolve);
2230       if (acl_proxy_users->push_back(proxy))
2231       {
2232         end_read_record(&read_record_info);
2233         goto end;
2234       }
2235     } // END reading records from the mysql.proxies_priv table
2236 
2237     end_read_record(&read_record_info);
2238     if (read_rec_errcode > 0)
2239     {
2240       table->file->print_error(read_rec_errcode, MYF(ME_ERRORLOG));
2241       goto end;
2242     }
2243 
2244     std::sort(acl_proxy_users->begin(), acl_proxy_users->end(), ACL_compare());
2245   }
2246   else
2247   {
2248     sql_print_error("Missing system table mysql.proxies_priv; "
2249                     "please run mysql_upgrade to create it");
2250   }
2251   acl_proxy_users->shrink_to_fit();
2252   validate_user_plugin_records();
2253   init_check_host();
2254 
2255   initialized=1;
2256   return_val= FALSE;
2257 
2258 end:
2259   thd->variables.sql_mode= old_sql_mode;
2260   if (table_schema)
2261     delete table_schema;
2262   DBUG_RETURN(return_val);
2263 }
2264 
2265 
2266 
2267 
acl_free(bool end)2268 void acl_free(bool end)
2269 {
2270   acl_free_utility_user();
2271   free_root(&global_acl_memory,MYF(0));
2272   delete acl_users;
2273   acl_users= NULL;
2274   delete acl_dbs;
2275   acl_dbs= NULL;
2276   delete acl_wild_hosts;
2277   acl_wild_hosts= NULL;
2278   delete acl_proxy_users;
2279   acl_proxy_users= NULL;
2280   my_hash_free(&acl_check_hosts);
2281   if (!end)
2282     acl_cache->clear(1); /* purecov: inspected */
2283   else
2284   {
2285     plugin_unlock(0, native_password_plugin);
2286     delete acl_cache;
2287     acl_cache=0;
2288 
2289     if (rwlocks_initialized)
2290     {
2291       LOCK_grant.destroy();
2292       rwlocks_initialized= false;
2293     }
2294   }
2295 }
2296 
2297 
2298 /*
2299   Forget current user/db-level privileges and read new privileges
2300   from the privilege tables.
2301 
2302   SYNOPSIS
2303     acl_reload()
2304       thd  Current thread
2305 
2306   NOTE
2307     All tables of calling thread which were open and locked by LOCK TABLES
2308     statement will be unlocked and closed.
2309     This function is also used for initialization of structures responsible
2310     for user/db-level privilege checking.
2311 
2312   RETURN VALUE
2313     FALSE  Success
2314     TRUE   Failure
2315 */
2316 
acl_reload(THD * thd)2317 my_bool acl_reload(THD *thd)
2318 {
2319   TABLE_LIST tables[3];
2320 
2321   MEM_ROOT old_mem;
2322   bool old_initialized;
2323   my_bool return_val= TRUE;
2324   DBUG_ENTER("acl_reload");
2325 
2326   /*
2327     To avoid deadlocks we should obtain table locks before
2328     obtaining acl_cache->lock mutex.
2329   */
2330   tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
2331                            C_STRING_WITH_LEN("user"), "user", TL_READ);
2332   tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
2333                            C_STRING_WITH_LEN("db"), "db", TL_READ);
2334   tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
2335                            C_STRING_WITH_LEN("proxies_priv"),
2336                            "proxies_priv", TL_READ);
2337   tables[0].next_local= tables[0].next_global= tables + 1;
2338   tables[1].next_local= tables[1].next_global= tables + 2;
2339   tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
2340   tables[2].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
2341 
2342   if (open_and_lock_tables(thd, tables, MYSQL_LOCK_IGNORE_TIMEOUT))
2343   {
2344     /*
2345       Execution might have been interrupted; only print the error message
2346       if a user error condition has been raised.
2347     */
2348     if (thd->get_stmt_da()->is_error())
2349     {
2350       sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
2351                       thd->get_stmt_da()->message_text());
2352     }
2353     close_acl_tables(thd);
2354     DBUG_RETURN(true);
2355   }
2356 
2357   if ((old_initialized=initialized))
2358     mysql_mutex_lock(&acl_cache->lock);
2359 
2360   Prealloced_array<ACL_USER, ACL_PREALLOC_SIZE> *old_acl_users= acl_users;
2361   Prealloced_array<ACL_DB, ACL_PREALLOC_SIZE> *old_acl_dbs= acl_dbs;
2362   Prealloced_array<ACL_PROXY_USER,
2363                    ACL_PREALLOC_SIZE> *old_acl_proxy_users = acl_proxy_users;
2364 
2365   acl_users= new Prealloced_array<ACL_USER,
2366                                   ACL_PREALLOC_SIZE>(key_memory_acl_mem);
2367   acl_dbs= new Prealloced_array<ACL_DB,
2368                                 ACL_PREALLOC_SIZE>(key_memory_acl_mem);
2369   acl_proxy_users=
2370     new Prealloced_array<ACL_PROXY_USER,
2371                          ACL_PREALLOC_SIZE>(key_memory_acl_mem);
2372 
2373   old_mem= global_acl_memory;
2374   delete acl_wild_hosts;
2375   acl_wild_hosts= NULL;
2376   my_hash_free(&acl_check_hosts);
2377 
2378   if ((return_val= acl_load(thd, tables)))
2379   {                                     // Error. Revert to old list
2380     DBUG_PRINT("error",("Reverting to old privileges"));
2381     acl_free();                         /* purecov: inspected */
2382     acl_users= old_acl_users;
2383     acl_dbs= old_acl_dbs;
2384     acl_proxy_users= old_acl_proxy_users;
2385 
2386     global_acl_memory= old_mem;
2387     init_check_host();
2388   }
2389   else
2390   {
2391     free_root(&old_mem,MYF(0));
2392     delete old_acl_users;
2393     delete old_acl_dbs;
2394     delete old_acl_proxy_users;
2395   }
2396   if (old_initialized)
2397     mysql_mutex_unlock(&acl_cache->lock);
2398 
2399   close_acl_tables(thd);
2400 
2401   DEBUG_SYNC(thd, "after_acl_reload");
2402   DBUG_RETURN(return_val);
2403 }
2404 
2405 
acl_insert_proxy_user(ACL_PROXY_USER * new_value)2406 void acl_insert_proxy_user(ACL_PROXY_USER *new_value)
2407 {
2408   DBUG_ENTER("acl_insert_proxy_user");
2409   mysql_mutex_assert_owner(&acl_cache->lock);
2410   acl_proxy_users->push_back(*new_value);
2411   std::sort(acl_proxy_users->begin(), acl_proxy_users->end(), ACL_compare());
2412   DBUG_VOID_RETURN;
2413 }
2414 
2415 
free_grant_table(GRANT_TABLE * grant_table)2416 void free_grant_table(GRANT_TABLE *grant_table)
2417 {
2418   my_hash_free(&grant_table->hash_columns);
2419 }
2420 
2421 
2422 /* Search after a matching grant. Prefer exact grants before not exact ones */
2423 
name_hash_search(HASH * name_hash,const char * host,const char * ip,const char * db,const char * user,const char * tname,bool exact,bool name_tolower)2424 GRANT_NAME *name_hash_search(HASH *name_hash,
2425                              const char *host,const char* ip,
2426                              const char *db,
2427                              const char *user, const char *tname,
2428                              bool exact, bool name_tolower)
2429 {
2430   char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr;
2431   uint len;
2432   GRANT_NAME *grant_name,*found=0;
2433   HASH_SEARCH_STATE state;
2434 
2435   name_ptr= my_stpcpy(my_stpcpy(helping, user) + 1, db) + 1;
2436   len  = (uint) (my_stpcpy(name_ptr, tname) - helping) + 1;
2437   if (name_tolower)
2438     my_casedn_str(files_charset_info, name_ptr);
2439   for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping,
2440                                                len, &state);
2441        grant_name ;
2442        grant_name= (GRANT_NAME*) my_hash_next(name_hash,(uchar*) helping,
2443                                               len, &state))
2444   {
2445     if (exact)
2446     {
2447       if (grant_name->host.is_null() ||
2448           (host &&
2449            !my_strcasecmp(system_charset_info, host,
2450                           grant_name->host.get_host())) ||
2451           (ip && !strcmp(ip, grant_name->host.get_host())))
2452         return grant_name;
2453     }
2454     else
2455     {
2456       if (grant_name->host.compare_hostname(host, ip) &&
2457           (!found || found->sort < grant_name->sort))
2458         found=grant_name;                                       // Host ok
2459     }
2460   }
2461   return found;
2462 }
2463 
2464 
2465 /* Free grant array if possible */
2466 
grant_free(void)2467 void  grant_free(void)
2468 {
2469   DBUG_ENTER("grant_free");
2470   my_hash_free(&column_priv_hash);
2471   my_hash_free(&proc_priv_hash);
2472   my_hash_free(&func_priv_hash);
2473   free_root(&memex,MYF(0));
2474   DBUG_VOID_RETURN;
2475 }
2476 
2477 
2478 /**
2479   @brief Initialize structures responsible for table/column-level privilege
2480    checking and load information for them from tables in the 'mysql' database.
2481 
2482   @param skip_grant_tables  true if the command line option
2483     --skip-grant-tables is specified, else false.
2484 
2485   @return Error status
2486     @retval false OK
2487     @retval true  Could not initialize grant subsystem.
2488 */
2489 
grant_init(bool skip_grant_tables)2490 bool grant_init(bool skip_grant_tables)
2491 {
2492   THD  *thd;
2493   my_bool return_val;
2494   DBUG_ENTER("grant_init");
2495 
2496   if (skip_grant_tables)
2497     DBUG_RETURN(false);
2498 
2499   if (!(thd= new THD))
2500     DBUG_RETURN(1);                             /* purecov: deadcode */
2501   thd->thread_stack= (char*) &thd;
2502   thd->store_globals();
2503 
2504   return_val=  grant_reload(thd);
2505 
2506   if (return_val && thd->get_stmt_da()->is_error())
2507     sql_print_error("Fatal: can't initialize grant subsystem - '%s'",
2508                     thd->get_stmt_da()->message_text());
2509 
2510   thd->release_resources();
2511   delete thd;
2512 
2513   DBUG_RETURN(return_val);
2514 }
2515 
2516 
2517 /**
2518   @brief Helper function to grant_reload
2519 
2520   Reads the procs_priv table into memory hash.
2521 
2522   @param table A pointer to the procs_priv table structure.
2523 
2524   @see grant_reload
2525 
2526   @return Error state
2527     @retval TRUE An error occurred
2528     @retval FALSE Success
2529 */
2530 
grant_load_procs_priv(TABLE * p_table)2531 static my_bool grant_load_procs_priv(TABLE *p_table)
2532 {
2533   MEM_ROOT *memex_ptr;
2534   my_bool return_val= 1;
2535   int error;
2536   bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
2537   MEM_ROOT **save_mem_root_ptr= my_thread_get_THR_MALLOC();
2538   DBUG_ENTER("grant_load_procs_priv");
2539   (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
2540                       0,0,0, (my_hash_get_key) get_grant_table,
2541                       0, 0, key_memory_acl_memex);
2542   (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
2543                       0,0,0, (my_hash_get_key) get_grant_table,
2544                       0, 0, key_memory_acl_memex);
2545   error= p_table->file->ha_index_init(0, 1);
2546   if (error)
2547   {
2548     acl_print_ha_error(p_table, error);
2549     DBUG_RETURN(true);
2550   }
2551   p_table->use_all_columns();
2552 
2553   error= p_table->file->ha_index_first(p_table->record[0]);
2554   DBUG_EXECUTE_IF("se_error_grant_load_procs_read",
2555                   error= HA_ERR_LOCK_WAIT_TIMEOUT;);
2556   if (error)
2557   {
2558     if (error == HA_ERR_END_OF_FILE)
2559       return_val= 0; // Return Ok.
2560     else
2561       acl_print_ha_error(p_table, error);
2562   }
2563   else
2564   {
2565     memex_ptr= &memex;
2566     my_thread_set_THR_MALLOC(&memex_ptr);
2567     do
2568     {
2569       GRANT_NAME *mem_check;
2570       HASH *hash;
2571       if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE)))
2572       {
2573         /* This could only happen if we are out memory */
2574         goto end_unlock;
2575       }
2576 
2577       if (check_no_resolve)
2578       {
2579         if (hostname_requires_resolving(mem_check->host.get_host()))
2580         {
2581           sql_print_warning("'procs_priv' entry '%s %s@%s' "
2582                             "ignored in --skip-name-resolve mode.",
2583                             mem_check->tname, mem_check->user,
2584                             mem_check->host.get_host());
2585         }
2586       }
2587       if (p_table->field[4]->val_int() == SP_TYPE_PROCEDURE)
2588       {
2589         hash= &proc_priv_hash;
2590       }
2591       else
2592       if (p_table->field[4]->val_int() == SP_TYPE_FUNCTION)
2593       {
2594         hash= &func_priv_hash;
2595       }
2596       else
2597       {
2598         sql_print_warning("'procs_priv' entry '%s' "
2599                           "ignored, bad routine type",
2600                           mem_check->tname);
2601         continue;
2602       }
2603 
2604       mem_check->privs= fix_rights_for_procedure(mem_check->privs);
2605       if (! mem_check->ok())
2606         delete mem_check;
2607       else if (my_hash_insert(hash, (uchar*) mem_check))
2608       {
2609         delete mem_check;
2610         goto end_unlock;
2611       }
2612       error= p_table->file->ha_index_next(p_table->record[0]);
2613       DBUG_EXECUTE_IF("se_error_grant_load_procs_read_next",
2614                       error= HA_ERR_LOCK_WAIT_TIMEOUT;);
2615       if (error)
2616       {
2617         if (error == HA_ERR_END_OF_FILE)
2618           return_val= 0;
2619         else
2620           acl_print_ha_error(p_table, error);
2621         goto end_unlock;
2622       }
2623     }
2624     while (true);
2625   }
2626 
2627 end_unlock:
2628   p_table->file->ha_index_end();
2629   my_thread_set_THR_MALLOC(save_mem_root_ptr);
2630   DBUG_RETURN(return_val);
2631 }
2632 
2633 
2634 /**
2635   @brief Initialize structures responsible for table/column-level privilege
2636     checking and load information about grants from open privilege tables.
2637 
2638   @param thd Current thread
2639   @param tables List containing open "mysql.tables_priv" and
2640     "mysql.columns_priv" tables.
2641 
2642   @see grant_reload
2643 
2644   @return Error state
2645     @retval FALSE Success
2646     @retval TRUE Error
2647 */
2648 
grant_load(THD * thd,TABLE_LIST * tables)2649 static my_bool grant_load(THD *thd, TABLE_LIST *tables)
2650 {
2651   MEM_ROOT *memex_ptr;
2652   my_bool return_val= 1;
2653   int error;
2654   TABLE *t_table= 0, *c_table= 0;
2655   bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
2656   MEM_ROOT **save_mem_root_ptr= my_thread_get_THR_MALLOC();
2657   sql_mode_t old_sql_mode= thd->variables.sql_mode;
2658   DBUG_ENTER("grant_load");
2659 
2660   thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
2661 
2662   (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
2663                       0,0,0, (my_hash_get_key) get_grant_table,
2664                       (my_hash_free_key) free_grant_table,0,
2665                       key_memory_acl_memex);
2666 
2667   t_table = tables[0].table;
2668   c_table = tables[1].table;
2669   error= t_table->file->ha_index_init(0, 1);
2670   if (error)
2671   {
2672     acl_print_ha_error(t_table, error);
2673     goto end_index_init;
2674   }
2675   t_table->use_all_columns();
2676   c_table->use_all_columns();
2677 
2678   error= t_table->file->ha_index_first(t_table->record[0]);
2679   DBUG_EXECUTE_IF("se_error_grant_load_read",
2680                   error= HA_ERR_LOCK_WAIT_TIMEOUT;);
2681   if (error)
2682   {
2683     if (error == HA_ERR_END_OF_FILE)
2684       return_val= 0; // Return Ok.
2685     else
2686       acl_print_ha_error(t_table, error);
2687   }
2688   else
2689   {
2690     memex_ptr= &memex;
2691     my_thread_set_THR_MALLOC(&memex_ptr);
2692     do
2693     {
2694       GRANT_TABLE *mem_check;
2695       mem_check= new (memex_ptr) GRANT_TABLE(t_table);
2696 
2697       if (!mem_check)
2698       {
2699         /* This could only happen if we are out memory */
2700         goto end_unlock;
2701       }
2702 
2703       if (mem_check->init(c_table))
2704       {
2705         delete mem_check;
2706         goto end_unlock;
2707       }
2708 
2709       if (check_no_resolve)
2710       {
2711         if (hostname_requires_resolving(mem_check->host.get_host()) &&
2712             !is_localhost_string(mem_check->host.get_host())) {
2713           sql_print_warning("'tables_priv' entry '%s %s@%s' "
2714                             "ignored in --skip-name-resolve mode.",
2715                             mem_check->tname,
2716                             mem_check->user ? mem_check->user : "",
2717                             mem_check->host.get_host());
2718         }
2719       }
2720 
2721       if (! mem_check->ok())
2722         delete mem_check;
2723       else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check))
2724       {
2725         delete mem_check;
2726         goto end_unlock;
2727       }
2728       error= t_table->file->ha_index_next(t_table->record[0]);
2729       DBUG_EXECUTE_IF("se_error_grant_load_read_next",
2730                       error= HA_ERR_LOCK_WAIT_TIMEOUT;);
2731       if (error)
2732       {
2733         if (error != HA_ERR_END_OF_FILE)
2734           acl_print_ha_error(t_table, error);
2735         else
2736           return_val= 0;
2737         goto end_unlock;
2738       }
2739 
2740     }
2741     while (true);
2742   }
2743 
2744 end_unlock:
2745   t_table->file->ha_index_end();
2746   my_thread_set_THR_MALLOC(save_mem_root_ptr);
2747 end_index_init:
2748   thd->variables.sql_mode= old_sql_mode;
2749   DBUG_RETURN(return_val);
2750 }
2751 
2752 
2753 /**
2754   @brief Helper function to grant_reload. Reloads procs_priv table is it
2755     exists.
2756 
2757   @param thd A pointer to the thread handler object.
2758   @param table A pointer to the table list.
2759 
2760   @see grant_reload
2761 
2762   @return Error state
2763     @retval FALSE Success
2764     @retval TRUE An error has occurred.
2765 */
2766 
grant_reload_procs_priv(THD * thd,TABLE_LIST * table)2767 static my_bool grant_reload_procs_priv(THD *thd, TABLE_LIST *table)
2768 {
2769   HASH old_proc_priv_hash, old_func_priv_hash;
2770   my_bool return_val= FALSE;
2771   DBUG_ENTER("grant_reload_procs_priv");
2772 
2773   /* Save a copy of the current hash if we need to undo the grant load */
2774   old_proc_priv_hash= proc_priv_hash;
2775   old_func_priv_hash= func_priv_hash;
2776 
2777   if ((return_val= grant_load_procs_priv(table->table)))
2778   {
2779     /* Error; Reverting to old hash */
2780     DBUG_PRINT("error",("Reverting to old privileges"));
2781     my_hash_free(&proc_priv_hash);
2782     my_hash_free(&func_priv_hash);
2783     proc_priv_hash= old_proc_priv_hash;
2784     func_priv_hash= old_func_priv_hash;
2785   }
2786   else
2787   {
2788     my_hash_free(&old_proc_priv_hash);
2789     my_hash_free(&old_func_priv_hash);
2790   }
2791 
2792   DBUG_RETURN(return_val);
2793 }
2794 
2795 
2796 /**
2797   @brief Reload information about table and column level privileges if possible
2798 
2799   @param thd Current thread
2800 
2801   Locked tables are checked by acl_reload() and doesn't have to be checked
2802   in this call.
2803   This function is also used for initialization of structures responsible
2804   for table/column-level privilege checking.
2805 
2806   @return Error state
2807     @retval FALSE Success
2808     @retval TRUE  Error
2809 */
2810 
grant_reload(THD * thd)2811 my_bool grant_reload(THD *thd)
2812 {
2813   TABLE_LIST tables[3];
2814   HASH old_column_priv_hash;
2815   MEM_ROOT old_mem;
2816   my_bool return_val= 1;
2817   DBUG_ENTER("grant_reload");
2818 
2819   /* Don't do anything if running with --skip-grant-tables */
2820   if (!initialized)
2821     DBUG_RETURN(0);
2822 
2823   tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
2824                            C_STRING_WITH_LEN("tables_priv"),
2825                            "tables_priv", TL_READ);
2826   tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
2827                            C_STRING_WITH_LEN("columns_priv"),
2828                            "columns_priv", TL_READ);
2829   tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
2830                            C_STRING_WITH_LEN("procs_priv"),
2831                            "procs_priv", TL_READ);
2832 
2833   tables[0].next_local= tables[0].next_global= tables+1;
2834   tables[1].next_local= tables[1].next_global= tables+2;
2835   tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
2836 
2837   /*
2838     Reload will work in the following manner:-
2839 
2840                              proc_priv_hash structure
2841                               /                     \
2842                     not initialized                 initialized
2843                    /               \                     |
2844     mysql.procs_priv table        Server Startup         |
2845         is missing                      \                |
2846              |                         open_and_lock_tables()
2847     Assume we are working on           /success             \failure
2848     pre 4.1 system tables.        Normal Scenario.          An error is thrown.
2849     A warning is printed          Reload column privilege.  Retain the old hash.
2850     and continue with             Reload function and
2851     reloading the column          procedure privileges,
2852     privileges.                   if available.
2853   */
2854 
2855   if (!(my_hash_inited(&proc_priv_hash)))
2856     tables[2].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
2857 
2858   /*
2859     To avoid deadlocks we should obtain table locks before
2860     obtaining LOCK_grant rwlock.
2861   */
2862   if (open_and_lock_tables(thd, tables, MYSQL_LOCK_IGNORE_TIMEOUT))
2863   {
2864     if (thd->get_stmt_da()->is_error())
2865     {
2866       sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
2867                       thd->get_stmt_da()->message_text());
2868     }
2869     goto end;
2870   }
2871 
2872   if (tables[2].table == NULL)
2873   {
2874     sql_print_warning("Table 'mysql.procs_priv' does not exist. "
2875                       "Please run mysql_upgrade.");
2876     push_warning_printf(thd, Sql_condition::SL_WARNING, ER_NO_SUCH_TABLE,
2877                         ER(ER_NO_SUCH_TABLE), tables[2].db,
2878                         tables[2].table_name);
2879   }
2880 
2881   LOCK_grant.wrlock();
2882 
2883   /* Save a copy of the current hash if we need to undo the grant load */
2884   old_column_priv_hash= column_priv_hash;
2885 
2886   /*
2887     Create a new memory pool but save the current memory pool to make an undo
2888     opertion possible in case of failure.
2889   */
2890   old_mem= memex;
2891   init_sql_alloc(key_memory_acl_memex,
2892                  &memex, ACL_ALLOC_BLOCK_SIZE, 0);
2893   /*
2894     tables[2].table i.e. procs_priv can be null if we are working with
2895     pre 4.1 privilage tables
2896   */
2897   if ((return_val= (grant_load(thd, tables) ||
2898                     (tables[2].table != NULL &&
2899                      grant_reload_procs_priv(thd, &tables[2])))
2900      ))
2901   {                                             // Error. Revert to old hash
2902     DBUG_PRINT("error",("Reverting to old privileges"));
2903     my_hash_free(&column_priv_hash);
2904     free_root(&memex,MYF(0));
2905     column_priv_hash= old_column_priv_hash;     /* purecov: deadcode */
2906     memex= old_mem;                             /* purecov: deadcode */
2907   }
2908   else
2909   {                                             //Reload successful
2910     my_hash_free(&old_column_priv_hash);
2911     free_root(&old_mem,MYF(0));
2912     grant_version++;
2913   }
2914   LOCK_grant.wrunlock();
2915 
2916 end:
2917   close_acl_tables(thd);
2918   DBUG_RETURN(return_val);
2919 }
2920 
2921 
acl_update_user(const char * user,const char * host,enum SSL_type ssl_type,const char * ssl_cipher,const char * x509_issuer,const char * x509_subject,USER_RESOURCES * mqh,ulong privileges,const LEX_CSTRING & plugin,const LEX_CSTRING & auth,MYSQL_TIME password_change_time,LEX_ALTER password_life,ulong what_is_set)2922 void acl_update_user(const char *user, const char *host,
2923                      enum SSL_type ssl_type,
2924                      const char *ssl_cipher,
2925                      const char *x509_issuer,
2926                      const char *x509_subject,
2927                      USER_RESOURCES  *mqh,
2928                      ulong privileges,
2929                      const LEX_CSTRING &plugin,
2930                      const LEX_CSTRING &auth,
2931 		     MYSQL_TIME password_change_time,
2932                      LEX_ALTER password_life,
2933                      ulong what_is_set)
2934 {
2935   DBUG_ENTER("acl_update_user");
2936   mysql_mutex_assert_owner(&acl_cache->lock);
2937   for (ACL_USER *acl_user= acl_users->begin();
2938        acl_user != acl_users->end(); ++acl_user)
2939   {
2940     if ((!acl_user->user && !user[0]) ||
2941         (acl_user->user && !strcmp(user,acl_user->user)))
2942     {
2943       if ((acl_user->host.is_null() && !host[0]) ||
2944           (!acl_user->host.is_null() &&
2945            !my_strcasecmp(system_charset_info, host, acl_user->host.get_host())))
2946       {
2947         if (plugin.length > 0)
2948         {
2949           acl_user->plugin.str= plugin.str;
2950           acl_user->plugin.length = plugin.length;
2951           optimize_plugin_compare_by_pointer(&acl_user->plugin);
2952           if (!auth_plugin_is_built_in(acl_user->plugin.str))
2953             acl_user->plugin.str= strmake_root(&global_acl_memory,
2954                                                plugin.str, plugin.length);
2955           /* Update auth string only when specified in ALTER/GRANT */
2956           if (auth.str)
2957           {
2958             if (auth.length == 0)
2959               acl_user->auth_string.str= const_cast<char*>("");
2960             else
2961               acl_user->auth_string.str= strmake_root(&global_acl_memory,
2962                               auth.str, auth.length);
2963             acl_user->auth_string.length= auth.length;
2964             set_user_salt(acl_user);
2965             if (password_change_time.time_type != MYSQL_TIMESTAMP_ERROR)
2966               acl_user->password_last_changed= password_change_time;
2967           }
2968         }
2969         acl_user->access=privileges;
2970         if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
2971           acl_user->user_resource.questions=mqh->questions;
2972         if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
2973           acl_user->user_resource.updates=mqh->updates;
2974         if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
2975           acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
2976         if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
2977           acl_user->user_resource.user_conn= mqh->user_conn;
2978         if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
2979         {
2980           acl_user->ssl_type= ssl_type;
2981           acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&global_acl_memory,
2982                                                     ssl_cipher) :        0);
2983           acl_user->x509_issuer= (x509_issuer ? strdup_root(&global_acl_memory,
2984                                                       x509_issuer) : 0);
2985           acl_user->x509_subject= (x509_subject ?
2986                                    strdup_root(&global_acl_memory, x509_subject) : 0);
2987         }
2988         /* update details related to password lifetime, password expiry */
2989         if (password_life.update_password_expired_column ||
2990             what_is_set & PLUGIN_ATTR)
2991           acl_user->password_expired= password_life.update_password_expired_column;
2992         if (!password_life.update_password_expired_column &&
2993             password_life.update_password_expired_fields)
2994         {
2995           if (!password_life.use_default_password_lifetime)
2996           {
2997             acl_user->password_lifetime= password_life.expire_after_days;
2998             acl_user->use_default_password_lifetime= false;
2999           }
3000           else
3001             acl_user->use_default_password_lifetime= true;
3002         }
3003 
3004         if (password_life.update_account_locked_column)
3005         {
3006           acl_user->account_locked = password_life.account_locked;
3007         }
3008 
3009         /* search complete: */
3010         break;
3011       }
3012     }
3013   }
3014   DBUG_VOID_RETURN;
3015 }
3016 
3017 
acl_insert_user(const char * user,const char * host,enum SSL_type ssl_type,const char * ssl_cipher,const char * x509_issuer,const char * x509_subject,USER_RESOURCES * mqh,ulong privileges,const LEX_CSTRING & plugin,const LEX_CSTRING & auth,MYSQL_TIME password_change_time,LEX_ALTER password_life)3018 void acl_insert_user(const char *user, const char *host,
3019                      enum SSL_type ssl_type,
3020                      const char *ssl_cipher,
3021                      const char *x509_issuer,
3022                      const char *x509_subject,
3023                      USER_RESOURCES *mqh,
3024                      ulong privileges,
3025                      const LEX_CSTRING &plugin,
3026                      const LEX_CSTRING &auth,
3027 		     MYSQL_TIME password_change_time,
3028                      LEX_ALTER password_life)
3029 {
3030   DBUG_ENTER("acl_insert_user");
3031   ACL_USER acl_user;
3032 
3033   mysql_mutex_assert_owner(&acl_cache->lock);
3034   /*
3035      All accounts can authenticate per default. This will change when
3036      we add a new field to the user table.
3037 
3038      Currently this flag is only set to false when authentication is attempted
3039      using an unknown user name.
3040   */
3041   acl_user.can_authenticate= true;
3042 
3043   acl_user.user= *user ? strdup_root(&global_acl_memory,user) : 0;
3044   acl_user.host.update_hostname(*host ? strdup_root(&global_acl_memory, host) : 0);
3045   if (plugin.str[0])
3046   {
3047     acl_user.plugin= plugin;
3048     optimize_plugin_compare_by_pointer(&acl_user.plugin);
3049     if (!auth_plugin_is_built_in(acl_user.plugin.str))
3050       acl_user.plugin.str= strmake_root(&global_acl_memory,
3051                                         plugin.str, plugin.length);
3052     acl_user.auth_string.str= auth.str ?
3053       strmake_root(&global_acl_memory, auth.str,
3054                    auth.length) : const_cast<char*>("");
3055     acl_user.auth_string.length= auth.length;
3056 
3057     optimize_plugin_compare_by_pointer(&acl_user.plugin);
3058   }
3059   else
3060   {
3061     acl_user.plugin= native_password_plugin_name;
3062     acl_user.auth_string.str= const_cast<char*>("");
3063     acl_user.auth_string.length= 0;
3064   }
3065 
3066   acl_user.access= privileges;
3067   acl_user.user_resource= *mqh;
3068   acl_user.sort= get_sort(2,acl_user.host.get_host(), acl_user.user);
3069   //acl_user.hostname_length=(uint) strlen(host);
3070   acl_user.ssl_type=
3071     (ssl_type != SSL_TYPE_NOT_SPECIFIED ? ssl_type : SSL_TYPE_NONE);
3072   acl_user.ssl_cipher=
3073     ssl_cipher ? strdup_root(&global_acl_memory, ssl_cipher) : 0;
3074   acl_user.x509_issuer=
3075     x509_issuer ? strdup_root(&global_acl_memory, x509_issuer) : 0;
3076   acl_user.x509_subject=
3077     x509_subject ? strdup_root(&global_acl_memory, x509_subject) : 0;
3078   /* update details related to password lifetime, password expiry */
3079   acl_user.password_expired= password_life.update_password_expired_column;
3080   acl_user.password_lifetime= password_life.expire_after_days;
3081   acl_user.use_default_password_lifetime= password_life.use_default_password_lifetime;
3082   acl_user.password_last_changed= password_change_time;
3083   acl_user.account_locked= password_life.account_locked;
3084 
3085   set_user_salt(&acl_user);
3086 
3087   acl_users->push_back(acl_user);
3088   if (acl_user.host.check_allow_all_hosts())
3089     allow_all_hosts=1;          // Anyone can connect /* purecov: tested */
3090   std::sort(acl_users->begin(), acl_users->end(), ACL_compare());
3091 
3092   /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
3093   rebuild_check_host();
3094   DBUG_VOID_RETURN;
3095 }
3096 
3097 
acl_update_proxy_user(ACL_PROXY_USER * new_value,bool is_revoke)3098 void acl_update_proxy_user(ACL_PROXY_USER *new_value, bool is_revoke)
3099 {
3100   mysql_mutex_assert_owner(&acl_cache->lock);
3101 
3102   DBUG_ENTER("acl_update_proxy_user");
3103   for (ACL_PROXY_USER *acl_user= acl_proxy_users->begin();
3104        acl_user != acl_proxy_users->end(); ++acl_user)
3105   {
3106     if (acl_user->pk_equals(new_value))
3107     {
3108       if (is_revoke)
3109       {
3110         DBUG_PRINT("info", ("delting ACL_PROXY_USER"));
3111         acl_proxy_users->erase(acl_user);
3112       }
3113       else
3114       {
3115         DBUG_PRINT("info", ("updating ACL_PROXY_USER"));
3116         acl_user->set_data(new_value);
3117       }
3118       break;
3119     }
3120   }
3121   DBUG_VOID_RETURN;
3122 }
3123 
3124 
acl_update_db(const char * user,const char * host,const char * db,ulong privileges)3125 void acl_update_db(const char *user, const char *host, const char *db,
3126                    ulong privileges)
3127 {
3128   mysql_mutex_assert_owner(&acl_cache->lock);
3129 
3130   for (ACL_DB *acl_db= acl_dbs->begin(); acl_db < acl_dbs->end(); )
3131   {
3132     if ((!acl_db->user && !user[0]) ||
3133         (acl_db->user &&
3134         !strcmp(user,acl_db->user)))
3135     {
3136       if ((acl_db->host.is_null() && !host[0]) ||
3137           (acl_db->host.get_host_len() &&
3138           !strcmp(host, acl_db->host.get_host())))
3139       {
3140         if ((!acl_db->db && !db[0]) ||
3141             (acl_db->db && !strcmp(db,acl_db->db)))
3142         {
3143           if (privileges)
3144             acl_db->access=privileges;
3145           else
3146           {
3147             acl_db= acl_dbs->erase(acl_db);
3148             // Don't increment loop variable.
3149             continue;
3150           }
3151         }
3152       }
3153     }
3154     ++acl_db;
3155   }
3156 }
3157 
3158 
3159 /*
3160   Insert a user/db/host combination into the global acl_cache
3161 
3162   SYNOPSIS
3163     acl_insert_db()
3164     user                User name
3165     host                Host name
3166     db                  Database name
3167     privileges          Bitmap of privileges
3168 
3169   NOTES
3170     acl_cache->lock must be locked when calling this
3171 */
3172 
acl_insert_db(const char * user,const char * host,const char * db,ulong privileges)3173 void acl_insert_db(const char *user, const char *host, const char *db,
3174                    ulong privileges)
3175 {
3176   ACL_DB acl_db;
3177   mysql_mutex_assert_owner(&acl_cache->lock);
3178   acl_db.user= strdup_root(&global_acl_memory,user);
3179   acl_db.host.update_hostname(*host ? strdup_root(&global_acl_memory, host) : 0);
3180   acl_db.db= strdup_root(&global_acl_memory, db);
3181   acl_db.access= privileges;
3182   acl_db.sort= get_sort(3,acl_db.host.get_host(), acl_db.db, acl_db.user);
3183   acl_dbs->push_back(acl_db);
3184   std::sort(acl_dbs->begin(), acl_dbs->end(), ACL_compare());
3185 }
3186 
3187 
get_mqh(const char * user,const char * host,USER_CONN * uc)3188 void get_mqh(const char *user, const char *host, USER_CONN *uc)
3189 {
3190   ACL_USER *acl_user;
3191 
3192   mysql_mutex_lock(&acl_cache->lock);
3193 
3194   if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
3195     uc->user_resources= acl_user->user_resource;
3196   else
3197     memset(&uc->user_resources, 0, sizeof(uc->user_resources));
3198 
3199   mysql_mutex_unlock(&acl_cache->lock);
3200 }
3201 
3202 
3203 
3204 /**
3205   Update the security context when updating the user
3206 
3207   Helper function.
3208   Update only if the security context is pointing to the same user and
3209   the user is not a proxied user for a different proxy user.
3210   And return true if the update happens (i.e. we're operating on the
3211   user account of the current user).
3212   Normalize the names for a safe compare.
3213 
3214   @param sctx           The security context to update
3215   @param acl_user_ptr   User account being updated
3216   @param expired        new value of the expiration flag
3217   @return               did the update happen ?
3218  */
3219 bool
update_sctx_cache(Security_context * sctx,ACL_USER * acl_user_ptr,bool expired)3220 update_sctx_cache(Security_context *sctx, ACL_USER *acl_user_ptr, bool expired)
3221 {
3222   const char *acl_host= acl_user_ptr->host.get_host();
3223   const char *acl_user= acl_user_ptr->user;
3224   const char *sctx_user= sctx->priv_user().str;
3225   const char *sctx_host= sctx->priv_host().str;
3226 
3227   /* If the user is connected as a proxied user, verify against proxy user */
3228   if (sctx->proxy_user().str && *sctx->proxy_user().str != '\0')
3229   {
3230     sctx_user = sctx->user().str;
3231   }
3232 
3233   if(!acl_user)
3234     acl_user= "";
3235   if (!sctx_host)
3236     sctx_host= "";
3237   if (!sctx_user)
3238     sctx_user= "";
3239 
3240   if (!strcmp(acl_user, sctx_user) && !strcmp(acl_host, sctx_host))
3241   {
3242     sctx->set_password_expired(expired);
3243     return true;
3244   }
3245 
3246   return false;
3247 }
3248 
3249 #else
3250 
acl_is_utility_user(const char * user,const char * host,const char * ip)3251 bool acl_is_utility_user(const char *user, const char *host,
3252                          const char *ip)
3253 {
3254   return false;
3255 }
3256 
3257 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
3258 
3259