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