1 /* Copyright (c) 2000, 2020, 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 #ifndef SQL_USER_CACHE_INCLUDED
23 #define SQL_USER_CACHE_INCLUDED
24 
25 #include <string.h>
26 #include <sys/types.h>
27 #include <atomic>
28 #include <boost/graph/adjacency_list.hpp>
29 #include <boost/graph/graph_selectors.hpp>
30 #include <boost/graph/graph_traits.hpp>
31 #include <boost/graph/properties.hpp>
32 #include <boost/pending/property.hpp>
33 #include <list>
34 #include <memory>
35 #include <string>
36 #include <unordered_map>
37 
38 #include "lex_string.h"
39 #include "lf.h"
40 #include "m_ctype.h"
41 #include "map_helpers.h"
42 #include "mf_wcomp.h"  // wild_many, wild_one, wild_prefix
43 #include "my_alloc.h"
44 #include "my_compiler.h"
45 #include "my_inttypes.h"
46 #include "my_sharedlib.h"
47 #include "my_sys.h"
48 #include "mysql/components/services/mysql_mutex_bits.h"
49 #include "mysql/mysql_lex_string.h"
50 #include "mysql_com.h"   // SCRAMBLE_LENGTH
51 #include "mysql_time.h"  // MYSQL_TIME
52 #include "sql/auth/auth_common.h"
53 #include "sql/auth/auth_internal.h"  // List_of_authid, Authid
54 #include "sql/auth/partial_revokes.h"
55 #include "sql/malloc_allocator.h"
56 #include "sql/psi_memory_key.h"
57 #include "sql/sql_connect.h"  // USER_RESOURCES
58 #include "violite.h"          // SSL_type
59 
60 /* Forward declarations */
61 class Security_context;
62 class String;
63 class THD;
64 struct TABLE;
65 template <typename Element_type, size_t Prealloc>
66 class Prealloced_array;
67 class Acl_restrictions;
68 enum class Lex_acl_attrib_udyn;
69 
70 /* Classes */
71 
72 class ACL_HOST_AND_IP {
73   const char *hostname;
74   size_t hostname_length;
75   long ip, ip_mask;  // Used with masked ip:s
76 
77   const char *calc_ip(const char *ip_arg, long *val, char end);
78 
79  public:
ACL_HOST_AND_IP()80   ACL_HOST_AND_IP()
81       : hostname(nullptr), hostname_length(0), ip(0), ip_mask(0) {}
get_host()82   const char *get_host() const { return hostname ? hostname : ""; }
get_host_len()83   size_t get_host_len() const { return hostname_length; }
84 
has_wildcard()85   bool has_wildcard() {
86     return (strchr(get_host(), wild_many) || strchr(get_host(), wild_one) ||
87             ip_mask);
88   }
89 
check_allow_all_hosts()90   bool check_allow_all_hosts() {
91     return (!hostname || (hostname[0] == wild_many && !hostname[1]));
92   }
93 
94   void update_hostname(const char *host_arg);
95 
96   bool compare_hostname(const char *host_arg, const char *ip_arg);
97 };
98 
99 class ACL_ACCESS {
100  public:
ACL_ACCESS()101   ACL_ACCESS() : host(), sort(0), access(0) {}
102   ACL_HOST_AND_IP host;
103   ulong sort;
104   ulong access;
105 };
106 
107 class ACL_compare {
108  public:
109   bool operator()(const ACL_ACCESS &a, const ACL_ACCESS &b);
110   bool operator()(const ACL_ACCESS *a, const ACL_ACCESS *b);
111 };
112 
113 /* ACL_HOST is used if no host is specified */
114 
115 class ACL_HOST : public ACL_ACCESS {
116  public:
117   char *db;
118 };
119 
120 #define NUM_CREDENTIALS 2
121 #define PRIMARY_CRED (NUM_CREDENTIALS - NUM_CREDENTIALS)
122 #define SECOND_CRED (PRIMARY_CRED + 1)
123 
124 class Acl_credential {
125  public:
Acl_credential()126   Acl_credential() {
127     m_auth_string = {"", 0};
128     memset(m_salt, 0, SCRAMBLE_LENGTH + 1);
129     m_salt_len = 0;
130   }
131 
132  public:
133   LEX_CSTRING m_auth_string;
134   /**
135     The salt variable is used as the password hash for
136     native_password_authetication.
137   */
138   uint8 m_salt[SCRAMBLE_LENGTH + 1];  // scrambled password in binary form
139   /**
140     In the old protocol the salt_len indicated what type of autnetication
141     protocol was used: 0 - no password, 4 - 3.20, 8 - 4.0,  20 - 4.1.1
142   */
143   uint8 m_salt_len;
144 };
145 
146 class ACL_USER : public ACL_ACCESS {
147  public:
148   USER_RESOURCES user_resource;
149   char *user;
150   enum SSL_type ssl_type;
151   const char *ssl_cipher, *x509_issuer, *x509_subject;
152   LEX_CSTRING plugin;
153   bool password_expired;
154   bool can_authenticate;
155   MYSQL_TIME password_last_changed;
156   uint password_lifetime;
157   bool use_default_password_lifetime;
158   /**
159     Specifies whether the user account is locked or unlocked.
160   */
161   bool account_locked;
162   /**
163    If this ACL_USER was used as a role id then this flag is true.
164    During RENAME USER this variable is used for determining if it is safe
165    to rename the user or not.
166   */
167   bool is_role;
168 
169   /**
170     The number of old passwords to check when setting a new password
171   */
172   uint32 password_history_length;
173 
174   /**
175     Ignore @ref password_history_length,
176     use the global default @ref global_password_history
177   */
178   bool use_default_password_history;
179 
180   /**
181     The number of days that would have to pass before a password can be reused.
182   */
183   uint32 password_reuse_interval;
184   /**
185     Ignore @ref password_reuse_interval,
186     use the global default @ref global_password_reuse_interval
187   */
188   bool use_default_password_reuse_interval;
189 
190   /**
191     The current password needed to be specified while changing it.
192   */
193   Lex_acl_attrib_udyn password_require_current;
194 
195   /**
196     Additional credentials
197   */
198   Acl_credential credentials[NUM_CREDENTIALS];
199 
200   ACL_USER *copy(MEM_ROOT *root);
201   ACL_USER();
202 
203   void set_user(MEM_ROOT *mem, const char *user_arg);
204   void set_host(MEM_ROOT *mem, const char *host_arg);
get_username_length()205   size_t get_username_length() const { return user ? strlen(user) : 0; }
206   class Password_locked_state {
207    public:
is_active()208     bool is_active() const {
209       return m_password_lock_time_days != 0 && m_failed_login_attempts != 0;
210     }
get_password_lock_time_days()211     int get_password_lock_time_days() const {
212       return m_password_lock_time_days;
213     }
get_failed_login_attempts()214     uint get_failed_login_attempts() const { return m_failed_login_attempts; }
215     void set_parameters(uint password_lock_time_days,
216                         uint failed_login_attempts);
217     bool update(THD *thd, bool successful_login, long *ret_days_remaining);
Password_locked_state()218     Password_locked_state()
219         : m_password_lock_time_days(0),
220           m_failed_login_attempts(0),
221           m_remaining_login_attempts(0),
222           m_daynr_locked(0) {}
223 
224    protected:
225     /**
226       read from the user config. The number of days to keep the accont locked
227     */
228     int m_password_lock_time_days;
229     /**
230       read from the user config. The number of failed login attemps before the
231       account is locked
232     */
233     uint m_failed_login_attempts;
234     /**
235       The remaining login tries, valid ony if @ref m_failed_login_attempts and
236       @ref m_password_lock_time_days are non-zero
237     */
238     uint m_remaining_login_attempts;
239     /** The day the account is locked, 0 if not locked */
240     long m_daynr_locked;
241   } password_locked_state;
242 };
243 
244 class ACL_DB : public ACL_ACCESS {
245  public:
246   char *user, *db;
247 
248   void set_user(MEM_ROOT *mem, const char *user_arg);
249   void set_host(MEM_ROOT *mem, const char *host_arg);
250 };
251 
252 class ACL_PROXY_USER : public ACL_ACCESS {
253   const char *user;
254   ACL_HOST_AND_IP proxied_host;
255   const char *proxied_user;
256   bool with_grant;
257 
258   typedef enum {
259     MYSQL_PROXIES_PRIV_HOST,
260     MYSQL_PROXIES_PRIV_USER,
261     MYSQL_PROXIES_PRIV_PROXIED_HOST,
262     MYSQL_PROXIES_PRIV_PROXIED_USER,
263     MYSQL_PROXIES_PRIV_WITH_GRANT,
264     MYSQL_PROXIES_PRIV_GRANTOR,
265     MYSQL_PROXIES_PRIV_TIMESTAMP
266   } old_acl_proxy_users;
267 
268  public:
ACL_PROXY_USER()269   ACL_PROXY_USER() {}
270 
271   void init(const char *host_arg, const char *user_arg,
272             const char *proxied_host_arg, const char *proxied_user_arg,
273             bool with_grant_arg);
274 
275   void init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
276             const char *proxied_host_arg, const char *proxied_user_arg,
277             bool with_grant_arg);
278 
279   void init(TABLE *table, MEM_ROOT *mem);
280 
get_with_grant()281   bool get_with_grant() { return with_grant; }
get_user()282   const char *get_user() { return user; }
get_proxied_user()283   const char *get_proxied_user() { return proxied_user; }
get_proxied_host()284   const char *get_proxied_host() { return proxied_host.get_host(); }
285   void set_user(MEM_ROOT *mem, const char *user_arg);
286   void set_host(MEM_ROOT *mem, const char *host_arg);
287 
288   bool check_validity(bool check_no_resolve);
289 
290   bool matches(const char *host_arg, const char *user_arg, const char *ip_arg,
291                const char *proxied_user_arg, bool any_proxy_user);
292 
auth_element_equals(const char * a,const char * b)293   inline static bool auth_element_equals(const char *a, const char *b) {
294     return (a == b || (a != nullptr && b != nullptr && !strcmp(a, b)));
295   }
296 
297   bool pk_equals(ACL_PROXY_USER *grant);
298 
granted_on(const char * host_arg,const char * user_arg)299   bool granted_on(const char *host_arg, const char *user_arg) {
300     return (
301         ((!user && (!user_arg || !user_arg[0])) ||
302          (user && user_arg && !strcmp(user, user_arg))) &&
303         ((!host.get_host() && (!host_arg || !host_arg[0])) ||
304          (host.get_host() && host_arg && !strcmp(host.get_host(), host_arg))));
305   }
306 
307   void print_grant(String *str);
308 
set_data(ACL_PROXY_USER * grant)309   void set_data(ACL_PROXY_USER *grant) { with_grant = grant->with_grant; }
310 
311   static int store_pk(TABLE *table, const LEX_CSTRING &host,
312                       const LEX_CSTRING &user, const LEX_CSTRING &proxied_host,
313                       const LEX_CSTRING &proxied_user);
314 
315   static int store_with_grant(TABLE *table, bool with_grant);
316 
317   static int store_data_record(TABLE *table, const LEX_CSTRING &host,
318                                const LEX_CSTRING &user,
319                                const LEX_CSTRING &proxied_host,
320                                const LEX_CSTRING &proxied_user, bool with_grant,
321                                const char *grantor);
322 };
323 
324 class acl_entry {
325  public:
326   ulong access;
327   uint16 length;
328   char key[1];  // Key will be stored here
329 };
330 
331 class GRANT_COLUMN {
332  public:
333   ulong rights;
334   std::string column;
335   GRANT_COLUMN(String &c, ulong y);
336 };
337 
338 class GRANT_NAME {
339  public:
340   ACL_HOST_AND_IP host;
341   char *db;
342   const char *user;
343   char *tname;
344   ulong privs;
345   ulong sort;
346   std::string hash_key;
347   GRANT_NAME(const char *h, const char *d, const char *u, const char *t,
348              ulong p, bool is_routine);
349   GRANT_NAME(TABLE *form, bool is_routine);
~GRANT_NAME()350   virtual ~GRANT_NAME() {}
ok()351   virtual bool ok() { return privs != 0; }
352   void set_user_details(const char *h, const char *d, const char *u,
353                         const char *t, bool is_routine);
354 };
355 
356 class GRANT_TABLE : public GRANT_NAME {
357  public:
358   ulong cols;
359   collation_unordered_multimap<std::string,
360                                unique_ptr_destroy_only<GRANT_COLUMN>>
361       hash_columns;
362 
363   GRANT_TABLE(const char *h, const char *d, const char *u, const char *t,
364               ulong p, ulong c);
365   explicit GRANT_TABLE(TABLE *form);
366   bool init(TABLE *col_privs);
367   ~GRANT_TABLE();
ok()368   bool ok() { return privs != 0 || cols != 0; }
369 };
370 
371 /*
372  * A default/no-arg constructor is useful with containers-of-containers
373  * situations in which a two-allocator scoped_allocator_adapter is not enough.
374  * This custom allocator provides a Malloc_allocator with a no-arg constructor
375  * by hard-coding the key_memory_acl_cache constructor argument.
376  * This "solution" lacks beauty, yet is pragmatic.
377  */
378 template <class T>
379 class Acl_cache_allocator : public Malloc_allocator<T> {
380  public:
Acl_cache_allocator()381   Acl_cache_allocator() : Malloc_allocator<T>(key_memory_acl_cache) {}
382   template <class U>
383   struct rebind {
384     typedef Acl_cache_allocator<U> other;
385   };
386 
387   template <class U>
Acl_cache_allocator(const Acl_cache_allocator<U> & other MY_ATTRIBUTE ((unused)))388   Acl_cache_allocator(
389       const Acl_cache_allocator<U> &other MY_ATTRIBUTE((unused)))
390       : Malloc_allocator<T>(key_memory_acl_cache) {}
391 
392   template <class U>
393   Acl_cache_allocator &operator=(
394       const Acl_cache_allocator<U> &other MY_ATTRIBUTE((unused))) {}
395 };
396 typedef Acl_cache_allocator<ACL_USER *> Acl_user_ptr_allocator;
397 typedef std::list<ACL_USER *, Acl_user_ptr_allocator> Acl_user_ptr_list;
398 Acl_user_ptr_list *cached_acl_users_for_name(const char *name);
399 void rebuild_cached_acl_users_for_name(void);
400 
401 /* Data Structures */
402 extern MEM_ROOT global_acl_memory;
403 extern MEM_ROOT memex;
404 const size_t ACL_PREALLOC_SIZE = 10U;
405 extern Prealloced_array<ACL_USER, ACL_PREALLOC_SIZE> *acl_users;
406 extern Prealloced_array<ACL_PROXY_USER, ACL_PREALLOC_SIZE> *acl_proxy_users;
407 extern Prealloced_array<ACL_DB, ACL_PREALLOC_SIZE> *acl_dbs;
408 extern Prealloced_array<ACL_HOST_AND_IP, ACL_PREALLOC_SIZE> *acl_wild_hosts;
409 extern std::unique_ptr<malloc_unordered_multimap<
410     std::string, unique_ptr_destroy_only<GRANT_TABLE>>>
411     column_priv_hash;
412 extern std::unique_ptr<
413     malloc_unordered_multimap<std::string, unique_ptr_destroy_only<GRANT_NAME>>>
414     proc_priv_hash, func_priv_hash;
415 extern collation_unordered_map<std::string, ACL_USER *> *acl_check_hosts;
416 extern bool allow_all_hosts;
417 extern uint grant_version; /* Version of priv tables */
418 extern std::unique_ptr<Acl_restrictions> acl_restrictions;
419 // Search for a matching grant. Prefer exact grants before non-exact ones.
420 
421 extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info;
422 
423 template <class T>
name_hash_search(const malloc_unordered_multimap<std::string,unique_ptr_destroy_only<T>> & name_hash,const char * host,const char * ip,const char * db,const char * user,const char * tname,bool exact,bool name_tolower)424 T *name_hash_search(
425     const malloc_unordered_multimap<std::string, unique_ptr_destroy_only<T>>
426         &name_hash,
427     const char *host, const char *ip, const char *db, const char *user,
428     const char *tname, bool exact, bool name_tolower) {
429   T *found = nullptr;
430 
431   std::string name = tname;
432   if (name_tolower) my_casedn_str(files_charset_info, &name[0]);
433   std::string key = user;
434   key.push_back('\0');
435   key.append(db);
436   key.push_back('\0');
437   key.append(name);
438   key.push_back('\0');
439 
440   auto it_range = name_hash.equal_range(key);
441   for (auto it = it_range.first; it != it_range.second; ++it) {
442     T *grant_name = it->second.get();
443     if (exact) {
444       if (!grant_name->host.get_host() ||
445           (host && !my_strcasecmp(system_charset_info, host,
446                                   grant_name->host.get_host())) ||
447           (ip && !strcmp(ip, grant_name->host.get_host())))
448         return grant_name;
449     } else {
450       if (grant_name->host.compare_hostname(host, ip) &&
451           (!found || found->sort < grant_name->sort))
452         found = grant_name;  // Host ok
453     }
454   }
455   return found;
456 }
457 
routine_hash_search(const char * host,const char * ip,const char * db,const char * user,const char * tname,bool proc,bool exact)458 inline GRANT_NAME *routine_hash_search(const char *host, const char *ip,
459                                        const char *db, const char *user,
460                                        const char *tname, bool proc,
461                                        bool exact) {
462   return name_hash_search(proc ? *proc_priv_hash : *func_priv_hash, host, ip,
463                           db, user, tname, exact, true);
464 }
465 
table_hash_search(const char * host,const char * ip,const char * db,const char * user,const char * tname,bool exact)466 inline GRANT_TABLE *table_hash_search(const char *host, const char *ip,
467                                       const char *db, const char *user,
468                                       const char *tname, bool exact) {
469   return name_hash_search(*column_priv_hash, host, ip, db, user, tname, exact,
470                           false);
471 }
472 
column_hash_search(GRANT_TABLE * t,const char * cname,size_t length)473 inline GRANT_COLUMN *column_hash_search(GRANT_TABLE *t, const char *cname,
474                                         size_t length) {
475   return find_or_nullptr(t->hash_columns, std::string(cname, length));
476 }
477 
478 /* Role management */
479 
480 /** Tag dispatch for custom Role_properties */
481 namespace boost {
482 enum vertex_acl_user_t { vertex_acl_user };
483 BOOST_INSTALL_PROPERTY(vertex, acl_user);
484 }  // namespace boost
485 
486 /**
487   Custom vertex properties used in Granted_roles_graph
488   TODO ACL_USER contains too much information. We only need global access,
489   username and hostname. If this was a POD we don't have to hold the same
490   mutex as ACL_USER.
491 */
492 typedef boost::property<boost::vertex_acl_user_t, ACL_USER,
493                         boost::property<boost::vertex_name_t, std::string>>
494     Role_properties;
495 
496 typedef boost::property<boost::edge_capacity_t, int> Role_edge_properties;
497 
498 /** A graph of all users/roles privilege inheritance */
499 typedef boost::adjacency_list<boost::setS,            // OutEdges
500                               boost::vecS,            // Vertices
501                               boost::bidirectionalS,  // Directed graph
502                               Role_properties,        // Vertex props
503                               Role_edge_properties>
504     Granted_roles_graph;
505 
506 /** The data type of a vertex in the Granted_roles_graph */
507 typedef boost::graph_traits<Granted_roles_graph>::vertex_descriptor
508     Role_vertex_descriptor;
509 
510 /** The data type of an edge in the Granted_roles_graph */
511 typedef boost::graph_traits<Granted_roles_graph>::edge_descriptor
512     Role_edge_descriptor;
513 
514 /** The datatype of the map between authids and graph vertex descriptors */
515 typedef std::unordered_map<std::string, Role_vertex_descriptor> Role_index_map;
516 
517 /** The type used for the number of edges incident to a vertex in the graph.
518  */
519 using degree_s_t = boost::graph_traits<Granted_roles_graph>::degree_size_type;
520 
521 /** The type for the iterator returned by out_edges(). */
522 using out_edge_itr_t =
523     boost::graph_traits<Granted_roles_graph>::out_edge_iterator;
524 
525 /** The type for the iterator returned by in_edges(). */
526 using in_edge_itr_t =
527     boost::graph_traits<Granted_roles_graph>::in_edge_iterator;
528 
529 /** Container for global, schema, table/view and routine ACL maps */
530 class Acl_map {
531  public:
532   Acl_map(Security_context *sctx, uint64 ver);
533   Acl_map(const Acl_map &map) = delete;
534   Acl_map(const Acl_map &&map);
535   ~Acl_map();
536 
537  private:
538   Acl_map &operator=(const Acl_map &map);
539 
540  public:
541   void *operator new(size_t size);
542   void operator delete(void *p);
543   Acl_map &operator=(Acl_map &&map);
544   void increase_reference_count();
545   void decrease_reference_count();
546 
547   ulong global_acl();
548   Db_access_map *db_acls();
549   Db_access_map *db_wild_acls();
550   Table_access_map *table_acls();
551   SP_access_map *sp_acls();
552   SP_access_map *func_acls();
553   Grant_acl_set *grant_acls();
554   Dynamic_privileges *dynamic_privileges();
555   Restrictions &restrictions();
version()556   uint64 version() { return m_version; }
reference_count()557   uint32 reference_count() { return m_reference_count.load(); }
558 
559  private:
560   std::atomic<int32> m_reference_count;
561   uint64 m_version;
562   Db_access_map m_db_acls;
563   Db_access_map m_db_wild_acls;
564   Table_access_map m_table_acls;
565   ulong m_global_acl;
566   SP_access_map m_sp_acls;
567   SP_access_map m_func_acls;
568   Grant_acl_set m_with_admin_acls;
569   Dynamic_privileges m_dynamic_privileges;
570   Restrictions m_restrictions;
571 };
572 
573 typedef LF_HASH Acl_cache_internal;
574 
575 class Acl_cache {
576  public:
577   Acl_cache();
578   ~Acl_cache();
579 
580   /**
581     When ever the role graph is modified we must flatten the privileges again.
582     This is done by increasing the role graph version counter. Next time
583     a security context is created for an authorization id (aid) a request is
584     also sent to the acl_cache to checkout a flattened acl_map for this
585     particular aid. If a previous acl_map exists the version of this map is
586     compared to the role graph version. If they don't match a new acl_map
587     is calculated and inserted into the cache.
588   */
589   void increase_version();
590   /**
591     Returns a pointer to an acl map to the caller and increase the reference
592     count on the object, iff the object version is the same as the global
593     graph version.
594     If no acl map exists which correspond to the current authorization id of
595     the security context, a new acl map is calculated, inserted into the cache
596     and returned to the user.
597     A new object will also be created if the role graph version counter is
598     different than the acl map object's version.
599 
600     @param uid user id
601   */
602   Acl_map *checkout_acl_map(Security_context *sctx, Auth_id_ref &uid,
603                             List_of_auth_id_refs &active_roles);
604   /**
605     When the security context is done with the acl map it calls the cache
606     to decrease the reference count on that object.
607     @param map acl map
608   */
609   void return_acl_map(Acl_map *map);
610   /**
611     Removes all acl map objects with a references count of zero.
612   */
613   void flush_cache();
614   /**
615     Return a lower boundary to the current version count.
616   */
617   uint64 version();
618   /**
619     Return a snapshot of the number of items in the cache
620   */
621   int32 size();
622 
623  private:
624   /**
625     Creates a new acl map for the authorization id of the security context.
626 
627     @param version The version of the new map
628     @param sctx The associated security context
629   */
630   Acl_map *create_acl_map(uint64 version, Security_context *sctx);
631   /** Role graph version counter */
632   std::atomic<uint64> m_role_graph_version;
633   Acl_cache_internal m_cache;
634   mysql_mutex_t m_cache_flush_mutex;
635 };
636 
637 Acl_cache *get_global_acl_cache();
638 
639 /**
640   Enum for specifying lock type over Acl cache
641 */
642 
643 enum class Acl_cache_lock_mode { READ_MODE = 1, WRITE_MODE };
644 
645 /**
646   Lock guard for ACL Cache.
647   Destructor automatically releases the lock.
648 */
649 
650 class Acl_cache_lock_guard {
651  public:
652   Acl_cache_lock_guard(THD *thd, Acl_cache_lock_mode mode);
653 
654   /**
655     Acl_cache_lock_guard destructor.
656 
657     Release lock(s) if taken
658   */
~Acl_cache_lock_guard()659   ~Acl_cache_lock_guard() { unlock(); }
660 
661   bool lock(bool raise_error = true);
662   void unlock();
663 
664  private:
665   bool already_locked();
666 
667  private:
668   /** Handle to THD object */
669   THD *m_thd;
670   /** Lock mode */
671   Acl_cache_lock_mode m_mode;
672   /** Lock status */
673   bool m_locked;
674 };
675 
676 /**
677   Cache to store the Restrictions of every auth_id.
678   This cache is not thread safe.
679   Callers must acquire acl_cache_write_lock before to amend the cache.
680   Callers should acquire acl_cache_read_lock to probe the cache.
681 
682   Acl_restrictions is not part of ACL_USER because as of now latter is POD
683   type class. We use copy-POD for ACL_USER that makes the explicit memory
684   management of its members hard.
685 */
686 class Acl_restrictions {
687  public:
688   Acl_restrictions();
689 
690   Acl_restrictions(const Acl_restrictions &) = delete;
691   Acl_restrictions(Acl_restrictions &&) = delete;
692   Acl_restrictions &operator=(const Acl_restrictions &) = delete;
693   Acl_restrictions &operator=(Acl_restrictions &&) = delete;
694 
695   void remove_restrictions(const ACL_USER *acl_user);
696   void upsert_restrictions(const ACL_USER *acl_user,
697                            const Restrictions &restriction);
698 
699   Restrictions find_restrictions(const ACL_USER *acl_user) const;
700   size_t size() const;
701 
702  private:
703   malloc_unordered_map<std::string, Restrictions> m_restrictions_map;
704 };
705 
706 #endif /* SQL_USER_CACHE_INCLUDED */
707