1/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
2 Copyright (c) 2009, 2018, MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17
18/*
19 The privileges are saved in the following tables:
20 mysql/user ; super user who are allowed to do almost anything
21 mysql/host ; host privileges. This is used if host is empty in mysql/db.
22 mysql/db ; database privileges / user
23
24 data in tables is sorted according to how many not-wild-cards there is
25 in the relevant fields. Empty strings comes last.
26*/
27
28#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */
29#include "sql_priv.h"
30#include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS
31#include "sql_base.h" // close_mysql_tables
32#include "key.h" // key_copy, key_cmp_if_same, key_restore
33#include "sql_show.h" // append_identifier
34#include "sql_table.h" // write_bin_log
35#include "hash_filo.h"
36#include "sql_parse.h" // check_access
37#include "sql_view.h" // VIEW_ANY_ACL
38#include "records.h" // READ_RECORD, read_record_info,
39 // init_read_record, end_read_record
40#include "rpl_filter.h" // rpl_filter
41#include "rpl_rli.h"
42#include <m_ctype.h>
43#include <stdarg.h>
44#include "sp_head.h"
45#include "sp.h"
46#include "transaction.h"
47#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
48#include <sql_common.h>
49#include <mysql/plugin_auth.h>
50#include <mysql/plugin_password_validation.h>
51#include "sql_connect.h"
52#include "hostname.h"
53#include "sql_db.h"
54#include "sql_array.h"
55#include "sql_hset.h"
56#include "password.h"
57
58#include "sql_plugin_compat.h"
59
60bool mysql_user_table_is_in_short_password_format= false;
61
62static LEX_CSTRING native_password_plugin_name= {
63 STRING_WITH_LEN("mysql_native_password")
64};
65
66static LEX_CSTRING old_password_plugin_name= {
67 STRING_WITH_LEN("mysql_old_password")
68};
69
70/// @todo make it configurable
71LEX_CSTRING *default_auth_plugin_name= &native_password_plugin_name;
72
73/*
74 Wildcard host, matches any hostname
75*/
76LEX_CSTRING host_not_specified= { STRING_WITH_LEN("%") };
77
78/*
79 Constants, used in the SHOW GRANTS command.
80 Their actual string values are irrelevant, they're always compared
81 as pointers to these string constants.
82*/
83LEX_CSTRING current_user= { STRING_WITH_LEN("*current_user") };
84LEX_CSTRING current_role= { STRING_WITH_LEN("*current_role") };
85LEX_CSTRING current_user_and_current_role= { STRING_WITH_LEN("*current_user_and_current_role") };
86
87
88#ifndef NO_EMBEDDED_ACCESS_CHECKS
89static plugin_ref old_password_plugin;
90#endif
91static plugin_ref native_password_plugin;
92
93/* Classes */
94
95struct acl_host_and_ip
96{
97 char *hostname;
98 long ip, ip_mask; // Used with masked ip:s
99};
100
101#ifndef NO_EMBEDDED_ACCESS_CHECKS
102static bool compare_hostname(const acl_host_and_ip *, const char *, const char *);
103#else
104#define compare_hostname(X,Y,Z) 0
105#endif
106
107class ACL_ACCESS {
108public:
109 ulong sort;
110 ulong access;
111};
112
113/* ACL_HOST is used if no host is specified */
114
115class ACL_HOST :public ACL_ACCESS
116{
117public:
118 acl_host_and_ip host;
119 char *db;
120};
121
122class ACL_USER_BASE :public ACL_ACCESS
123{
124
125public:
126 static void *operator new(size_t size, MEM_ROOT *mem_root)
127 { return (void*) alloc_root(mem_root, size); }
128 static void operator delete(void *, MEM_ROOT *){}
129 uchar flags; // field used to store various state information
130 LEX_CSTRING user;
131 /* list to hold references to granted roles (ACL_ROLE instances) */
132 DYNAMIC_ARRAY role_grants;
133};
134
135class ACL_USER :public ACL_USER_BASE
136{
137public:
138 acl_host_and_ip host;
139 size_t hostname_length;
140 USER_RESOURCES user_resource;
141 uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
142 uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
143 enum SSL_type ssl_type;
144 const char *ssl_cipher, *x509_issuer, *x509_subject;
145 LEX_CSTRING plugin;
146 LEX_CSTRING auth_string;
147 LEX_CSTRING default_rolename;
148
149 ACL_USER *copy(MEM_ROOT *root)
150 {
151 ACL_USER *dst= (ACL_USER *) alloc_root(root, sizeof(ACL_USER));
152 if (!dst)
153 return 0;
154 *dst= *this;
155 dst->user.str= safe_strdup_root(root, user.str);
156 dst->user.length= user.length;
157 dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
158 dst->x509_issuer= safe_strdup_root(root, x509_issuer);
159 dst->x509_subject= safe_strdup_root(root, x509_subject);
160 if (plugin.str == native_password_plugin_name.str ||
161 plugin.str == old_password_plugin_name.str)
162 dst->plugin= plugin;
163 else
164 dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
165 dst->auth_string.str= safe_strdup_root(root, auth_string.str);
166 dst->host.hostname= safe_strdup_root(root, host.hostname);
167 dst->default_rolename.str= safe_strdup_root(root, default_rolename.str);
168 dst->default_rolename.length= default_rolename.length;
169 bzero(&dst->role_grants, sizeof(role_grants));
170 return dst;
171 }
172
173 int cmp(const char *user2, const char *host2)
174 {
175 CHARSET_INFO *cs= system_charset_info;
176 int res;
177 res= strcmp(safe_str(user.str), safe_str(user2));
178 if (!res)
179 res= my_strcasecmp(cs, host.hostname, host2);
180 return res;
181 }
182
183 bool eq(const char *user2, const char *host2) { return !cmp(user2, host2); }
184
185 bool wild_eq(const char *user2, const char *host2, const char *ip2)
186 {
187 if (strcmp(safe_str(user.str), safe_str(user2)))
188 return false;
189
190 return compare_hostname(&host, host2, ip2 ? ip2 : host2);
191 }
192};
193
194class ACL_ROLE :public ACL_USER_BASE
195{
196public:
197 /*
198 In case of granting a role to a role, the access bits are merged together
199 via a bit OR operation and placed in the ACL_USER::access field.
200
201 When rebuilding role_grants via the rebuild_role_grant function,
202 the ACL_USER::access field needs to be reset first. The field
203 initial_role_access holds initial grants, as granted directly to the role
204 */
205 ulong initial_role_access;
206 /*
207 In subgraph traversal, when we need to traverse only a part of the graph
208 (e.g. all direct and indirect grantees of a role X), the counter holds the
209 number of affected neighbour nodes.
210 See also propagate_role_grants()
211 */
212 uint counter;
213 DYNAMIC_ARRAY parent_grantee; // array of backlinks to elements granted
214
215 ACL_ROLE(ACL_USER * user, MEM_ROOT *mem);
216 ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *mem);
217
218};
219
220class ACL_DB :public ACL_ACCESS
221{
222public:
223 acl_host_and_ip host;
224 const char *user,*db;
225 ulong initial_access; /* access bits present in the table */
226};
227
228#ifndef DBUG_OFF
229/* status variables, only visible in SHOW STATUS after -#d,role_merge_stats */
230ulong role_global_merges= 0, role_db_merges= 0, role_table_merges= 0,
231 role_column_merges= 0, role_routine_merges= 0;
232#endif
233
234#ifndef NO_EMBEDDED_ACCESS_CHECKS
235static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd);
236static void update_hostname(acl_host_and_ip *host, const char *hostname);
237static ulong get_sort(uint count,...);
238static bool show_proxy_grants (THD *, const char *, const char *,
239 char *, size_t);
240static bool show_role_grants(THD *, const char *, const char *,
241 ACL_USER_BASE *, char *, size_t);
242static bool show_global_privileges(THD *, ACL_USER_BASE *,
243 bool, char *, size_t);
244static bool show_database_privileges(THD *, const char *, const char *,
245 char *, size_t);
246static bool show_table_and_column_privileges(THD *, const char *, const char *,
247 char *, size_t);
248static int show_routine_grants(THD *, const char *, const char *,
249 const Sp_handler *sph, char *, int);
250
251class Grant_tables;
252class User_table;
253class Proxies_priv_table;
254
255class ACL_PROXY_USER :public ACL_ACCESS
256{
257 acl_host_and_ip host;
258 const char *user;
259 acl_host_and_ip proxied_host;
260 const char *proxied_user;
261 bool with_grant;
262
263 typedef enum {
264 MYSQL_PROXIES_PRIV_HOST,
265 MYSQL_PROXIES_PRIV_USER,
266 MYSQL_PROXIES_PRIV_PROXIED_HOST,
267 MYSQL_PROXIES_PRIV_PROXIED_USER,
268 MYSQL_PROXIES_PRIV_WITH_GRANT,
269 MYSQL_PROXIES_PRIV_GRANTOR,
270 MYSQL_PROXIES_PRIV_TIMESTAMP } proxy_table_fields;
271public:
272 ACL_PROXY_USER () {};
273
274 void init(const char *host_arg, const char *user_arg,
275 const char *proxied_host_arg, const char *proxied_user_arg,
276 bool with_grant_arg)
277 {
278 user= (user_arg && *user_arg) ? user_arg : NULL;
279 update_hostname (&host, (host_arg && *host_arg) ? host_arg : NULL);
280 proxied_user= (proxied_user_arg && *proxied_user_arg) ?
281 proxied_user_arg : NULL;
282 update_hostname (&proxied_host,
283 (proxied_host_arg && *proxied_host_arg) ?
284 proxied_host_arg : NULL);
285 with_grant= with_grant_arg;
286 sort= get_sort(4, host.hostname, user, proxied_host.hostname, proxied_user);
287 }
288
289 void init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
290 const char *proxied_host_arg, const char *proxied_user_arg,
291 bool with_grant_arg)
292 {
293 init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
294 (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
295 (proxied_host_arg && *proxied_host_arg) ?
296 strdup_root (mem, proxied_host_arg) : NULL,
297 (proxied_user_arg && *proxied_user_arg) ?
298 strdup_root (mem, proxied_user_arg) : NULL,
299 with_grant_arg);
300 }
301
302 void init(const Proxies_priv_table& proxies_priv_table, MEM_ROOT *mem);
303
304 bool get_with_grant() { return with_grant; }
305 const char *get_user() { return user; }
306 const char *get_host() { return host.hostname; }
307 const char *get_proxied_user() { return proxied_user; }
308 const char *get_proxied_host() { return proxied_host.hostname; }
309 void set_user(MEM_ROOT *mem, const char *user_arg)
310 {
311 user= user_arg && *user_arg ? strdup_root(mem, user_arg) : NULL;
312 }
313 void set_host(MEM_ROOT *mem, const char *host_arg)
314 {
315 update_hostname(&host, safe_strdup_root(mem, host_arg));
316 }
317
318 bool check_validity(bool check_no_resolve)
319 {
320 if (check_no_resolve &&
321 (hostname_requires_resolving(host.hostname) ||
322 hostname_requires_resolving(proxied_host.hostname)))
323 {
324 sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
325 "ignored in --skip-name-resolve mode.",
326 safe_str(proxied_user),
327 safe_str(proxied_host.hostname),
328 safe_str(user),
329 safe_str(host.hostname));
330 return TRUE;
331 }
332 return FALSE;
333 }
334
335 bool matches(const char *host_arg, const char *user_arg, const char *ip_arg,
336 const char *proxied_user_arg)
337 {
338 DBUG_ENTER("ACL_PROXY_USER::matches");
339 DBUG_PRINT("info", ("compare_hostname(%s,%s,%s) &&"
340 "compare_hostname(%s,%s,%s) &&"
341 "wild_compare (%s,%s) &&"
342 "wild_compare (%s,%s)",
343 host.hostname, host_arg, ip_arg, proxied_host.hostname,
344 host_arg, ip_arg, user_arg, user,
345 proxied_user_arg, proxied_user));
346 DBUG_RETURN(compare_hostname(&host, host_arg, ip_arg) &&
347 compare_hostname(&proxied_host, host_arg, ip_arg) &&
348 (!user ||
349 (user_arg && !wild_compare(user_arg, user, TRUE))) &&
350 (!proxied_user ||
351 (proxied_user && !wild_compare(proxied_user_arg,
352 proxied_user, TRUE))));
353 }
354
355
356 inline static bool auth_element_equals(const char *a, const char *b)
357 {
358 return (a == b || (a != NULL && b != NULL && !strcmp(a,b)));
359 }
360
361
362 bool pk_equals(ACL_PROXY_USER *grant)
363 {
364 DBUG_ENTER("pk_equals");
365 DBUG_PRINT("info", ("strcmp(%s,%s) &&"
366 "strcmp(%s,%s) &&"
367 "wild_compare (%s,%s) &&"
368 "wild_compare (%s,%s)",
369 user, grant->user, proxied_user, grant->proxied_user,
370 host.hostname, grant->host.hostname,
371 proxied_host.hostname, grant->proxied_host.hostname));
372
373 bool res= auth_element_equals(user, grant->user) &&
374 auth_element_equals(proxied_user, grant->proxied_user) &&
375 auth_element_equals(host.hostname, grant->host.hostname) &&
376 auth_element_equals(proxied_host.hostname,
377 grant->proxied_host.hostname);
378 DBUG_RETURN(res);
379 }
380
381
382 bool granted_on(const char *host_arg, const char *user_arg)
383 {
384 return (((!user && (!user_arg || !user_arg[0])) ||
385 (user && user_arg && !strcmp(user, user_arg))) &&
386 ((!host.hostname && (!host_arg || !host_arg[0])) ||
387 (host.hostname && host_arg && !strcmp(host.hostname, host_arg))));
388 }
389
390
391 void print_grant(String *str)
392 {
393 str->append(STRING_WITH_LEN("GRANT PROXY ON '"));
394 if (proxied_user)
395 str->append(proxied_user, strlen(proxied_user));
396 str->append(STRING_WITH_LEN("'@'"));
397 if (proxied_host.hostname)
398 str->append(proxied_host.hostname, strlen(proxied_host.hostname));
399 str->append(STRING_WITH_LEN("' TO '"));
400 if (user)
401 str->append(user, strlen(user));
402 str->append(STRING_WITH_LEN("'@'"));
403 if (host.hostname)
404 str->append(host.hostname, strlen(host.hostname));
405 str->append(STRING_WITH_LEN("'"));
406 if (with_grant)
407 str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
408 }
409
410 void set_data(ACL_PROXY_USER *grant)
411 {
412 with_grant= grant->with_grant;
413 }
414
415 static int store_pk(TABLE *table,
416 const LEX_CSTRING *host,
417 const LEX_CSTRING *user,
418 const LEX_CSTRING *proxied_host,
419 const LEX_CSTRING *proxied_user)
420 {
421 DBUG_ENTER("ACL_PROXY_USER::store_pk");
422 DBUG_PRINT("info", ("host=%s, user=%s, proxied_host=%s, proxied_user=%s",
423 host->str, user->str,
424 proxied_host->str, proxied_user->str));
425 if (table->field[MYSQL_PROXIES_PRIV_HOST]->store(host->str,
426 host->length,
427 system_charset_info))
428 DBUG_RETURN(TRUE);
429 if (table->field[MYSQL_PROXIES_PRIV_USER]->store(user->str,
430 user->length,
431 system_charset_info))
432 DBUG_RETURN(TRUE);
433 if (table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]->store(proxied_host->str,
434 proxied_host->length,
435 system_charset_info))
436 DBUG_RETURN(TRUE);
437 if (table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]->store(proxied_user->str,
438 proxied_user->length,
439 system_charset_info))
440 DBUG_RETURN(TRUE);
441
442 DBUG_RETURN(FALSE);
443 }
444
445 static int store_data_record(TABLE *table,
446 const LEX_CSTRING *host,
447 const LEX_CSTRING *user,
448 const LEX_CSTRING *proxied_host,
449 const LEX_CSTRING *proxied_user,
450 bool with_grant,
451 const char *grantor)
452 {
453 DBUG_ENTER("ACL_PROXY_USER::store_pk");
454 if (store_pk(table, host, user, proxied_host, proxied_user))
455 DBUG_RETURN(TRUE);
456 DBUG_PRINT("info", ("with_grant=%s", with_grant ? "TRUE" : "FALSE"));
457 if (table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->store(with_grant ? 1 : 0,
458 TRUE))
459 DBUG_RETURN(TRUE);
460 if (table->field[MYSQL_PROXIES_PRIV_GRANTOR]->store(grantor,
461 strlen(grantor),
462 system_charset_info))
463 DBUG_RETURN(TRUE);
464
465 DBUG_RETURN(FALSE);
466 }
467};
468
469#define FIRST_NON_YN_FIELD 26
470
471class acl_entry :public hash_filo_element
472{
473public:
474 ulong access;
475 uint16 length;
476 char key[1]; // Key will be stored here
477};
478
479
480static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
481 my_bool not_used __attribute__((unused)))
482{
483 *length=(uint) entry->length;
484 return (uchar*) entry->key;
485}
486
487static uchar* acl_role_get_key(ACL_ROLE *entry, size_t *length,
488 my_bool not_used __attribute__((unused)))
489{
490 *length=(uint) entry->user.length;
491 return (uchar*) entry->user.str;
492}
493
494struct ROLE_GRANT_PAIR : public Sql_alloc
495{
496 char *u_uname;
497 char *u_hname;
498 char *r_uname;
499 LEX_STRING hashkey;
500 bool with_admin;
501
502 bool init(MEM_ROOT *mem, const char *username, const char *hostname,
503 const char *rolename, bool with_admin_option);
504};
505
506static uchar* acl_role_map_get_key(ROLE_GRANT_PAIR *entry, size_t *length,
507 my_bool not_used __attribute__((unused)))
508{
509 *length=(uint) entry->hashkey.length;
510 return (uchar*) entry->hashkey.str;
511}
512
513bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, const char *username,
514 const char *hostname, const char *rolename,
515 bool with_admin_option)
516{
517 size_t uname_l = safe_strlen(username);
518 size_t hname_l = safe_strlen(hostname);
519 size_t rname_l = safe_strlen(rolename);
520 /*
521 Create a buffer that holds all 3 NULL terminated strings in succession
522 To save memory space, the same buffer is used as the hashkey
523 */
524 size_t bufflen = uname_l + hname_l + rname_l + 3; //add the '\0' aswell
525 char *buff= (char *)alloc_root(mem, bufflen);
526 if (!buff)
527 return true;
528
529 /*
530 Offsets in the buffer for all 3 strings
531 */
532 char *username_pos= buff;
533 char *hostname_pos= buff + uname_l + 1;
534 char *rolename_pos= buff + uname_l + hname_l + 2;
535
536 if (username) //prevent undefined behaviour
537 memcpy(username_pos, username, uname_l);
538 username_pos[uname_l]= '\0'; //#1 string terminator
539 u_uname= username_pos;
540
541 if (hostname) //prevent undefined behaviour
542 memcpy(hostname_pos, hostname, hname_l);
543 hostname_pos[hname_l]= '\0'; //#2 string terminator
544 u_hname= hostname_pos;
545
546 if (rolename) //prevent undefined behaviour
547 memcpy(rolename_pos, rolename, rname_l);
548 rolename_pos[rname_l]= '\0'; //#3 string terminator
549 r_uname= rolename_pos;
550
551 hashkey.str = buff;
552 hashkey.length = bufflen;
553
554 with_admin= with_admin_option;
555
556 return false;
557}
558
559#define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
560#define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
561 1 + USERNAME_LENGTH + 1)
562
563#if defined(HAVE_OPENSSL)
564/*
565 Without SSL the handshake consists of one packet. This packet
566 has both client capabilities and scrambled password.
567 With SSL the handshake might consist of two packets. If the first
568 packet (client capabilities) has CLIENT_SSL flag set, we have to
569 switch to SSL and read the second packet. The scrambled password
570 is in the second packet and client_capabilities field will be ignored.
571 Maybe it is better to accept flags other than CLIENT_SSL from the
572 second packet?
573*/
574#define SSL_HANDSHAKE_SIZE 2
575#define MIN_HANDSHAKE_SIZE 2
576#else
577#define MIN_HANDSHAKE_SIZE 6
578#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
579#define NORMAL_HANDSHAKE_SIZE 6
580
581#define ROLE_ASSIGN_COLUMN_IDX 44
582#define DEFAULT_ROLE_COLUMN_IDX 45
583#define MAX_STATEMENT_TIME_COLUMN_IDX 46
584
585/* various flags valid for ACL_USER */
586#define IS_ROLE (1L << 0)
587/* Flag to mark that a ROLE is on the recursive DEPTH_FIRST_SEARCH stack */
588#define ROLE_ON_STACK (1L << 1)
589/*
590 Flag to mark that a ROLE and all it's neighbours have
591 been visited
592*/
593#define ROLE_EXPLORED (1L << 2)
594/* Flag to mark that on_node was already called for this role */
595#define ROLE_OPENED (1L << 3)
596
597static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
598static HASH acl_roles;
599/*
600 An hash containing mappings user <--> role
601
602 A hash is used so as to make updates quickly
603 The hashkey used represents all the entries combined
604*/
605static HASH acl_roles_mappings;
606static MEM_ROOT acl_memroot, grant_memroot;
607static bool initialized=0;
608static bool allow_all_hosts=1;
609static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
610static HASH package_spec_priv_hash, package_body_priv_hash;
611static DYNAMIC_ARRAY acl_wild_hosts;
612static Hash_filo<acl_entry> *acl_cache;
613static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
614static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
615static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
616static ulong get_sort(uint count,...);
617static void init_check_host(void);
618static void rebuild_check_host(void);
619static void rebuild_role_grants(void);
620static ACL_USER *find_user_exact(const char *host, const char *user);
621static ACL_USER *find_user_wild(const char *host, const char *user, const char *ip= 0);
622static ACL_ROLE *find_acl_role(const char *user);
623static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_CSTRING *u, const LEX_CSTRING *h, const LEX_CSTRING *r);
624static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host);
625static bool update_user_table(THD *, const User_table &, const char *, const char *, const
626 char *, size_t new_password_len);
627static bool acl_load(THD *thd, const Grant_tables& grant_tables);
628static inline void get_grantor(THD *thd, char* grantor);
629static bool add_role_user_mapping(const char *uname, const char *hname, const char *rname);
630static bool get_YN_as_bool(Field *field);
631
632#define ROLE_CYCLE_FOUND 2
633static int traverse_role_graph_up(ACL_ROLE *, void *,
634 int (*) (ACL_ROLE *, void *),
635 int (*) (ACL_ROLE *, ACL_ROLE *, void *));
636
637static int traverse_role_graph_down(ACL_USER_BASE *, void *,
638 int (*) (ACL_USER_BASE *, void *),
639 int (*) (ACL_USER_BASE *, ACL_ROLE *, void *));
640
641
642HASH *Sp_handler_procedure::get_priv_hash() const
643{
644 return &proc_priv_hash;
645}
646
647
648HASH *Sp_handler_function::get_priv_hash() const
649{
650 return &func_priv_hash;
651}
652
653
654HASH *Sp_handler_package_spec::get_priv_hash() const
655{
656 return &package_spec_priv_hash;
657}
658
659
660HASH *Sp_handler_package_body::get_priv_hash() const
661{
662 return &package_body_priv_hash;
663}
664
665
666/*
667 Enumeration of ACL/GRANT tables in the mysql database
668*/
669enum enum_acl_tables
670{
671 USER_TABLE,
672 DB_TABLE,
673 TABLES_PRIV_TABLE,
674 COLUMNS_PRIV_TABLE,
675#define FIRST_OPTIONAL_TABLE HOST_TABLE
676 HOST_TABLE,
677 PROCS_PRIV_TABLE,
678 PROXIES_PRIV_TABLE,
679 ROLES_MAPPING_TABLE,
680 TABLES_MAX // <== always the last
681};
682// bits for open_grant_tables
683static const int Table_user= 1 << USER_TABLE;
684static const int Table_db= 1 << DB_TABLE;
685static const int Table_tables_priv= 1 << TABLES_PRIV_TABLE;
686static const int Table_columns_priv= 1 << COLUMNS_PRIV_TABLE;
687static const int Table_host= 1 << HOST_TABLE;
688static const int Table_procs_priv= 1 << PROCS_PRIV_TABLE;
689static const int Table_proxies_priv= 1 << PROXIES_PRIV_TABLE;
690static const int Table_roles_mapping= 1 << ROLES_MAPPING_TABLE;
691
692/**
693 Base class representing a generic grant table from the mysql database.
694
695 The potential tables that this class can represent are:
696 user, db, columns_priv, tables_priv, host, procs_priv, proxies_priv,
697 roles_mapping
698
699 Objects belonging to this parent class can only be constructed by the
700 Grants_table class. This ensures the correct initialization of the objects.
701*/
702class Grant_table_base
703{
704 public:
705 /* Number of fields for this Grant Table. */
706 uint num_fields() const { return tl.table->s->fields; }
707 /* Check if the table exists after an attempt to open it was made.
708 Some tables, such as the host table in MySQL 5.6.7+ are missing. */
709 bool table_exists() const { return tl.table; };
710 /* Initializes the READ_RECORD structure provided as a parameter
711 to read through the whole table, with all columns available. Cleaning up
712 is the caller's job. */
713 bool init_read_record(READ_RECORD* info, THD* thd) const
714 {
715 DBUG_ASSERT(tl.table);
716 bool result= ::init_read_record(info, thd, tl.table, NULL, NULL, 1,
717 true, false);
718 if (!result)
719 tl.table->use_all_columns();
720 return result;
721 }
722
723 /* Return the number of privilege columns for this table. */
724 uint num_privileges() const { return num_privilege_cols; }
725 /* Return a privilege column by index. */
726 Field* priv_field(uint privilege_idx) const
727 {
728 DBUG_ASSERT(privilege_idx < num_privileges());
729 return tl.table->field[start_privilege_column + privilege_idx];
730 }
731
732 /* Fetch the privileges from the table as a set of bits. The first column
733 is represented by the first bit in the result, the second column by the
734 second bit, etc. */
735 ulong get_access() const
736 {
737 return get_access(start_privilege_column,
738 start_privilege_column + num_privileges() - 1);
739 }
740
741 /* Return the underlying TABLE handle. */
742 TABLE* table() const
743 {
744 return tl.table;
745 }
746
747 /** Check if the table was opened, issue an error otherwise. */
748 int no_such_table() const
749 {
750 if (table_exists())
751 return 0;
752
753 my_error(ER_NO_SUCH_TABLE, MYF(0), tl.db.str, tl.alias.str);
754 return 1;
755 }
756
757
758 protected:
759 friend class Grant_tables;
760
761 Grant_table_base() : start_privilege_column(0), num_privilege_cols(0)
762 {
763 bzero(&tl, sizeof(tl));
764 };
765
766 /* Initialization sequence common for all grant tables. This should be called
767 after all table-specific initialization is performed. */
768 void init(enum thr_lock_type lock_type, bool is_optional)
769 {
770 tl.open_type= OT_BASE_ONLY;
771 if (lock_type >= TL_WRITE_ALLOW_WRITE)
772 tl.updating= 1;
773 if (is_optional)
774 tl.open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
775 }
776
777 /*
778 Get all access bits from table between start_field and end_field indices.
779
780 IMPLEMENTATION
781 The record should be already read in table->record[0]. All privileges
782 are specified as an ENUM(Y,N).
783
784 SYNOPSIS
785 get_access()
786 start_field_idx The field index at which the first privilege
787 specification begins.
788 end_field_idx The field index at which the last privilege
789 specification is located.
790
791 RETURN VALUE
792 privilege mask
793 */
794 ulong get_access(uint start_field_idx, uint end_field_idx) const
795 {
796 ulong access_bits= 0, bit= 1;
797 for (uint i = start_field_idx; i <= end_field_idx; i++, bit<<=1)
798 {
799 if (get_YN_as_bool(tl.table->field[i]))
800 access_bits|= bit;
801 }
802 return access_bits;
803 }
804
805 /* Compute how many privilege columns this table has. This method
806 can only be called after the table has been opened.
807
808 IMPLEMENTATION
809 A privilege column is of type enum('Y', 'N'). Privilege columns are
810 expected to be one after another.
811 */
812 void compute_num_privilege_cols()
813 {
814 if (!table_exists()) // Table does not exist or not opened.
815 return;
816
817 num_privilege_cols= 0;
818 for (uint i= 0; i < num_fields(); i++)
819 {
820 Field *field= tl.table->field[i];
821 if (num_privilege_cols > 0 && field->real_type() != MYSQL_TYPE_ENUM)
822 return;
823 if (field->real_type() == MYSQL_TYPE_ENUM &&
824 static_cast<Field_enum*>(field)->typelib->count == 2)
825 {
826 num_privilege_cols++;
827 if (num_privilege_cols == 1)
828 start_privilege_column= i;
829 }
830 }
831 }
832
833 /* The index at which privilege columns start. */
834 uint start_privilege_column;
835 /* The number of privilege columns in the table. */
836 uint num_privilege_cols;
837
838 TABLE_LIST tl;
839};
840
841class User_table: public Grant_table_base
842{
843 public:
844 /* Field getters return NULL if the column is not present in the table.
845 This is consistent only if the table is in a supported version. We do
846 not guard against corrupt tables. (yet) */
847 Field* host() const
848 { return get_field(0); }
849 Field* user() const
850 { return get_field(1); }
851 Field* password() const
852 { return have_password() ? NULL : tl.table->field[2]; }
853 /* Columns after privilege columns. */
854 Field* ssl_type() const
855 { return get_field(start_privilege_column + num_privileges()); }
856 Field* ssl_cipher() const
857 { return get_field(start_privilege_column + num_privileges() + 1); }
858 Field* x509_issuer() const
859 { return get_field(start_privilege_column + num_privileges() + 2); }
860 Field* x509_subject() const
861 { return get_field(start_privilege_column + num_privileges() + 3); }
862 Field* max_questions() const
863 { return get_field(start_privilege_column + num_privileges() + 4); }
864 Field* max_updates() const
865 { return get_field(start_privilege_column + num_privileges() + 5); }
866 Field* max_connections() const
867 { return get_field(start_privilege_column + num_privileges() + 6); }
868 Field* max_user_connections() const
869 { return get_field(start_privilege_column + num_privileges() + 7); }
870 Field* plugin() const
871 { return get_field(start_privilege_column + num_privileges() + 8); }
872 Field* authentication_string() const
873 { return get_field(start_privilege_column + num_privileges() + 9); }
874 Field* password_expired() const
875 { return get_field(start_privilege_column + num_privileges() + 10); }
876 Field* is_role() const
877 { return get_field(start_privilege_column + num_privileges() + 11); }
878 Field* default_role() const
879 { return get_field(start_privilege_column + num_privileges() + 12); }
880 Field* max_statement_time() const
881 { return get_field(start_privilege_column + num_privileges() + 13); }
882
883 /*
884 Check if a user entry in the user table is marked as being a role entry
885
886 IMPLEMENTATION
887 Access the coresponding column and check the coresponding ENUM of the form
888 ENUM('N', 'Y')
889
890 SYNOPSIS
891 check_is_role()
892 form an open table to read the entry from.
893 The record should be already read in table->record[0]
894
895 RETURN VALUE
896 TRUE if the user is marked as a role
897 FALSE otherwise
898 */
899 bool check_is_role() const
900 {
901 /* Table version does not support roles */
902 if (!is_role())
903 return false;
904
905 return get_YN_as_bool(is_role());
906 }
907
908
909 private:
910 friend class Grant_tables;
911
912 /* Only Grant_tables can instantiate this class. */
913 User_table() {};
914
915 void init(enum thr_lock_type lock_type)
916 {
917 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
918 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_USER_NAME, NULL, lock_type);
919 Grant_table_base::init(lock_type, false);
920 }
921
922 /* The user table is a bit different compared to the other Grant tables.
923 Usually, we only add columns to the grant tables when adding functionality.
924 This makes it easy to test which version of the table we are using, by
925 just looking at the number of fields present in the table.
926
927 In MySQL 5.7.6 the Password column was removed. We need to guard for that.
928 The field-fetching methods for the User table return NULL if the field
929 doesn't exist. This simplifies checking of table "version", as we don't
930 have to make use of num_fields() any more.
931 */
932 inline Field* get_field(uint field_num) const
933 {
934 if (field_num >= num_fields())
935 return NULL;
936
937 return tl.table->field[field_num];
938 }
939
940 /* Normally password column is the third column in the table. If privileges
941 start on the third column instead, we are missing the password column.
942 This means we are using a MySQL 5.7.6+ data directory. */
943 bool have_password() const { return start_privilege_column == 2; }
944
945};
946
947class Db_table: public Grant_table_base
948{
949 public:
950 Field* host() const { return tl.table->field[0]; }
951 Field* db() const { return tl.table->field[1]; }
952 Field* user() const { return tl.table->field[2]; }
953
954 private:
955 friend class Grant_tables;
956
957 Db_table() {};
958
959 void init(enum thr_lock_type lock_type)
960 {
961 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
962 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_DB_NAME, NULL, lock_type);
963 Grant_table_base::init(lock_type, false);
964 }
965};
966
967class Tables_priv_table: public Grant_table_base
968{
969 public:
970 Field* host() const { return tl.table->field[0]; }
971 Field* db() const { return tl.table->field[1]; }
972 Field* user() const { return tl.table->field[2]; }
973 Field* table_name() const { return tl.table->field[3]; }
974 Field* grantor() const { return tl.table->field[4]; }
975 Field* timestamp() const { return tl.table->field[5]; }
976 Field* table_priv() const { return tl.table->field[6]; }
977 Field* column_priv() const { return tl.table->field[7]; }
978
979 private:
980 friend class Grant_tables;
981
982 Tables_priv_table() {};
983
984 void init(enum thr_lock_type lock_type, Grant_table_base *next_table= NULL)
985 {
986 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
987 LEX_CSTRING MYSQL_TABLES_PRIV_NAME={STRING_WITH_LEN("tables_priv") };
988 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_TABLES_PRIV_NAME, NULL, lock_type);
989 Grant_table_base::init(lock_type, false);
990 }
991};
992
993class Columns_priv_table: public Grant_table_base
994{
995 public:
996 Field* host() const { return tl.table->field[0]; }
997 Field* db() const { return tl.table->field[1]; }
998 Field* user() const { return tl.table->field[2]; }
999 Field* table_name() const { return tl.table->field[3]; }
1000 Field* column_name() const { return tl.table->field[4]; }
1001 Field* timestamp() const { return tl.table->field[5]; }
1002 Field* column_priv() const { return tl.table->field[6]; }
1003
1004 private:
1005 friend class Grant_tables;
1006
1007 Columns_priv_table() {};
1008
1009 void init(enum thr_lock_type lock_type)
1010 {
1011 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
1012 LEX_CSTRING MYSQL_COLUMNS_PRIV_NAME={ STRING_WITH_LEN("columns_priv") };
1013 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_COLUMNS_PRIV_NAME, NULL, lock_type);
1014 Grant_table_base::init(lock_type, false);
1015 }
1016};
1017
1018class Host_table: public Grant_table_base
1019{
1020 public:
1021 Field* host() const { return tl.table->field[0]; }
1022 Field* db() const { return tl.table->field[1]; }
1023
1024 private:
1025 friend class Grant_tables;
1026
1027 Host_table() {}
1028
1029 void init(enum thr_lock_type lock_type)
1030 {
1031 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
1032 LEX_CSTRING MYSQL_HOST_NAME={STRING_WITH_LEN("host") };
1033 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_HOST_NAME, NULL, lock_type);
1034 Grant_table_base::init(lock_type, true);
1035 }
1036};
1037
1038class Procs_priv_table: public Grant_table_base
1039{
1040 public:
1041 Field* host() const { return tl.table->field[0]; }
1042 Field* db() const { return tl.table->field[1]; }
1043 Field* user() const { return tl.table->field[2]; }
1044 Field* routine_name() const { return tl.table->field[3]; }
1045 Field* routine_type() const { return tl.table->field[4]; }
1046 Field* grantor() const { return tl.table->field[5]; }
1047 Field* proc_priv() const { return tl.table->field[6]; }
1048 Field* timestamp() const { return tl.table->field[7]; }
1049
1050 private:
1051 friend class Grant_tables;
1052
1053 Procs_priv_table() {}
1054
1055 void init(enum thr_lock_type lock_type)
1056 {
1057 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
1058 LEX_CSTRING MYSQL_PROCS_PRIV_NAME={STRING_WITH_LEN("procs_priv") };
1059 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_PROCS_PRIV_NAME, NULL, lock_type);
1060 Grant_table_base::init(lock_type, true);
1061 }
1062};
1063
1064class Proxies_priv_table: public Grant_table_base
1065{
1066 public:
1067 Field* host() const { return tl.table->field[0]; }
1068 Field* user() const { return tl.table->field[1]; }
1069 Field* proxied_host() const { return tl.table->field[2]; }
1070 Field* proxied_user() const { return tl.table->field[3]; }
1071 Field* with_grant() const { return tl.table->field[4]; }
1072 Field* grantor() const { return tl.table->field[5]; }
1073 Field* timestamp() const { return tl.table->field[6]; }
1074
1075 private:
1076 friend class Grant_tables;
1077
1078 Proxies_priv_table() {}
1079
1080 void init(enum thr_lock_type lock_type)
1081 {
1082 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
1083 LEX_CSTRING MYSQL_PROXIES_PRIV_NAME={STRING_WITH_LEN("proxies_priv") };
1084 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_PROXIES_PRIV_NAME, NULL, lock_type);
1085 Grant_table_base::init(lock_type, true);
1086 }
1087};
1088
1089class Roles_mapping_table: public Grant_table_base
1090{
1091 public:
1092 Field* host() const { return tl.table->field[0]; }
1093 Field* user() const { return tl.table->field[1]; }
1094 Field* role() const { return tl.table->field[2]; }
1095 Field* admin_option() const { return tl.table->field[3]; }
1096
1097 private:
1098 friend class Grant_tables;
1099
1100 Roles_mapping_table() {}
1101
1102 void init(enum thr_lock_type lock_type)
1103 {
1104 /* We are relying on init_one_table zeroing out the TABLE_LIST structure. */
1105 LEX_CSTRING MYSQL_ROLES_MAPPING_NAME={STRING_WITH_LEN("roles_mapping") };
1106 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_ROLES_MAPPING_NAME, NULL, lock_type);
1107 Grant_table_base::init(lock_type, true);
1108 }
1109};
1110
1111/**
1112 Class that represents a collection of grant tables.
1113*/
1114class Grant_tables
1115{
1116 public:
1117 /* When constructing the Grant_tables object, we initialize only
1118 the tables which are going to be opened.
1119 @param which_tables Bitmap of which tables to open.
1120 @param lock_type Lock type to use when opening tables.
1121 */
1122 Grant_tables(int which_tables, enum thr_lock_type lock_type)
1123 {
1124 DBUG_ENTER("Grant_tables::Grant_tables");
1125 DBUG_PRINT("info", ("which_tables: %x, lock_type: %u",
1126 which_tables, lock_type));
1127 DBUG_ASSERT(which_tables); /* At least one table must be opened. */
1128 Grant_table_base* prev= NULL;
1129 /* We start from the last table, Table_roles_mapping, such that
1130 the first one in the linked list is Table_user. */
1131 if (which_tables & Table_roles_mapping)
1132 {
1133 m_roles_mapping_table.init(lock_type);
1134 prev= &m_roles_mapping_table;
1135 }
1136 if (which_tables & Table_proxies_priv)
1137 {
1138 m_proxies_priv_table.init(lock_type);
1139 link_tables(&m_proxies_priv_table, prev);
1140 prev= &m_proxies_priv_table;
1141 }
1142 if (which_tables & Table_procs_priv)
1143 {
1144 m_procs_priv_table.init(lock_type);
1145 link_tables(&m_procs_priv_table, prev);
1146 prev= &m_procs_priv_table;
1147 }
1148 if (which_tables & Table_host)
1149 {
1150 m_host_table.init(lock_type);
1151 link_tables(&m_host_table, prev);
1152 prev= &m_host_table;
1153 }
1154 if (which_tables & Table_columns_priv)
1155 {
1156 m_columns_priv_table.init(lock_type);
1157 link_tables(&m_columns_priv_table, prev);
1158 prev= &m_columns_priv_table;
1159 }
1160 if (which_tables & Table_tables_priv)
1161 {
1162 m_tables_priv_table.init(lock_type);
1163 link_tables(&m_tables_priv_table, prev);
1164 prev= &m_tables_priv_table;
1165 }
1166 if (which_tables & Table_db)
1167 {
1168 m_db_table.init(lock_type);
1169 link_tables(&m_db_table, prev);
1170 prev= &m_db_table;
1171 }
1172 if (which_tables & Table_user)
1173 {
1174 m_user_table.init(lock_type);
1175 link_tables(&m_user_table, prev);
1176 prev= &m_user_table;
1177 }
1178
1179 first_table_in_list= prev;
1180 DBUG_VOID_RETURN;
1181 }
1182
1183 /* Before any operation is possible on grant tables, they must be opened.
1184 This opens the tables according to the lock type specified during
1185 construction.
1186
1187 @retval 1 replication filters matched. Abort the operation,
1188 but return OK (!)
1189 @retval 0 tables were opened successfully
1190 @retval -1 error, tables could not be opened
1191 */
1192 int open_and_lock(THD *thd)
1193 {
1194 DBUG_ENTER("Grant_tables::open_and_lock");
1195 DBUG_ASSERT(first_table_in_list);
1196#ifdef HAVE_REPLICATION
1197 if (first_table_in_list->tl.lock_type >= TL_WRITE_ALLOW_WRITE &&
1198 thd->slave_thread && !thd->spcont)
1199 {
1200 /*
1201 GRANT and REVOKE are applied the slave in/exclusion rules as they are
1202 some kind of updates to the mysql.% tables.
1203 */
1204 Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
1205 if (rpl_filter->is_on() &&
1206 !rpl_filter->tables_ok(0, &first_table_in_list->tl))
1207 DBUG_RETURN(1);
1208 }
1209#endif
1210 if (open_and_lock_tables(thd, &first_table_in_list->tl, FALSE,
1211 MYSQL_LOCK_IGNORE_TIMEOUT))
1212 DBUG_RETURN(-1);
1213
1214 /*
1215 We can read privilege tables even when !initialized.
1216 This can be acl_load() - server startup or FLUSH PRIVILEGES
1217 */
1218 if (first_table_in_list->tl.lock_type >= TL_WRITE_ALLOW_WRITE &&
1219 !initialized)
1220 {
1221 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
1222 DBUG_RETURN(-1);
1223 }
1224
1225 /* The privilge columns vary based on MariaDB version. Figure out
1226 how many we have after we've opened the table. */
1227 m_user_table.compute_num_privilege_cols();
1228 m_db_table.compute_num_privilege_cols();
1229 m_tables_priv_table.compute_num_privilege_cols();
1230 m_columns_priv_table.compute_num_privilege_cols();
1231 m_host_table.compute_num_privilege_cols();
1232 m_procs_priv_table.compute_num_privilege_cols();
1233 m_proxies_priv_table.compute_num_privilege_cols();
1234 m_roles_mapping_table.compute_num_privilege_cols();
1235 DBUG_RETURN(0);
1236 }
1237
1238 inline const User_table& user_table() const
1239 {
1240 return m_user_table;
1241 }
1242
1243 inline const Db_table& db_table() const
1244 {
1245 return m_db_table;
1246 }
1247
1248
1249 inline const Tables_priv_table& tables_priv_table() const
1250 {
1251 return m_tables_priv_table;
1252 }
1253
1254 inline const Columns_priv_table& columns_priv_table() const
1255 {
1256 return m_columns_priv_table;
1257 }
1258
1259 inline const Host_table& host_table() const
1260 {
1261 return m_host_table;
1262 }
1263
1264 inline const Procs_priv_table& procs_priv_table() const
1265 {
1266 return m_procs_priv_table;
1267 }
1268
1269 inline const Proxies_priv_table& proxies_priv_table() const
1270 {
1271 return m_proxies_priv_table;
1272 }
1273
1274 inline const Roles_mapping_table& roles_mapping_table() const
1275 {
1276 return m_roles_mapping_table;
1277 }
1278
1279 private:
1280 User_table m_user_table;
1281 Db_table m_db_table;
1282 Tables_priv_table m_tables_priv_table;
1283 Columns_priv_table m_columns_priv_table;
1284 Host_table m_host_table;
1285 Procs_priv_table m_procs_priv_table;
1286 Proxies_priv_table m_proxies_priv_table;
1287 Roles_mapping_table m_roles_mapping_table;
1288
1289 /* The grant tables are set-up in a linked list. We keep the head of it. */
1290 Grant_table_base *first_table_in_list;
1291 /**
1292 Chain two grant tables' TABLE_LIST members.
1293 */
1294 static void link_tables(Grant_table_base *from, Grant_table_base *to)
1295 {
1296 DBUG_ASSERT(from);
1297 if (to)
1298 from->tl.next_local= from->tl.next_global= &to->tl;
1299 else
1300 from->tl.next_local= from->tl.next_global= NULL;
1301 }
1302};
1303
1304
1305void ACL_PROXY_USER::init(const Proxies_priv_table& proxies_priv_table,
1306 MEM_ROOT *mem)
1307{
1308 init(get_field(mem, proxies_priv_table.host()),
1309 get_field(mem, proxies_priv_table.user()),
1310 get_field(mem, proxies_priv_table.proxied_host()),
1311 get_field(mem, proxies_priv_table.proxied_user()),
1312 proxies_priv_table.with_grant()->val_int() != 0);
1313}
1314
1315
1316
1317/*
1318 Enumeration of various ACL's and Hashes used in handle_grant_struct()
1319*/
1320enum enum_acl_lists
1321{
1322 USER_ACL= 0,
1323 ROLE_ACL,
1324 DB_ACL,
1325 COLUMN_PRIVILEGES_HASH,
1326 PROC_PRIVILEGES_HASH,
1327 FUNC_PRIVILEGES_HASH,
1328 PACKAGE_SPEC_PRIVILEGES_HASH,
1329 PACKAGE_BODY_PRIVILEGES_HASH,
1330 PROXY_USERS_ACL,
1331 ROLES_MAPPINGS_HASH
1332};
1333
1334ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) : counter(0)
1335{
1336
1337 access= user->access;
1338 /* set initial role access the same as the table row privileges */
1339 initial_role_access= user->access;
1340 this->user.str= safe_strdup_root(root, user->user.str);
1341 this->user.length= user->user.length;
1342 bzero(&role_grants, sizeof(role_grants));
1343 bzero(&parent_grantee, sizeof(parent_grantee));
1344 flags= IS_ROLE;
1345}
1346
1347ACL_ROLE::ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *root) :
1348 initial_role_access(privileges), counter(0)
1349{
1350 this->access= initial_role_access;
1351 this->user.str= safe_strdup_root(root, rolename);
1352 this->user.length= strlen(rolename);
1353 bzero(&role_grants, sizeof(role_grants));
1354 bzero(&parent_grantee, sizeof(parent_grantee));
1355 flags= IS_ROLE;
1356}
1357
1358
1359static bool is_invalid_role_name(const char *str)
1360{
1361 if (*str && strcasecmp(str, "PUBLIC") && strcasecmp(str, "NONE"))
1362 return false;
1363
1364 my_error(ER_INVALID_ROLE, MYF(0), str);
1365 return true;
1366}
1367
1368
1369static void free_acl_user(ACL_USER *user)
1370{
1371 delete_dynamic(&(user->role_grants));
1372}
1373
1374static void free_acl_role(ACL_ROLE *role)
1375{
1376 delete_dynamic(&(role->role_grants));
1377 delete_dynamic(&(role->parent_grantee));
1378}
1379
1380static my_bool check_if_exists(THD *, plugin_ref, void *)
1381{
1382 return TRUE;
1383}
1384
1385static bool has_validation_plugins()
1386{
1387 return plugin_foreach(NULL, check_if_exists,
1388 MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
1389}
1390
1391struct validation_data { LEX_CSTRING *user, *password; };
1392
1393static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
1394{
1395 struct validation_data *data= (struct validation_data *)arg;
1396 struct st_mariadb_password_validation *handler=
1397 (st_mariadb_password_validation *)plugin_decl(plugin)->info;
1398 return handler->validate_password(data->user, data->password);
1399}
1400
1401
1402static bool validate_password(LEX_USER *user, THD *thd)
1403{
1404 if (user->pwtext.length || !user->pwhash.length)
1405 {
1406 struct validation_data data= { &user->user,
1407 user->pwtext.str ? &user->pwtext :
1408 const_cast<LEX_CSTRING *>(&empty_clex_str) };
1409 if (plugin_foreach(NULL, do_validate,
1410 MariaDB_PASSWORD_VALIDATION_PLUGIN, &data))
1411 {
1412 my_error(ER_NOT_VALID_PASSWORD, MYF(0));
1413 return true;
1414 }
1415 }
1416 else
1417 {
1418 if (!thd->slave_thread &&
1419 strict_password_validation && has_validation_plugins())
1420 {
1421 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation");
1422 return true;
1423 }
1424 }
1425 return false;
1426}
1427
1428/**
1429 Convert scrambled password to binary form, according to scramble type,
1430 Binary form is stored in user.salt.
1431
1432 @param acl_user The object where to store the salt
1433 @param password The password hash containing the salt
1434 @param password_len The length of the password hash
1435
1436 Despite the name of the function it is used when loading ACLs from disk
1437 to store the password hash in the ACL_USER object.
1438*/
1439
1440static void
1441set_user_salt(ACL_USER *acl_user, const char *password, size_t password_len)
1442{
1443 if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
1444 {
1445 get_salt_from_password(acl_user->salt, password);
1446 acl_user->salt_len= SCRAMBLE_LENGTH;
1447 }
1448 else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
1449 {
1450 get_salt_from_password_323((ulong *) acl_user->salt, password);
1451 acl_user->salt_len= SCRAMBLE_LENGTH_323;
1452 }
1453 else
1454 acl_user->salt_len= 0;
1455}
1456
1457static const char *fix_plugin_ptr(const char *name)
1458{
1459 if (my_strcasecmp(system_charset_info, name,
1460 native_password_plugin_name.str) == 0)
1461 return native_password_plugin_name.str;
1462 else
1463 if (my_strcasecmp(system_charset_info, name,
1464 old_password_plugin_name.str) == 0)
1465 return old_password_plugin_name.str;
1466 else
1467 return name;
1468}
1469
1470/**
1471 Fix ACL::plugin pointer to point to a hard-coded string, if appropriate
1472
1473 Make sure that if ACL_USER's plugin is a built-in, then it points
1474 to a hard coded string, not to an allocated copy. Run-time, for
1475 authentication, we want to be able to detect built-ins by comparing
1476 pointers, not strings.
1477
1478 Additionally - update the salt if the plugin is built-in.
1479
1480 @retval 0 the pointers were fixed
1481 @retval 1 this ACL_USER uses a not built-in plugin
1482*/
1483static bool fix_user_plugin_ptr(ACL_USER *user)
1484{
1485 if (lex_string_eq(&user->plugin, &native_password_plugin_name))
1486 user->plugin= native_password_plugin_name;
1487 else
1488 if (lex_string_eq(&user->plugin, &old_password_plugin_name))
1489 user->plugin= old_password_plugin_name;
1490 else
1491 return true;
1492
1493 if (user->auth_string.length)
1494 set_user_salt(user, user->auth_string.str, user->auth_string.length);
1495 return false;
1496}
1497
1498
1499/*
1500 Validates the password, calculates password hash, transforms
1501 equivalent LEX_USER representations.
1502
1503 Upon entering this function:
1504
1505 - if user->plugin is specified, user->auth is the plugin auth data.
1506 - if user->plugin is mysql_native_password or mysql_old_password,
1507 user->auth is the password hash, and LEX_USER is transformed
1508 to match the next case (that is, user->plugin is cleared).
1509 - if user->plugin is NOT specified, built-in auth is assumed, that is
1510 mysql_native_password or mysql_old_password. In that case,
1511 user->pwhash is the password hash. And user->pwtext is the original
1512 plain-text password. Either one can be set or both.
1513
1514 Upon exiting this function:
1515
1516 - user->pwtext is left untouched
1517 - user->pwhash is the password hash, as the mysql.user.password column
1518 - user->plugin is the plugin name, as the mysql.user.plugin column
1519 - user->auth is the plugin auth data, as the mysql.user.authentication_string column
1520*/
1521static bool fix_lex_user(THD *thd, LEX_USER *user)
1522{
1523 size_t check_length;
1524
1525 DBUG_ASSERT(user->plugin.length || !user->auth.length);
1526 DBUG_ASSERT(!(user->plugin.length && (user->pwtext.length || user->pwhash.length)));
1527
1528 if (lex_string_eq(&user->plugin, &native_password_plugin_name))
1529 check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
1530 else
1531 if (lex_string_eq(&user->plugin, &old_password_plugin_name))
1532 check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
1533 else
1534 if (user->plugin.length)
1535 return false; // nothing else to do
1536 else if (thd->variables.old_passwords == 1 ||
1537 user->pwhash.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
1538 check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
1539 else
1540 check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
1541
1542 if (user->plugin.length)
1543 {
1544 user->pwhash= user->auth;
1545 user->plugin= empty_clex_str;
1546 user->auth= empty_clex_str;
1547 }
1548
1549 if (user->pwhash.length && user->pwhash.length != check_length)
1550 {
1551 my_error(ER_PASSWD_LENGTH, MYF(0), (int) check_length);
1552 return true;
1553 }
1554
1555 if (user->pwtext.length && !user->pwhash.length)
1556 {
1557 size_t scramble_length;
1558 void (*make_scramble)(char *, const char *, size_t);
1559
1560 if (thd->variables.old_passwords == 1)
1561 {
1562 scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
1563 make_scramble= my_make_scrambled_password_323;
1564 }
1565 else
1566 {
1567 scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
1568 make_scramble= my_make_scrambled_password;
1569 }
1570
1571 Query_arena *arena, backup;
1572 arena= thd->activate_stmt_arena_if_needed(&backup);
1573 char *buff= (char *) thd->alloc(scramble_length + 1);
1574 if (arena)
1575 thd->restore_active_arena(arena, &backup);
1576
1577 if (buff == NULL)
1578 return true;
1579 make_scramble(buff, user->pwtext.str, user->pwtext.length);
1580 user->pwhash.str= buff;
1581 user->pwhash.length= scramble_length;
1582 }
1583
1584 return false;
1585}
1586
1587
1588static bool get_YN_as_bool(Field *field)
1589{
1590 char buff[2];
1591 String res(buff,sizeof(buff),&my_charset_latin1);
1592 field->val_str(&res);
1593 return res[0] == 'Y' || res[0] == 'y';
1594}
1595
1596
1597/*
1598 Initialize structures responsible for user/db-level privilege checking and
1599 load privilege information for them from tables in the 'mysql' database.
1600
1601 SYNOPSIS
1602 acl_init()
1603 dont_read_acl_tables TRUE if we want to skip loading data from
1604 privilege tables and disable privilege checking.
1605
1606 NOTES
1607 This function is mostly responsible for preparatory steps, main work
1608 on initialization and grants loading is done in acl_reload().
1609
1610 RETURN VALUES
1611 0 ok
1612 1 Could not initialize grant's
1613*/
1614
1615bool acl_init(bool dont_read_acl_tables)
1616{
1617 THD *thd;
1618 bool return_val;
1619 DBUG_ENTER("acl_init");
1620
1621 acl_cache= new Hash_filo<acl_entry>(ACL_CACHE_SIZE, 0, 0,
1622 (my_hash_get_key) acl_entry_get_key,
1623 (my_hash_free_key) free,
1624 &my_charset_utf8_bin);
1625
1626 /*
1627 cache built-in native authentication plugins,
1628 to avoid hash searches and a global mutex lock on every connect
1629 */
1630 native_password_plugin= my_plugin_lock_by_name(0,
1631 &native_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
1632 old_password_plugin= my_plugin_lock_by_name(0,
1633 &old_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
1634
1635 if (!native_password_plugin || !old_password_plugin)
1636 DBUG_RETURN(1);
1637
1638 if (dont_read_acl_tables)
1639 {
1640 DBUG_RETURN(0); /* purecov: tested */
1641 }
1642
1643 /*
1644 To be able to run this from boot, we allocate a temporary THD
1645 */
1646 if (!(thd=new THD(0)))
1647 DBUG_RETURN(1); /* purecov: inspected */
1648 thd->thread_stack= (char*) &thd;
1649 thd->store_globals();
1650 /*
1651 It is safe to call acl_reload() since acl_* arrays and hashes which
1652 will be freed there are global static objects and thus are initialized
1653 by zeros at startup.
1654 */
1655 return_val= acl_reload(thd);
1656 delete thd;
1657 DBUG_RETURN(return_val);
1658}
1659
1660/**
1661 Choose from either native or old password plugins when assigning a password
1662*/
1663
1664static bool set_user_plugin (ACL_USER *user, size_t password_len)
1665{
1666 switch (password_len)
1667 {
1668 case 0: /* no password */
1669 case SCRAMBLED_PASSWORD_CHAR_LENGTH:
1670 user->plugin= native_password_plugin_name;
1671 return FALSE;
1672 case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
1673 user->plugin= old_password_plugin_name;
1674 return FALSE;
1675 default:
1676 sql_print_warning("Found invalid password for user: '%s@%s'; "
1677 "Ignoring user", safe_str(user->user.str),
1678 safe_str(user->host.hostname));
1679 return TRUE;
1680 }
1681}
1682
1683
1684/*
1685 Initialize structures responsible for user/db-level privilege checking
1686 and load information about grants from open privilege tables.
1687
1688 SYNOPSIS
1689 acl_load()
1690 thd Current thread
1691 tables List containing open "mysql.host", "mysql.user",
1692 "mysql.db", "mysql.proxies_priv" and "mysql.roles_mapping"
1693 tables.
1694
1695 RETURN VALUES
1696 FALSE Success
1697 TRUE Error
1698*/
1699
1700static bool acl_load(THD *thd, const Grant_tables& tables)
1701{
1702 READ_RECORD read_record_info;
1703 bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
1704 char tmp_name[SAFE_NAME_LEN+1];
1705 int password_length;
1706 Sql_mode_save old_mode_save(thd);
1707 DBUG_ENTER("acl_load");
1708
1709 thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
1710
1711 grant_version++; /* Privileges updated */
1712
1713 const Host_table& host_table= tables.host_table();
1714 init_sql_alloc(&acl_memroot, "ACL", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
1715 if (host_table.table_exists()) // "host" table may not exist (e.g. in MySQL 5.6.7+)
1716 {
1717 if (host_table.init_read_record(&read_record_info, thd))
1718 DBUG_RETURN(true);
1719 while (!(read_record_info.read_record()))
1720 {
1721 ACL_HOST host;
1722 update_hostname(&host.host, get_field(&acl_memroot, host_table.host()));
1723 host.db= get_field(&acl_memroot, host_table.db());
1724 if (lower_case_table_names && host.db)
1725 {
1726 /*
1727 convert db to lower case and give a warning if the db wasn't
1728 already in lower case
1729 */
1730 char *end = strnmov(tmp_name, host.db, sizeof(tmp_name));
1731 if (end >= tmp_name + sizeof(tmp_name))
1732 {
1733 sql_print_warning(ER_THD(thd, ER_WRONG_DB_NAME), host.db);
1734 continue;
1735 }
1736 my_casedn_str(files_charset_info, host.db);
1737 if (strcmp(host.db, tmp_name) != 0)
1738 sql_print_warning("'host' entry '%s|%s' had database in mixed "
1739 "case that has been forced to lowercase because "
1740 "lower_case_table_names is set. It will not be "
1741 "possible to remove this privilege using REVOKE.",
1742 host.host.hostname, host.db);
1743 }
1744 host.access= host_table.get_access();
1745 host.access= fix_rights_for_db(host.access);
1746 host.sort= get_sort(2, host.host.hostname, host.db);
1747 if (check_no_resolve && hostname_requires_resolving(host.host.hostname))
1748 {
1749 sql_print_warning("'host' entry '%s|%s' "
1750 "ignored in --skip-name-resolve mode.",
1751 safe_str(host.host.hostname),
1752 safe_str(host.db));
1753 continue;
1754 }
1755#ifndef TO_BE_REMOVED
1756 if (host_table.num_fields() == 8)
1757 { // Without grant
1758 if (host.access & CREATE_ACL)
1759 host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
1760 }
1761#endif
1762 (void) push_dynamic(&acl_hosts,(uchar*) &host);
1763 }
1764 my_qsort((uchar*) dynamic_element(&acl_hosts, 0, ACL_HOST*),
1765 acl_hosts.elements, sizeof(ACL_HOST),(qsort_cmp) acl_compare);
1766 end_read_record(&read_record_info);
1767 }
1768 freeze_size(&acl_hosts);
1769
1770 const User_table& user_table= tables.user_table();
1771 if (user_table.init_read_record(&read_record_info, thd))
1772 DBUG_RETURN(true);
1773
1774 username_char_length= MY_MIN(user_table.user()->char_length(),
1775 USERNAME_CHAR_LENGTH);
1776 if (user_table.password()) // Password column might be missing. (MySQL 5.7.6+)
1777 {
1778 password_length= user_table.password()->field_length /
1779 user_table.password()->charset()->mbmaxlen;
1780 if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
1781 {
1782 sql_print_error("Fatal error: mysql.user table is damaged or in "
1783 "unsupported 3.20 format.");
1784 DBUG_RETURN(TRUE);
1785 }
1786
1787 DBUG_PRINT("info",("user table fields: %d, password length: %d",
1788 user_table.num_fields(), password_length));
1789
1790 mysql_mutex_lock(&LOCK_global_system_variables);
1791 if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
1792 {
1793 if (opt_secure_auth)
1794 {
1795 mysql_mutex_unlock(&LOCK_global_system_variables);
1796 sql_print_error("Fatal error: mysql.user table is in old format, "
1797 "but server started with --secure-auth option.");
1798 DBUG_RETURN(TRUE);
1799 }
1800 mysql_user_table_is_in_short_password_format= true;
1801 if (global_system_variables.old_passwords)
1802 mysql_mutex_unlock(&LOCK_global_system_variables);
1803 else
1804 {
1805 extern sys_var *Sys_old_passwords_ptr;
1806 Sys_old_passwords_ptr->value_origin= sys_var::AUTO;
1807 global_system_variables.old_passwords= 1;
1808 mysql_mutex_unlock(&LOCK_global_system_variables);
1809 sql_print_warning("mysql.user table is not updated to new password format; "
1810 "Disabling new password usage until "
1811 "mysql_fix_privilege_tables is run");
1812 }
1813 thd->variables.old_passwords= 1;
1814 }
1815 else
1816 {
1817 mysql_user_table_is_in_short_password_format= false;
1818 mysql_mutex_unlock(&LOCK_global_system_variables);
1819 }
1820 }
1821
1822 allow_all_hosts=0;
1823 while (!(read_record_info.read_record()))
1824 {
1825 ACL_USER user;
1826 bool is_role= FALSE;
1827 bzero(&user, sizeof(user));
1828 update_hostname(&user.host, get_field(&acl_memroot, user_table.host()));
1829 char *username= get_field(&acl_memroot, user_table.user());
1830 user.user.str= username;
1831 user.user.length= safe_strlen(username);
1832
1833 /*
1834 If the user entry is a role, skip password and hostname checks
1835 A user can not log in with a role so some checks are not necessary
1836 */
1837 is_role= user_table.check_is_role();
1838
1839 if (is_role && is_invalid_role_name(username))
1840 {
1841 thd->clear_error(); // the warning is still issued
1842 continue;
1843 }
1844
1845 if (!is_role && check_no_resolve &&
1846 hostname_requires_resolving(user.host.hostname))
1847 {
1848 sql_print_warning("'user' entry '%s@%s' "
1849 "ignored in --skip-name-resolve mode.",
1850 safe_str(user.user.str),
1851 safe_str(user.host.hostname));
1852 continue;
1853 }
1854
1855 char *password= const_cast<char*>("");
1856 if (user_table.password())
1857 password= get_field(&acl_memroot, user_table.password());
1858 size_t password_len= safe_strlen(password);
1859 user.auth_string.str= safe_str(password);
1860 user.auth_string.length= password_len;
1861 set_user_salt(&user, password, password_len);
1862
1863 if (!is_role && set_user_plugin(&user, password_len))
1864 continue;
1865
1866 {
1867 user.access= user_table.get_access() & GLOBAL_ACLS;
1868 /*
1869 if it is pre 5.0.1 privilege table then map CREATE privilege on
1870 CREATE VIEW & SHOW VIEW privileges
1871 */
1872 if (user_table.num_fields() <= 31 && (user.access & CREATE_ACL))
1873 user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
1874
1875 /*
1876 if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
1877 CREATE PROCEDURE & ALTER PROCEDURE privileges
1878 */
1879 if (user_table.num_fields() <= 33 && (user.access & CREATE_ACL))
1880 user.access|= CREATE_PROC_ACL;
1881 if (user_table.num_fields() <= 33 && (user.access & ALTER_ACL))
1882 user.access|= ALTER_PROC_ACL;
1883
1884 /*
1885 pre 5.0.3 did not have CREATE_USER_ACL
1886 */
1887 if (user_table.num_fields() <= 36 && (user.access & GRANT_ACL))
1888 user.access|= CREATE_USER_ACL;
1889
1890
1891 /*
1892 if it is pre 5.1.6 privilege table then map CREATE privilege on
1893 CREATE|ALTER|DROP|EXECUTE EVENT
1894 */
1895 if (user_table.num_fields() <= 37 && (user.access & SUPER_ACL))
1896 user.access|= EVENT_ACL;
1897
1898 /*
1899 if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
1900 */
1901 if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL))
1902 user.access|= TRIGGER_ACL;
1903
1904 if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL))
1905 user.access|= DELETE_HISTORY_ACL;
1906
1907 user.sort= get_sort(2, user.host.hostname, user.user.str);
1908 user.hostname_length= safe_strlen(user.host.hostname);
1909 user.user_resource.user_conn= 0;
1910 user.user_resource.max_statement_time= 0.0;
1911
1912 /* Starting from 4.0.2 we have more fields */
1913 if (user_table.ssl_type())
1914 {
1915 char *ssl_type=get_field(thd->mem_root, user_table.ssl_type());
1916 if (!ssl_type)
1917 user.ssl_type=SSL_TYPE_NONE;
1918 else if (!strcmp(ssl_type, "ANY"))
1919 user.ssl_type=SSL_TYPE_ANY;
1920 else if (!strcmp(ssl_type, "X509"))
1921 user.ssl_type=SSL_TYPE_X509;
1922 else /* !strcmp(ssl_type, "SPECIFIED") */
1923 user.ssl_type=SSL_TYPE_SPECIFIED;
1924
1925 user.ssl_cipher= get_field(&acl_memroot, user_table.ssl_cipher());
1926 user.x509_issuer= get_field(&acl_memroot, user_table.x509_issuer());
1927 user.x509_subject= get_field(&acl_memroot, user_table.x509_subject());
1928
1929 char *ptr = get_field(thd->mem_root, user_table.max_questions());
1930 user.user_resource.questions=ptr ? atoi(ptr) : 0;
1931 ptr = get_field(thd->mem_root, user_table.max_updates());
1932 user.user_resource.updates=ptr ? atoi(ptr) : 0;
1933 ptr = get_field(thd->mem_root, user_table.max_connections());
1934 user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
1935 if (user.user_resource.questions || user.user_resource.updates ||
1936 user.user_resource.conn_per_hour)
1937 mqh_used=1;
1938
1939 if (user_table.max_user_connections())
1940 {
1941 /* Starting from 5.0.3 we have max_user_connections field */
1942 ptr= get_field(thd->mem_root, user_table.max_user_connections());
1943 user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
1944 }
1945
1946 if (!is_role && user_table.plugin())
1947 {
1948 /* We may have plugin & auth_String fields */
1949 char *tmpstr= get_field(&acl_memroot, user_table.plugin());
1950 if (tmpstr)
1951 {
1952 user.plugin.str= tmpstr;
1953 user.plugin.length= strlen(user.plugin.str);
1954 user.auth_string.str=
1955 safe_str(get_field(&acl_memroot,
1956 user_table.authentication_string()));
1957 user.auth_string.length= strlen(user.auth_string.str);
1958
1959 if (user.auth_string.length && password_len)
1960 {
1961 sql_print_warning("'user' entry '%s@%s' has both a password "
1962 "and an authentication plugin specified. The "
1963 "password will be ignored.",
1964 safe_str(user.user.str),
1965 safe_str(user.host.hostname));
1966 }
1967
1968 fix_user_plugin_ptr(&user);
1969 }
1970 }
1971
1972 if (user_table.max_statement_time())
1973 {
1974 /* Starting from 10.1.1 we can have max_statement_time */
1975 ptr= get_field(thd->mem_root,
1976 user_table.max_statement_time());
1977 user.user_resource.max_statement_time= ptr ? atof(ptr) : 0.0;
1978 }
1979 }
1980 else
1981 {
1982 user.ssl_type=SSL_TYPE_NONE;
1983#ifndef TO_BE_REMOVED
1984 if (user_table.num_fields() <= 13)
1985 { // Without grant
1986 if (user.access & CREATE_ACL)
1987 user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
1988 }
1989 /* Convert old privileges */
1990 user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
1991 if (user.access & FILE_ACL)
1992 user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
1993 if (user.access & PROCESS_ACL)
1994 user.access|= SUPER_ACL | EXECUTE_ACL;
1995#endif
1996 }
1997
1998 (void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_ROLE *),
1999 8, 8, MYF(0));
2000
2001 /* check default role, if any */
2002 if (!is_role && user_table.default_role())
2003 {
2004 user.default_rolename.str=
2005 get_field(&acl_memroot, user_table.default_role());
2006 user.default_rolename.length= safe_strlen(user.default_rolename.str);
2007 }
2008
2009 if (is_role)
2010 {
2011 DBUG_PRINT("info", ("Found role %s", user.user.str));
2012 ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
2013 entry->role_grants = user.role_grants;
2014 (void) my_init_dynamic_array(&entry->parent_grantee,
2015 sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
2016 my_hash_insert(&acl_roles, (uchar *)entry);
2017
2018 continue;
2019 }
2020 else
2021 {
2022 DBUG_PRINT("info", ("Found user %s", user.user.str));
2023 (void) push_dynamic(&acl_users,(uchar*) &user);
2024 }
2025 if (!user.host.hostname ||
2026 (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
2027 allow_all_hosts=1; // Anyone can connect
2028 }
2029 }
2030 my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
2031 sizeof(ACL_USER),(qsort_cmp) acl_compare);
2032 end_read_record(&read_record_info);
2033 freeze_size(&acl_users);
2034
2035 const Db_table& db_table= tables.db_table();
2036 if (db_table.init_read_record(&read_record_info, thd))
2037 DBUG_RETURN(TRUE);
2038 while (!(read_record_info.read_record()))
2039 {
2040 ACL_DB db;
2041 char *db_name;
2042 db.user=get_field(&acl_memroot, db_table.user());
2043 const char *hostname= get_field(&acl_memroot, db_table.host());
2044 if (!hostname && find_acl_role(db.user))
2045 hostname= "";
2046 update_hostname(&db.host, hostname);
2047 db.db= db_name= get_field(&acl_memroot, db_table.db());
2048 if (!db.db)
2049 {
2050 sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
2051 continue;
2052 }
2053 if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
2054 {
2055 sql_print_warning("'db' entry '%s %s@%s' "
2056 "ignored in --skip-name-resolve mode.",
2057 db.db, safe_str(db.user), safe_str(db.host.hostname));
2058 continue;
2059 }
2060 db.access= db_table.get_access();
2061 db.access=fix_rights_for_db(db.access);
2062 db.initial_access= db.access;
2063 if (lower_case_table_names)
2064 {
2065 /*
2066 convert db to lower case and give a warning if the db wasn't
2067 already in lower case
2068 */
2069 char *end = strnmov(tmp_name, db.db, sizeof(tmp_name));
2070 if (end >= tmp_name + sizeof(tmp_name))
2071 {
2072 sql_print_warning(ER_THD(thd, ER_WRONG_DB_NAME), db.db);
2073 continue;
2074 }
2075 my_casedn_str(files_charset_info, db_name);
2076 if (strcmp(db_name, tmp_name) != 0)
2077 {
2078 sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
2079 "case that has been forced to lowercase because "
2080 "lower_case_table_names is set. It will not be "
2081 "possible to remove this privilege using REVOKE.",
2082 db.db, safe_str(db.user), safe_str(db.host.hostname));
2083 }
2084 }
2085 db.sort=get_sort(3,db.host.hostname,db.db,db.user);
2086#ifndef TO_BE_REMOVED
2087 if (db_table.num_fields() <= 9)
2088 { // Without grant
2089 if (db.access & CREATE_ACL)
2090 db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
2091 }
2092#endif
2093 (void) push_dynamic(&acl_dbs,(uchar*) &db);
2094 }
2095 my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
2096 sizeof(ACL_DB),(qsort_cmp) acl_compare);
2097 end_read_record(&read_record_info);
2098 freeze_size(&acl_dbs);
2099
2100 const Proxies_priv_table& proxies_priv_table= tables.proxies_priv_table();
2101 if (proxies_priv_table.table_exists())
2102 {
2103 if (proxies_priv_table.init_read_record(&read_record_info, thd))
2104 DBUG_RETURN(TRUE);
2105 while (!(read_record_info.read_record()))
2106 {
2107 ACL_PROXY_USER proxy;
2108 proxy.init(proxies_priv_table, &acl_memroot);
2109 if (proxy.check_validity(check_no_resolve))
2110 continue;
2111 if (push_dynamic(&acl_proxy_users, (uchar*) &proxy))
2112 DBUG_RETURN(TRUE);
2113 }
2114 my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*),
2115 acl_proxy_users.elements,
2116 sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
2117 end_read_record(&read_record_info);
2118 }
2119 else
2120 {
2121 sql_print_error("Missing system table mysql.proxies_priv; "
2122 "please run mysql_upgrade to create it");
2123 }
2124 freeze_size(&acl_proxy_users);
2125
2126 const Roles_mapping_table& roles_mapping_table= tables.roles_mapping_table();
2127 if (roles_mapping_table.table_exists())
2128 {
2129 if (roles_mapping_table.init_read_record(&read_record_info, thd))
2130 DBUG_RETURN(TRUE);
2131
2132 MEM_ROOT temp_root;
2133 init_alloc_root(&temp_root, "ACL_tmp", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
2134 while (!(read_record_info.read_record()))
2135 {
2136 char *hostname= safe_str(get_field(&temp_root, roles_mapping_table.host()));
2137 char *username= safe_str(get_field(&temp_root, roles_mapping_table.user()));
2138 char *rolename= safe_str(get_field(&temp_root, roles_mapping_table.role()));
2139 bool with_grant_option= get_YN_as_bool(roles_mapping_table.admin_option());
2140
2141 if (add_role_user_mapping(username, hostname, rolename)) {
2142 sql_print_error("Invalid roles_mapping table entry user:'%s@%s', rolename:'%s'",
2143 username, hostname, rolename);
2144 continue;
2145 }
2146
2147 ROLE_GRANT_PAIR *mapping= new (&acl_memroot) ROLE_GRANT_PAIR;
2148
2149 if (mapping->init(&acl_memroot, username, hostname, rolename, with_grant_option))
2150 continue;
2151
2152 my_hash_insert(&acl_roles_mappings, (uchar*) mapping);
2153 }
2154
2155 free_root(&temp_root, MYF(0));
2156 end_read_record(&read_record_info);
2157 }
2158 else
2159 {
2160 sql_print_error("Missing system table mysql.roles_mapping; "
2161 "please run mysql_upgrade to create it");
2162 }
2163
2164 init_check_host();
2165
2166 initialized=1;
2167 DBUG_RETURN(FALSE);
2168}
2169
2170
2171void acl_free(bool end)
2172{
2173 my_hash_free(&acl_roles);
2174 free_root(&acl_memroot,MYF(0));
2175 delete_dynamic(&acl_hosts);
2176 delete_dynamic_with_callback(&acl_users, (FREE_FUNC) free_acl_user);
2177 delete_dynamic(&acl_dbs);
2178 delete_dynamic(&acl_wild_hosts);
2179 delete_dynamic(&acl_proxy_users);
2180 my_hash_free(&acl_check_hosts);
2181 my_hash_free(&acl_roles_mappings);
2182 if (!end)
2183 acl_cache->clear(1); /* purecov: inspected */
2184 else
2185 {
2186 plugin_unlock(0, native_password_plugin);
2187 plugin_unlock(0, old_password_plugin);
2188 delete acl_cache;
2189 acl_cache=0;
2190 }
2191}
2192
2193
2194/*
2195 Forget current user/db-level privileges and read new privileges
2196 from the privilege tables.
2197
2198 SYNOPSIS
2199 acl_reload()
2200 thd Current thread
2201
2202 NOTE
2203 All tables of calling thread which were open and locked by LOCK TABLES
2204 statement will be unlocked and closed.
2205 This function is also used for initialization of structures responsible
2206 for user/db-level privilege checking.
2207
2208 RETURN VALUE
2209 FALSE Success
2210 TRUE Failure
2211*/
2212
2213bool acl_reload(THD *thd)
2214{
2215 DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users;
2216 HASH old_acl_roles, old_acl_roles_mappings;
2217 MEM_ROOT old_mem;
2218 int result;
2219 DBUG_ENTER("acl_reload");
2220
2221 Grant_tables tables(Table_host | Table_user | Table_db | Table_proxies_priv |
2222 Table_roles_mapping, TL_READ);
2223 /*
2224 To avoid deadlocks we should obtain table locks before
2225 obtaining acl_cache->lock mutex.
2226 */
2227 if (unlikely((result= tables.open_and_lock(thd))))
2228 {
2229 DBUG_ASSERT(result <= 0);
2230 /*
2231 Execution might have been interrupted; only print the error message
2232 if an error condition has been raised.
2233 */
2234 if (thd->get_stmt_da()->is_error())
2235 sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
2236 thd->get_stmt_da()->message());
2237 goto end;
2238 }
2239
2240 acl_cache->clear(0);
2241 mysql_mutex_lock(&acl_cache->lock);
2242
2243 old_acl_hosts= acl_hosts;
2244 old_acl_users= acl_users;
2245 old_acl_roles= acl_roles;
2246 old_acl_roles_mappings= acl_roles_mappings;
2247 old_acl_proxy_users= acl_proxy_users;
2248 old_acl_dbs= acl_dbs;
2249 my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0));
2250 my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0));
2251 my_init_dynamic_array(&acl_dbs, sizeof(ACL_DB), 50, 100, MYF(0));
2252 my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0));
2253 my_hash_init2(&acl_roles,50, &my_charset_utf8_bin,
2254 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0,
2255 (void (*)(void *))free_acl_role, 0);
2256 my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0,
2257 (my_hash_get_key) acl_role_map_get_key, 0, 0, 0);
2258 old_mem= acl_memroot;
2259 delete_dynamic(&acl_wild_hosts);
2260 my_hash_free(&acl_check_hosts);
2261
2262 if ((result= acl_load(thd, tables)))
2263 { // Error. Revert to old list
2264 DBUG_PRINT("error",("Reverting to old privileges"));
2265 acl_free(); /* purecov: inspected */
2266 acl_hosts= old_acl_hosts;
2267 acl_users= old_acl_users;
2268 acl_roles= old_acl_roles;
2269 acl_roles_mappings= old_acl_roles_mappings;
2270 acl_proxy_users= old_acl_proxy_users;
2271 acl_dbs= old_acl_dbs;
2272 acl_memroot= old_mem;
2273 init_check_host();
2274 }
2275 else
2276 {
2277 my_hash_free(&old_acl_roles);
2278 free_root(&old_mem,MYF(0));
2279 delete_dynamic(&old_acl_hosts);
2280 delete_dynamic_with_callback(&old_acl_users, (FREE_FUNC) free_acl_user);
2281 delete_dynamic(&old_acl_proxy_users);
2282 delete_dynamic(&old_acl_dbs);
2283 my_hash_free(&old_acl_roles_mappings);
2284 }
2285 mysql_mutex_unlock(&acl_cache->lock);
2286end:
2287 close_mysql_tables(thd);
2288 DBUG_RETURN(result);
2289}
2290
2291/*
2292 Get all access bits from table after fieldnr
2293
2294 IMPLEMENTATION
2295 We know that the access privileges ends when there is no more fields
2296 or the field is not an enum with two elements.
2297
2298 SYNOPSIS
2299 get_access()
2300 form an open table to read privileges from.
2301 The record should be already read in table->record[0]
2302 fieldnr number of the first privilege (that is ENUM('N','Y') field
2303 next_field on return - number of the field next to the last ENUM
2304 (unless next_field == 0)
2305
2306 RETURN VALUE
2307 privilege mask
2308*/
2309
2310static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
2311{
2312 ulong access_bits=0,bit;
2313 char buff[2];
2314 String res(buff,sizeof(buff),&my_charset_latin1);
2315 Field **pos;
2316
2317 for (pos=form->field+fieldnr, bit=1;
2318 *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
2319 ((Field_enum*) (*pos))->typelib->count == 2 ;
2320 pos++, fieldnr++, bit<<=1)
2321 {
2322 if (get_YN_as_bool(*pos))
2323 access_bits|= bit;
2324 }
2325 if (next_field)
2326 *next_field=fieldnr;
2327 return access_bits;
2328}
2329
2330
2331/*
2332 Return a number which, if sorted 'desc', puts strings in this order:
2333 no wildcards
2334 wildcards
2335 empty string
2336*/
2337
2338static ulong get_sort(uint count,...)
2339{
2340 va_list args;
2341 va_start(args,count);
2342 ulong sort=0;
2343
2344 /* Should not use this function with more than 4 arguments for compare. */
2345 DBUG_ASSERT(count <= 4);
2346
2347 while (count--)
2348 {
2349 char *start, *str= va_arg(args,char*);
2350 uint chars= 0;
2351 uint wild_pos= 0; /* first wildcard position */
2352
2353 if ((start= str))
2354 {
2355 for (; *str ; str++)
2356 {
2357 if (*str == wild_prefix && str[1])
2358 str++;
2359 else if (*str == wild_many || *str == wild_one)
2360 {
2361 wild_pos= (uint) (str - start) + 1;
2362 break;
2363 }
2364 chars= 128; // Marker that chars existed
2365 }
2366 }
2367 sort= (sort << 8) + (wild_pos ? MY_MIN(wild_pos, 127U) : chars);
2368 }
2369 va_end(args);
2370 return sort;
2371}
2372
2373
2374static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
2375{
2376 if (a->sort > b->sort)
2377 return -1;
2378 if (a->sort < b->sort)
2379 return 1;
2380 return 0;
2381}
2382
2383
2384/*
2385 Gets user credentials without authentication and resource limit checks.
2386
2387 SYNOPSIS
2388 acl_getroot()
2389 sctx Context which should be initialized
2390 user user name
2391 host host name
2392 ip IP
2393 db current data base name
2394
2395 RETURN
2396 FALSE OK
2397 TRUE Error
2398*/
2399
2400bool acl_getroot(Security_context *sctx, const char *user, const char *host,
2401 const char *ip, const char *db)
2402{
2403 int res= 1;
2404 uint i;
2405 ACL_USER *acl_user= 0;
2406 DBUG_ENTER("acl_getroot");
2407
2408 DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
2409 host, ip, user, db));
2410 sctx->user= user;
2411 sctx->host= host;
2412 sctx->ip= ip;
2413 sctx->host_or_ip= host ? host : (safe_str(ip));
2414
2415 if (!initialized)
2416 {
2417 /*
2418 here if mysqld's been started with --skip-grant-tables option.
2419 */
2420 sctx->skip_grants();
2421 DBUG_RETURN(FALSE);
2422 }
2423
2424 mysql_mutex_lock(&acl_cache->lock);
2425
2426 sctx->master_access= 0;
2427 sctx->db_access= 0;
2428 *sctx->priv_user= *sctx->priv_host= *sctx->priv_role= 0;
2429
2430 if (host[0]) // User, not Role
2431 {
2432 acl_user= find_user_wild(host, user, ip);
2433
2434 if (acl_user)
2435 {
2436 res= 0;
2437 for (i=0 ; i < acl_dbs.elements ; i++)
2438 {
2439 ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
2440 if (!acl_db->user ||
2441 (user && user[0] && !strcmp(user, acl_db->user)))
2442 {
2443 if (compare_hostname(&acl_db->host, host, ip))
2444 {
2445 if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
2446 {
2447 sctx->db_access= acl_db->access;
2448 break;
2449 }
2450 }
2451 }
2452 }
2453 sctx->master_access= acl_user->access;
2454
2455 if (acl_user->user.str)
2456 strmake_buf(sctx->priv_user, user);
2457
2458 if (acl_user->host.hostname)
2459 strmake_buf(sctx->priv_host, acl_user->host.hostname);
2460 }
2461 }
2462 else // Role, not User
2463 {
2464 ACL_ROLE *acl_role= find_acl_role(user);
2465 if (acl_role)
2466 {
2467 res= 0;
2468 for (i=0 ; i < acl_dbs.elements ; i++)
2469 {
2470 ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
2471 if (!acl_db->user ||
2472 (user && user[0] && !strcmp(user, acl_db->user)))
2473 {
2474 if (compare_hostname(&acl_db->host, "", ""))
2475 {
2476 if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
2477 {
2478 sctx->db_access= acl_db->access;
2479 break;
2480 }
2481 }
2482 }
2483 }
2484 sctx->master_access= acl_role->access;
2485
2486 if (acl_role->user.str)
2487 strmake_buf(sctx->priv_role, user);
2488 }
2489 }
2490
2491 mysql_mutex_unlock(&acl_cache->lock);
2492 DBUG_RETURN(res);
2493}
2494
2495static int check_user_can_set_role(const char *user, const char *host,
2496 const char *ip, const char *rolename, ulonglong *access)
2497{
2498 ACL_ROLE *role;
2499 ACL_USER_BASE *acl_user_base;
2500 ACL_USER *UNINIT_VAR(acl_user);
2501 bool is_granted= FALSE;
2502 int result= 0;
2503
2504 /* clear role privileges */
2505 mysql_mutex_lock(&acl_cache->lock);
2506
2507 if (!strcasecmp(rolename, "NONE"))
2508 {
2509 /* have to clear the privileges */
2510 /* get the current user */
2511 acl_user= find_user_wild(host, user, ip);
2512 if (acl_user == NULL)
2513 {
2514 my_error(ER_INVALID_CURRENT_USER, MYF(0));
2515 result= -1;
2516 }
2517 else if (access)
2518 *access= acl_user->access;
2519
2520 goto end;
2521 }
2522
2523 role= find_acl_role(rolename);
2524
2525 /* According to SQL standard, the same error message must be presented */
2526 if (role == NULL) {
2527 my_error(ER_INVALID_ROLE, MYF(0), rolename);
2528 result= -1;
2529 goto end;
2530 }
2531
2532 for (uint i=0 ; i < role->parent_grantee.elements ; i++)
2533 {
2534 acl_user_base= *(dynamic_element(&role->parent_grantee, i, ACL_USER_BASE**));
2535 if (acl_user_base->flags & IS_ROLE)
2536 continue;
2537
2538 acl_user= (ACL_USER *)acl_user_base;
2539 if (acl_user->wild_eq(user, host, ip))
2540 {
2541 is_granted= TRUE;
2542 break;
2543 }
2544 }
2545
2546 /* According to SQL standard, the same error message must be presented */
2547 if (!is_granted)
2548 {
2549 my_error(ER_INVALID_ROLE, MYF(0), rolename);
2550 result= 1;
2551 goto end;
2552 }
2553
2554 if (access)
2555 {
2556 *access = acl_user->access | role->access;
2557 }
2558end:
2559 mysql_mutex_unlock(&acl_cache->lock);
2560 return result;
2561
2562}
2563
2564int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access)
2565{
2566 /* Yes! priv_user@host. Don't ask why - that's what check_access() does. */
2567 return check_user_can_set_role(thd->security_ctx->priv_user,
2568 thd->security_ctx->host, thd->security_ctx->ip, rolename, access);
2569}
2570
2571
2572int acl_setrole(THD *thd, const char *rolename, ulonglong access)
2573{
2574 /* merge the privileges */
2575 Security_context *sctx= thd->security_ctx;
2576 sctx->master_access= static_cast<ulong>(access);
2577 if (thd->db.str)
2578 sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db.str, FALSE);
2579
2580 if (!strcasecmp(rolename, "NONE"))
2581 {
2582 thd->security_ctx->priv_role[0]= 0;
2583 }
2584 else
2585 {
2586 if (thd->db.str)
2587 sctx->db_access|= acl_get("", "", rolename, thd->db.str, FALSE);
2588 /* mark the current role */
2589 strmake_buf(thd->security_ctx->priv_role, rolename);
2590 }
2591 return 0;
2592}
2593
2594static uchar* check_get_key(ACL_USER *buff, size_t *length,
2595 my_bool not_used __attribute__((unused)))
2596{
2597 *length=buff->hostname_length;
2598 return (uchar*) buff->host.hostname;
2599}
2600
2601
2602static void acl_update_role(const char *rolename, ulong privileges)
2603{
2604 ACL_ROLE *role= find_acl_role(rolename);
2605 if (role)
2606 role->initial_role_access= role->access= privileges;
2607}
2608
2609
2610static void acl_update_user(const char *user, const char *host,
2611 const char *password, size_t password_len,
2612 enum SSL_type ssl_type,
2613 const char *ssl_cipher,
2614 const char *x509_issuer,
2615 const char *x509_subject,
2616 USER_RESOURCES *mqh,
2617 ulong privileges,
2618 const LEX_CSTRING *plugin,
2619 const LEX_CSTRING *auth)
2620{
2621 mysql_mutex_assert_owner(&acl_cache->lock);
2622
2623 for (uint i=0 ; i < acl_users.elements ; i++)
2624 {
2625 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
2626 if (acl_user->eq(user, host))
2627 {
2628 if (plugin->str[0])
2629 {
2630 acl_user->plugin= *plugin;
2631 acl_user->auth_string.str= auth->str ?
2632 strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>("");
2633 acl_user->auth_string.length= auth->length;
2634 if (fix_user_plugin_ptr(acl_user))
2635 acl_user->plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
2636 }
2637 else
2638 if (password[0])
2639 {
2640 acl_user->auth_string.str= strmake_root(&acl_memroot, password, password_len);
2641 acl_user->auth_string.length= password_len;
2642 set_user_salt(acl_user, password, password_len);
2643 set_user_plugin(acl_user, password_len);
2644 }
2645 acl_user->access=privileges;
2646 if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
2647 acl_user->user_resource.questions=mqh->questions;
2648 if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
2649 acl_user->user_resource.updates=mqh->updates;
2650 if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
2651 acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
2652 if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
2653 acl_user->user_resource.user_conn= mqh->user_conn;
2654 if (mqh->specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
2655 acl_user->user_resource.max_statement_time= mqh->max_statement_time;
2656 if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
2657 {
2658 acl_user->ssl_type= ssl_type;
2659 acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) :
2660 0);
2661 acl_user->x509_issuer= (x509_issuer ? strdup_root(&acl_memroot,x509_issuer) :
2662 0);
2663 acl_user->x509_subject= (x509_subject ?
2664 strdup_root(&acl_memroot,x509_subject) : 0);
2665 }
2666 /* search complete: */
2667 break;
2668 }
2669 }
2670}
2671
2672
2673static void acl_insert_role(const char *rolename, ulong privileges)
2674{
2675 ACL_ROLE *entry;
2676
2677 mysql_mutex_assert_owner(&acl_cache->lock);
2678 entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot);
2679 (void) my_init_dynamic_array(&entry->parent_grantee,
2680 sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
2681 (void) my_init_dynamic_array(&entry->role_grants,sizeof(ACL_ROLE *),
2682 8, 8, MYF(0));
2683
2684 my_hash_insert(&acl_roles, (uchar *)entry);
2685}
2686
2687
2688static void acl_insert_user(const char *user, const char *host,
2689 const char *password, size_t password_len,
2690 enum SSL_type ssl_type,
2691 const char *ssl_cipher,
2692 const char *x509_issuer,
2693 const char *x509_subject,
2694 USER_RESOURCES *mqh,
2695 ulong privileges,
2696 const LEX_CSTRING *plugin,
2697 const LEX_CSTRING *auth)
2698{
2699 ACL_USER acl_user;
2700
2701 mysql_mutex_assert_owner(&acl_cache->lock);
2702
2703 bzero(&acl_user, sizeof(acl_user));
2704 acl_user.user.str=*user ? strdup_root(&acl_memroot,user) : 0;
2705 acl_user.user.length= strlen(user);
2706 update_hostname(&acl_user.host, safe_strdup_root(&acl_memroot, host));
2707 if (plugin->str[0])
2708 {
2709 acl_user.plugin= *plugin;
2710 acl_user.auth_string.str= auth->str ?
2711 strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>("");
2712 acl_user.auth_string.length= auth->length;
2713 if (fix_user_plugin_ptr(&acl_user))
2714 acl_user.plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
2715 }
2716 else
2717 {
2718 acl_user.auth_string.str= strmake_root(&acl_memroot, password, password_len);
2719 acl_user.auth_string.length= password_len;
2720 set_user_salt(&acl_user, password, password_len);
2721 set_user_plugin(&acl_user, password_len);
2722 }
2723
2724 acl_user.flags= 0;
2725 acl_user.access=privileges;
2726 acl_user.user_resource = *mqh;
2727 acl_user.sort=get_sort(2, acl_user.host.hostname, acl_user.user.str);
2728 acl_user.hostname_length=(uint) strlen(host);
2729 acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
2730 ssl_type : SSL_TYPE_NONE);
2731 acl_user.ssl_cipher= ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) : 0;
2732 acl_user.x509_issuer= x509_issuer ? strdup_root(&acl_memroot,x509_issuer) : 0;
2733 acl_user.x509_subject=x509_subject ? strdup_root(&acl_memroot,x509_subject) : 0;
2734 (void) my_init_dynamic_array(&acl_user.role_grants, sizeof(ACL_USER *),
2735 8, 8, MYF(0));
2736
2737 (void) push_dynamic(&acl_users,(uchar*) &acl_user);
2738 if (!acl_user.host.hostname ||
2739 (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
2740 allow_all_hosts=1; // Anyone can connect /* purecov: tested */
2741 my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
2742 sizeof(ACL_USER),(qsort_cmp) acl_compare);
2743
2744 /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
2745 rebuild_check_host();
2746
2747 /*
2748 Rebuild every user's role_grants since 'acl_users' has been sorted
2749 and old pointers to ACL_USER elements are no longer valid
2750 */
2751 rebuild_role_grants();
2752}
2753
2754
2755static bool acl_update_db(const char *user, const char *host, const char *db,
2756 ulong privileges)
2757{
2758 mysql_mutex_assert_owner(&acl_cache->lock);
2759
2760 bool updated= false;
2761
2762 for (uint i=0 ; i < acl_dbs.elements ; i++)
2763 {
2764 ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
2765 if ((!acl_db->user && !user[0]) ||
2766 (acl_db->user &&
2767 !strcmp(user,acl_db->user)))
2768 {
2769 if ((!acl_db->host.hostname && !host[0]) ||
2770 (acl_db->host.hostname &&
2771 !strcmp(host, acl_db->host.hostname)))
2772 {
2773 if ((!acl_db->db && !db[0]) ||
2774 (acl_db->db && !strcmp(db,acl_db->db)))
2775
2776 {
2777 if (privileges)
2778 {
2779 acl_db->access= privileges;
2780 acl_db->initial_access= acl_db->access;
2781 }
2782 else
2783 delete_dynamic_element(&acl_dbs,i);
2784 updated= true;
2785 }
2786 }
2787 }
2788 }
2789
2790 return updated;
2791}
2792
2793
2794/*
2795 Insert a user/db/host combination into the global acl_cache
2796
2797 SYNOPSIS
2798 acl_insert_db()
2799 user User name
2800 host Host name
2801 db Database name
2802 privileges Bitmap of privileges
2803
2804 NOTES
2805 acl_cache->lock must be locked when calling this
2806*/
2807
2808static void acl_insert_db(const char *user, const char *host, const char *db,
2809 ulong privileges)
2810{
2811 ACL_DB acl_db;
2812 mysql_mutex_assert_owner(&acl_cache->lock);
2813 acl_db.user=strdup_root(&acl_memroot,user);
2814 update_hostname(&acl_db.host, safe_strdup_root(&acl_memroot, host));
2815 acl_db.db=strdup_root(&acl_memroot,db);
2816 acl_db.initial_access= acl_db.access= privileges;
2817 acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
2818 (void) push_dynamic(&acl_dbs,(uchar*) &acl_db);
2819 my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
2820 sizeof(ACL_DB),(qsort_cmp) acl_compare);
2821}
2822
2823
2824/*
2825 Get privilege for a host, user and db combination
2826
2827 as db_is_pattern changes the semantics of comparison,
2828 acl_cache is not used if db_is_pattern is set.
2829*/
2830
2831ulong acl_get(const char *host, const char *ip,
2832 const char *user, const char *db, my_bool db_is_pattern)
2833{
2834 ulong host_access= ~(ulong)0, db_access= 0;
2835 uint i;
2836 size_t key_length;
2837 char key[ACL_KEY_LENGTH],*tmp_db,*end;
2838 acl_entry *entry;
2839 DBUG_ENTER("acl_get");
2840
2841 tmp_db= strmov(strmov(key, safe_str(ip)) + 1, user) + 1;
2842 end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db);
2843
2844 if (end >= key + sizeof(key)) // db name was truncated
2845 DBUG_RETURN(0); // no privileges for an invalid db name
2846
2847 if (lower_case_table_names)
2848 {
2849 my_casedn_str(files_charset_info, tmp_db);
2850 db=tmp_db;
2851 }
2852 key_length= (size_t) (end-key);
2853
2854 mysql_mutex_lock(&acl_cache->lock);
2855 if (!db_is_pattern && (entry=acl_cache->search((uchar*) key, key_length)))
2856 {
2857 db_access=entry->access;
2858 mysql_mutex_unlock(&acl_cache->lock);
2859 DBUG_PRINT("exit", ("access: 0x%lx", db_access));
2860 DBUG_RETURN(db_access);
2861 }
2862
2863 /*
2864 Check if there are some access rights for database and user
2865 */
2866 for (i=0 ; i < acl_dbs.elements ; i++)
2867 {
2868 ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
2869 if (!acl_db->user || !strcmp(user,acl_db->user))
2870 {
2871 if (compare_hostname(&acl_db->host,host,ip))
2872 {
2873 if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
2874 {
2875 db_access=acl_db->access;
2876 if (acl_db->host.hostname)
2877 goto exit; // Fully specified. Take it
2878 /* the host table is not used for roles */
2879 if ((!host || !host[0]) && !acl_db->host.hostname && find_acl_role(user))
2880 goto exit;
2881 break; /* purecov: tested */
2882 }
2883 }
2884 }
2885 }
2886 if (!db_access)
2887 goto exit; // Can't be better
2888
2889 /*
2890 No host specified for user. Get hostdata from host table
2891 */
2892 host_access=0; // Host must be found
2893 for (i=0 ; i < acl_hosts.elements ; i++)
2894 {
2895 ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
2896 if (compare_hostname(&acl_host->host,host,ip))
2897 {
2898 if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern))
2899 {
2900 host_access=acl_host->access; // Fully specified. Take it
2901 break;
2902 }
2903 }
2904 }
2905exit:
2906 /* Save entry in cache for quick retrieval */
2907 if (!db_is_pattern &&
2908 (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
2909 {
2910 entry->access=(db_access & host_access);
2911 DBUG_ASSERT(key_length < 0xffff);
2912 entry->length=(uint16)key_length;
2913 memcpy((uchar*) entry->key,key,key_length);
2914 acl_cache->add(entry);
2915 }
2916 mysql_mutex_unlock(&acl_cache->lock);
2917 DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
2918 DBUG_RETURN(db_access & host_access);
2919}
2920
2921/*
2922 Check if there are any possible matching entries for this host
2923
2924 NOTES
2925 All host names without wild cards are stored in a hash table,
2926 entries with wildcards are stored in a dynamic array
2927*/
2928
2929static void init_check_host(void)
2930{
2931 DBUG_ENTER("init_check_host");
2932 (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
2933 acl_users.elements, 1, MYF(0));
2934 (void) my_hash_init(&acl_check_hosts,system_charset_info,
2935 acl_users.elements, 0, 0,
2936 (my_hash_get_key) check_get_key, 0, 0);
2937 if (!allow_all_hosts)
2938 {
2939 for (uint i=0 ; i < acl_users.elements ; i++)
2940 {
2941 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
2942 if (strchr(acl_user->host.hostname,wild_many) ||
2943 strchr(acl_user->host.hostname,wild_one) ||
2944 acl_user->host.ip_mask)
2945 { // Has wildcard
2946 uint j;
2947 for (j=0 ; j < acl_wild_hosts.elements ; j++)
2948 { // Check if host already exists
2949 acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
2950 acl_host_and_ip *);
2951 if (!my_strcasecmp(system_charset_info,
2952 acl_user->host.hostname, acl->hostname))
2953 break; // already stored
2954 }
2955 if (j == acl_wild_hosts.elements) // If new
2956 (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
2957 }
2958 else if (!my_hash_search(&acl_check_hosts,(uchar*)
2959 acl_user->host.hostname,
2960 strlen(acl_user->host.hostname)))
2961 {
2962 if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
2963 { // End of memory
2964 allow_all_hosts=1; // Should never happen
2965 DBUG_VOID_RETURN;
2966 }
2967 }
2968 }
2969 }
2970 freeze_size(&acl_wild_hosts);
2971 freeze_size(&acl_check_hosts.array);
2972 DBUG_VOID_RETURN;
2973}
2974
2975
2976/*
2977 Rebuild lists used for checking of allowed hosts
2978
2979 We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
2980 dropping or renaming user, since they contain pointers to elements of
2981 'acl_user' array, which are invalidated by drop operation, and use
2982 ACL_USER::host::hostname as a key, which is changed by rename.
2983*/
2984static void rebuild_check_host(void)
2985{
2986 delete_dynamic(&acl_wild_hosts);
2987 my_hash_free(&acl_check_hosts);
2988 init_check_host();
2989}
2990
2991/*
2992 Reset a role role_grants dynamic array.
2993 Also, the role's access bits are reset to the ones present in the table.
2994*/
2995static my_bool acl_role_reset_role_arrays(void *ptr,
2996 void * not_used __attribute__((unused)))
2997{
2998 ACL_ROLE *role= (ACL_ROLE *)ptr;
2999 reset_dynamic(&role->role_grants);
3000 reset_dynamic(&role->parent_grantee);
3001 role->counter= 0;
3002 return 0;
3003}
3004
3005/*
3006 Add a the coresponding pointers present in the mapping to the entries in
3007 acl_users and acl_roles
3008*/
3009static bool add_role_user_mapping(ACL_USER_BASE *grantee, ACL_ROLE *role)
3010{
3011 return push_dynamic(&grantee->role_grants, (uchar*) &role)
3012 || push_dynamic(&role->parent_grantee, (uchar*) &grantee);
3013
3014}
3015
3016/*
3017 Revert the last add_role_user_mapping() action
3018*/
3019static void undo_add_role_user_mapping(ACL_USER_BASE *grantee, ACL_ROLE *role)
3020{
3021 void *pop __attribute__((unused));
3022
3023 pop= pop_dynamic(&grantee->role_grants);
3024 DBUG_ASSERT(role == *(ACL_ROLE**)pop);
3025
3026 pop= pop_dynamic(&role->parent_grantee);
3027 DBUG_ASSERT(grantee == *(ACL_USER_BASE**)pop);
3028}
3029
3030/*
3031 this helper is used when building role_grants and parent_grantee arrays
3032 from scratch.
3033
3034 this happens either on initial loading of data from tables, in acl_load().
3035 or in rebuild_role_grants after acl_role_reset_role_arrays().
3036*/
3037static bool add_role_user_mapping(const char *uname, const char *hname,
3038 const char *rname)
3039{
3040 ACL_USER_BASE *grantee= find_acl_user_base(uname, hname);
3041 ACL_ROLE *role= find_acl_role(rname);
3042
3043 if (grantee == NULL || role == NULL)
3044 return 1;
3045
3046 /*
3047 because all arrays are rebuilt completely, and counters were also reset,
3048 we can increment them here, and after the rebuild all counters will
3049 have correct values (equal to the number of roles granted).
3050 */
3051 if (grantee->flags & IS_ROLE)
3052 ((ACL_ROLE*)grantee)->counter++;
3053 return add_role_user_mapping(grantee, role);
3054}
3055
3056/*
3057 This helper function is used to removes roles and grantees
3058 from the corresponding cross-reference arrays. see remove_role_user_mapping().
3059 as such, it asserts that an element to delete is present in the array,
3060 and is present only once.
3061*/
3062static void remove_ptr_from_dynarray(DYNAMIC_ARRAY *array, void *ptr)
3063{
3064 bool found __attribute__((unused))= false;
3065 for (uint i= 0; i < array->elements; i++)
3066 {
3067 if (ptr == *dynamic_element(array, i, void**))
3068 {
3069 DBUG_ASSERT(!found);
3070 delete_dynamic_element(array, i);
3071 IF_DBUG_ASSERT(found= true, break);
3072 }
3073 }
3074 DBUG_ASSERT(found);
3075}
3076
3077static void remove_role_user_mapping(ACL_USER_BASE *grantee, ACL_ROLE *role,
3078 int grantee_idx=-1, int role_idx=-1)
3079{
3080 remove_ptr_from_dynarray(&grantee->role_grants, role);
3081 remove_ptr_from_dynarray(&role->parent_grantee, grantee);
3082}
3083
3084
3085static my_bool add_role_user_mapping_action(void *ptr, void *unused __attribute__((unused)))
3086{
3087 ROLE_GRANT_PAIR *pair= (ROLE_GRANT_PAIR*)ptr;
3088 bool status __attribute__((unused));
3089 status= add_role_user_mapping(pair->u_uname, pair->u_hname, pair->r_uname);
3090 /*
3091 The invariant chosen is that acl_roles_mappings should _always_
3092 only contain valid entries, referencing correct user and role grants.
3093 If add_role_user_mapping detects an invalid entry, it will not add
3094 the mapping into the ACL_USER::role_grants array.
3095 */
3096 DBUG_ASSERT(status == 0);
3097 return 0;
3098}
3099
3100
3101/*
3102 Rebuild the role grants every time the acl_users is modified
3103
3104 The role grants in the ACL_USER class need to be rebuilt, as they contain
3105 pointers to elements of the acl_users array.
3106*/
3107
3108static void rebuild_role_grants(void)
3109{
3110 DBUG_ENTER("rebuild_role_grants");
3111 /*
3112 Reset every user's and role's role_grants array
3113 */
3114 for (uint i=0; i < acl_users.elements; i++) {
3115 ACL_USER *user= dynamic_element(&acl_users, i, ACL_USER *);
3116 reset_dynamic(&user->role_grants);
3117 }
3118 my_hash_iterate(&acl_roles, acl_role_reset_role_arrays, NULL);
3119
3120 /* Rebuild the direct links between users and roles in ACL_USER::role_grants */
3121 my_hash_iterate(&acl_roles_mappings, add_role_user_mapping_action, NULL);
3122
3123 DBUG_VOID_RETURN;
3124}
3125
3126
3127/* Return true if there is no users that can match the given host */
3128bool acl_check_host(const char *host, const char *ip)
3129{
3130 if (allow_all_hosts)
3131 return 0;
3132 mysql_mutex_lock(&acl_cache->lock);
3133
3134 if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
3135 (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
3136 {
3137 mysql_mutex_unlock(&acl_cache->lock);
3138 return 0; // Found host
3139 }
3140 for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
3141 {
3142 acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
3143 if (compare_hostname(acl, host, ip))
3144 {
3145 mysql_mutex_unlock(&acl_cache->lock);
3146 return 0; // Host ok
3147 }
3148 }
3149 mysql_mutex_unlock(&acl_cache->lock);
3150 if (ip != NULL)
3151 {
3152 /* Increment HOST_CACHE.COUNT_HOST_ACL_ERRORS. */
3153 Host_errors errors;
3154 errors.m_host_acl= 1;
3155 inc_host_errors(ip, &errors);
3156 }
3157 return 1; // Host is not allowed
3158}
3159
3160/**
3161 Check if the user is allowed to alter the mysql.user table
3162
3163 @param thd THD
3164 @param host Hostname for the user
3165 @param user User name
3166
3167 @return Error status
3168 @retval 0 OK
3169 @retval 1 Error
3170*/
3171
3172static int check_alter_user(THD *thd, const char *host, const char *user)
3173{
3174 int error = 1;
3175 if (!initialized)
3176 {
3177 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
3178 goto end;
3179 }
3180
3181 if (IF_WSREP((!WSREP(thd) || !thd->wsrep_applier), 1) &&
3182 !thd->slave_thread && !thd->security_ctx->priv_user[0] &&
3183 !in_bootstrap)
3184 {
3185 my_message(ER_PASSWORD_ANONYMOUS_USER,
3186 ER_THD(thd, ER_PASSWORD_ANONYMOUS_USER),
3187 MYF(0));
3188 goto end;
3189 }
3190 if (!host) // Role
3191 {
3192 my_error(ER_PASSWORD_NO_MATCH, MYF(0));
3193 goto end;
3194 }
3195
3196 if (!thd->slave_thread &&
3197 IF_WSREP((!WSREP(thd) || !thd->wsrep_applier),1) &&
3198 (strcmp(thd->security_ctx->priv_user, user) ||
3199 my_strcasecmp(system_charset_info, host,
3200 thd->security_ctx->priv_host)))
3201 {
3202 if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0))
3203 goto end;
3204 }
3205
3206 error = 0;
3207
3208end:
3209 return error;
3210}
3211/**
3212 Check if the user is allowed to change password
3213
3214 @param thd THD
3215 @param user User, hostname, new password or password hash
3216
3217 @return Error status
3218 @retval 0 OK
3219 @retval 1 ERROR; In this case the error is sent to the client.
3220*/
3221
3222bool check_change_password(THD *thd, LEX_USER *user)
3223{
3224 LEX_USER *real_user= get_current_user(thd, user);
3225
3226 if (fix_and_copy_user(real_user, user, thd) ||
3227 validate_password(real_user, thd))
3228 return true;
3229
3230 *user= *real_user;
3231
3232 return check_alter_user(thd, user->host.str, user->user.str);
3233}
3234
3235
3236/**
3237 Change a password for a user.
3238
3239 @param thd THD
3240 @param user User, hostname, new password hash
3241
3242 @return Error code
3243 @retval 0 ok
3244 @retval 1 ERROR; In this case the error is sent to the client.
3245*/
3246bool change_password(THD *thd, LEX_USER *user)
3247{
3248 Grant_tables tables(Table_user, TL_WRITE);
3249 /* Buffer should be extended when password length is extended. */
3250 char buff[512];
3251 ulong query_length= 0;
3252 enum_binlog_format save_binlog_format;
3253 int result=0;
3254 const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
3255 DBUG_ENTER("change_password");
3256 DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
3257 user->host.str, user->user.str, user->pwhash.str));
3258 DBUG_ASSERT(user->host.str != 0); // Ensured by parent
3259
3260 /*
3261 This statement will be replicated as a statement, even when using
3262 row-based replication. The flag will be reset at the end of the
3263 statement.
3264 This has to be handled here as it's called by set_var.cc, which is
3265 not automaticly handled by sql_parse.cc
3266 */
3267 save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
3268
3269 if (mysql_bin_log.is_open() ||
3270 (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)))
3271 {
3272 query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
3273 safe_str(user->user.str), safe_str(user->host.str),
3274 safe_str(user->pwhash.str));
3275 }
3276
3277 if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
3278 {
3279 thd->set_query(buff, query_length, system_charset_info);
3280 WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
3281 }
3282
3283 if ((result= tables.open_and_lock(thd)))
3284 DBUG_RETURN(result != 1);
3285
3286 result= 1;
3287
3288 mysql_mutex_lock(&acl_cache->lock);
3289 ACL_USER *acl_user;
3290 if (!(acl_user= find_user_exact(user->host.str, user->user.str)))
3291 {
3292 mysql_mutex_unlock(&acl_cache->lock);
3293 my_message(ER_PASSWORD_NO_MATCH,
3294 ER_THD(thd, ER_PASSWORD_NO_MATCH), MYF(0));
3295 goto end;
3296 }
3297
3298 /* update loaded acl entry: */
3299 if (acl_user->plugin.str == native_password_plugin_name.str ||
3300 acl_user->plugin.str == old_password_plugin_name.str)
3301 {
3302 acl_user->auth_string.str= strmake_root(&acl_memroot, user->pwhash.str, user->pwhash.length);
3303 acl_user->auth_string.length= user->pwhash.length;
3304 set_user_salt(acl_user, user->pwhash.str, user->pwhash.length);
3305
3306 set_user_plugin(acl_user, user->pwhash.length);
3307 }
3308 else
3309 push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
3310 ER_SET_PASSWORD_AUTH_PLUGIN,
3311 ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN));
3312
3313 if (update_user_table(thd, tables.user_table(),
3314 safe_str(acl_user->host.hostname),
3315 safe_str(acl_user->user.str),
3316 user->pwhash.str, user->pwhash.length))
3317 {
3318 mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
3319 goto end;
3320 }
3321
3322 acl_cache->clear(1); // Clear locked hostname cache
3323 mysql_mutex_unlock(&acl_cache->lock);
3324 result= 0;
3325 if (mysql_bin_log.is_open())
3326 {
3327 DBUG_ASSERT(query_length);
3328 thd->clear_error();
3329 result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
3330 FALSE, FALSE, FALSE, 0);
3331 }
3332end:
3333 close_mysql_tables(thd);
3334
3335#ifdef WITH_WSREP
3336error: // this label is used in WSREP_TO_ISOLATION_BEGIN
3337 if (WSREP(thd) && !thd->wsrep_applier)
3338 {
3339 WSREP_TO_ISOLATION_END;
3340
3341 thd->set_query(query_save);
3342 thd->wsrep_exec_mode = LOCAL_STATE;
3343 }
3344#endif /* WITH_WSREP */
3345 thd->restore_stmt_binlog_format(save_binlog_format);
3346
3347 DBUG_RETURN(result);
3348}
3349
3350int acl_check_set_default_role(THD *thd, const char *host, const char *user)
3351{
3352 return check_alter_user(thd, host, user);
3353}
3354
3355int acl_set_default_role(THD *thd, const char *host, const char *user,
3356 const char *rolename)
3357{
3358 Grant_tables tables(Table_user, TL_WRITE);
3359 char user_key[MAX_KEY_LENGTH];
3360 int result= 1;
3361 int error;
3362 ulong query_length= 0;
3363 bool clear_role= FALSE;
3364 char buff[512];
3365 enum_binlog_format save_binlog_format;
3366 const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
3367
3368 DBUG_ENTER("acl_set_default_role");
3369 DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'",
3370 safe_str(user), safe_str(host), safe_str(rolename)));
3371
3372 if (rolename == current_role.str) {
3373 if (!thd->security_ctx->priv_role[0])
3374 rolename= "NONE";
3375 else
3376 rolename= thd->security_ctx->priv_role;
3377 }
3378
3379 if (check_user_can_set_role(user, host, host, rolename, NULL))
3380 DBUG_RETURN(result);
3381
3382 if (!strcasecmp(rolename, "NONE"))
3383 clear_role= TRUE;
3384
3385 if (mysql_bin_log.is_open() ||
3386 (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)))
3387 {
3388 query_length=
3389 sprintf(buff,"SET DEFAULT ROLE '%-.120s' FOR '%-.120s'@'%-.120s'",
3390 safe_str(rolename), safe_str(user), safe_str(host));
3391 }
3392
3393 /*
3394 This statement will be replicated as a statement, even when using
3395 row-based replication. The flag will be reset at the end of the
3396 statement.
3397 This has to be handled here as it's called by set_var.cc, which is
3398 not automaticly handled by sql_parse.cc
3399 */
3400 save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
3401
3402 if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
3403 {
3404 thd->set_query(buff, query_length, system_charset_info);
3405 WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
3406 }
3407
3408 /*
3409 Extra block due to WSREP_TO_ISOLATION_BEGIN using goto.
3410 TODO(cvicentiu) Should move this block out in a new function.
3411 */
3412 {
3413 if ((result= tables.open_and_lock(thd)))
3414 DBUG_RETURN(result != 1);
3415
3416 const User_table& user_table= tables.user_table();
3417 TABLE *table= user_table.table();
3418
3419 result= 1;
3420
3421 mysql_mutex_lock(&acl_cache->lock);
3422 ACL_USER *acl_user;
3423 if (!(acl_user= find_user_exact(host, user)))
3424 {
3425 mysql_mutex_unlock(&acl_cache->lock);
3426 my_message(ER_PASSWORD_NO_MATCH, ER_THD(thd, ER_PASSWORD_NO_MATCH),
3427 MYF(0));
3428 goto end;
3429 }
3430
3431 if (!clear_role)
3432 {
3433 /* set new default_rolename */
3434 acl_user->default_rolename.str= safe_strdup_root(&acl_memroot, rolename);
3435 acl_user->default_rolename.length= strlen(rolename);
3436 }
3437 else
3438 {
3439 /* clear the default_rolename */
3440 acl_user->default_rolename.str = NULL;
3441 acl_user->default_rolename.length = 0;
3442 }
3443
3444 /* update the mysql.user table with the new default role */
3445 tables.user_table().table()->use_all_columns();
3446 if (!tables.user_table().default_role())
3447 {
3448 my_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, MYF(0),
3449 table->alias.c_ptr(), DEFAULT_ROLE_COLUMN_IDX + 1,
3450 tables.user_table().num_fields(),
3451 static_cast<int>(table->s->mysql_version), MYSQL_VERSION_ID);
3452 mysql_mutex_unlock(&acl_cache->lock);
3453 goto end;
3454 }
3455 user_table.host()->store(host,(uint) strlen(host), system_charset_info);
3456 user_table.user()->store(user,(uint) strlen(user), system_charset_info);
3457 key_copy((uchar *) user_key, table->record[0], table->key_info,
3458 table->key_info->key_length);
3459
3460 if (table->file->ha_index_read_idx_map(table->record[0], 0,
3461 (uchar *) user_key, HA_WHOLE_KEY,
3462 HA_READ_KEY_EXACT))
3463 {
3464 mysql_mutex_unlock(&acl_cache->lock);
3465 my_message(ER_PASSWORD_NO_MATCH, ER_THD(thd, ER_PASSWORD_NO_MATCH),
3466 MYF(0));
3467 goto end;
3468 }
3469 store_record(table, record[1]);
3470 user_table.default_role()->store(acl_user->default_rolename.str,
3471 acl_user->default_rolename.length,
3472 system_charset_info);
3473 if (unlikely(error= table->file->ha_update_row(table->record[1],
3474 table->record[0])) &&
3475 error != HA_ERR_RECORD_IS_THE_SAME)
3476 {
3477 mysql_mutex_unlock(&acl_cache->lock);
3478 table->file->print_error(error,MYF(0)); /* purecov: deadcode */
3479 goto end;
3480 }
3481
3482 acl_cache->clear(1);
3483 mysql_mutex_unlock(&acl_cache->lock);
3484 result= 0;
3485 if (mysql_bin_log.is_open())
3486 {
3487 DBUG_ASSERT(query_length);
3488 thd->clear_error();
3489 result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
3490 FALSE, FALSE, FALSE, 0);
3491 }
3492 end:
3493 close_mysql_tables(thd);
3494 }
3495
3496#ifdef WITH_WSREP
3497error: // this label is used in WSREP_TO_ISOLATION_END
3498 if (WSREP(thd) && !thd->wsrep_applier)
3499 {
3500 WSREP_TO_ISOLATION_END;
3501
3502 thd->set_query(query_save);
3503 thd->wsrep_exec_mode = LOCAL_STATE;
3504 }
3505#endif /* WITH_WSREP */
3506
3507 thd->restore_stmt_binlog_format(save_binlog_format);
3508
3509 DBUG_RETURN(result);
3510}
3511
3512
3513/*
3514 Find user in ACL
3515
3516 SYNOPSIS
3517 is_acl_user()
3518 host host name
3519 user user name
3520
3521 RETURN
3522 FALSE user not fond
3523 TRUE there is such user
3524*/
3525
3526bool is_acl_user(const char *host, const char *user)
3527{
3528 bool res;
3529
3530 /* --skip-grants */
3531 if (!initialized)
3532 return TRUE;
3533
3534 mysql_mutex_lock(&acl_cache->lock);
3535
3536 if (*host) // User
3537 res= find_user_exact(host, user) != NULL;
3538 else // Role
3539 res= find_acl_role(user) != NULL;
3540
3541 mysql_mutex_unlock(&acl_cache->lock);
3542 return res;
3543}
3544
3545
3546/*
3547 unlike find_user_exact and find_user_wild,
3548 this function finds anonymous users too, it's when a
3549 user is not empty, but priv_user (acl_user->user) is empty.
3550*/
3551static ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip)
3552{
3553 ACL_USER *result= NULL;
3554 mysql_mutex_assert_owner(&acl_cache->lock);
3555 for (uint i=0; i < acl_users.elements; i++)
3556 {
3557 ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
3558 if ((!acl_user_tmp->user.str ||
3559 !strcmp(user, acl_user_tmp->user.str)) &&
3560 compare_hostname(&acl_user_tmp->host, host, ip))
3561 {
3562 result= acl_user_tmp;
3563 break;
3564 }
3565 }
3566 return result;
3567}
3568
3569
3570/*
3571 Find first entry that matches the specified user@host pair
3572*/
3573static ACL_USER * find_user_exact(const char *host, const char *user)
3574{
3575 mysql_mutex_assert_owner(&acl_cache->lock);
3576
3577 for (uint i=0 ; i < acl_users.elements ; i++)
3578 {
3579 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
3580 if (acl_user->eq(user, host))
3581 return acl_user;
3582 }
3583 return 0;
3584}
3585
3586/*
3587 Find first entry that matches the specified user@host pair
3588*/
3589static ACL_USER * find_user_wild(const char *host, const char *user, const char *ip)
3590{
3591 mysql_mutex_assert_owner(&acl_cache->lock);
3592
3593 for (uint i=0 ; i < acl_users.elements ; i++)
3594 {
3595 ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
3596 if (acl_user->wild_eq(user, host, ip))
3597 return acl_user;
3598 }
3599 return 0;
3600}
3601
3602/*
3603 Find a role with the specified name
3604*/
3605static ACL_ROLE *find_acl_role(const char *role)
3606{
3607 DBUG_ENTER("find_acl_role");
3608 DBUG_PRINT("enter",("role: '%s'", role));
3609 DBUG_PRINT("info", ("Hash elements: %ld", acl_roles.records));
3610
3611 mysql_mutex_assert_owner(&acl_cache->lock);
3612
3613 ACL_ROLE *r= (ACL_ROLE *)my_hash_search(&acl_roles, (uchar *)role,
3614 safe_strlen(role));
3615 DBUG_RETURN(r);
3616}
3617
3618
3619static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host)
3620{
3621 if (*host)
3622 return find_user_exact(host, user);
3623
3624 return find_acl_role(user);
3625}
3626
3627
3628/*
3629 Comparing of hostnames
3630
3631 NOTES
3632 A hostname may be of type:
3633 hostname (May include wildcards); monty.pp.sci.fi
3634 ip (May include wildcards); 192.168.0.0
3635 ip/netmask 192.168.0.0/255.255.255.0
3636
3637 A net mask of 0.0.0.0 is not allowed.
3638*/
3639
3640static const char *calc_ip(const char *ip, long *val, char end)
3641{
3642 long ip_val,tmp;
3643 if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
3644 return 0;
3645 ip_val<<=24;
3646 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
3647 return 0;
3648 ip_val+=tmp<<16;
3649 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
3650 return 0;
3651 ip_val+=tmp<<8;
3652 if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
3653 return 0;
3654 *val=ip_val+tmp;
3655 return ip;
3656}
3657
3658
3659static void update_hostname(acl_host_and_ip *host, const char *hostname)
3660{
3661 // fix historical undocumented convention that empty host is the same as '%'
3662 hostname=const_cast<char*>(hostname ? hostname : host_not_specified.str);
3663 host->hostname=(char*) hostname; // This will not be modified!
3664 if (!(hostname= calc_ip(hostname,&host->ip,'/')) ||
3665 !(hostname= calc_ip(hostname+1,&host->ip_mask,'\0')))
3666 {
3667 host->ip= host->ip_mask=0; // Not a masked ip
3668 }
3669}
3670
3671
3672static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
3673 const char *ip)
3674{
3675 long tmp;
3676 if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0'))
3677 {
3678 return (tmp & host->ip_mask) == host->ip;
3679 }
3680 return (!host->hostname ||
3681 (hostname && !wild_case_compare(system_charset_info,
3682 hostname, host->hostname)) ||
3683 (ip && !wild_compare(ip, host->hostname, 0)));
3684}
3685
3686/**
3687 Check if the given host name needs to be resolved or not.
3688 Host name has to be resolved if it actually contains *name*.
3689
3690 For example:
3691 192.168.1.1 --> FALSE
3692 192.168.1.0/255.255.255.0 --> FALSE
3693 % --> FALSE
3694 192.168.1.% --> FALSE
3695 AB% --> FALSE
3696
3697 AAAAFFFF --> TRUE (Hostname)
3698 AAAA:FFFF:1234:5678 --> FALSE
3699 ::1 --> FALSE
3700
3701 This function does not check if the given string is a valid host name or
3702 not. It assumes that the argument is a valid host name.
3703
3704 @param hostname the string to check.
3705
3706 @return a flag telling if the argument needs to be resolved or not.
3707 @retval TRUE the argument is a host name and needs to be resolved.
3708 @retval FALSE the argument is either an IP address, or a patter and
3709 should not be resolved.
3710*/
3711
3712bool hostname_requires_resolving(const char *hostname)
3713{
3714 if (!hostname)
3715 return FALSE;
3716
3717 /* Check if hostname is the localhost. */
3718
3719 size_t hostname_len= strlen(hostname);
3720 size_t localhost_len= strlen(my_localhost);
3721
3722 if (hostname == my_localhost ||
3723 (hostname_len == localhost_len &&
3724 !my_strnncoll(system_charset_info,
3725 (const uchar *) hostname, hostname_len,
3726 (const uchar *) my_localhost, strlen(my_localhost))))
3727 {
3728 return FALSE;
3729 }
3730
3731 /*
3732 If the string contains any of {':', '%', '_', '/'}, it is definitely
3733 not a host name:
3734 - ':' means that the string is an IPv6 address;
3735 - '%' or '_' means that the string is a pattern;
3736 - '/' means that the string is an IPv4 network address;
3737 */
3738
3739 for (const char *p= hostname; *p; ++p)
3740 {
3741 switch (*p) {
3742 case ':':
3743 case '%':
3744 case '_':
3745 case '/':
3746 return FALSE;
3747 }
3748 }
3749
3750 /*
3751 Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
3752 (12.34.56.78). The assumption is that if the string contains only
3753 digits and dots, it is an IPv4 address. Otherwise -- a host name.
3754 */
3755
3756 for (const char *p= hostname; *p; ++p)
3757 {
3758 if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
3759 return TRUE; /* a "letter" has been found. */
3760 }
3761
3762 return FALSE; /* all characters are either dots or digits. */
3763}
3764
3765
3766void set_authentication_plugin_from_password(const User_table& user_table,
3767 const char* password, size_t password_length)
3768{
3769 if (password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH)
3770 {
3771 user_table.plugin()->store(native_password_plugin_name.str,
3772 native_password_plugin_name.length,
3773 system_charset_info);
3774 }
3775 else
3776 {
3777 DBUG_ASSERT(password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
3778 user_table.plugin()->store(old_password_plugin_name.str,
3779 old_password_plugin_name.length,
3780 system_charset_info);
3781 }
3782 user_table.authentication_string()->store(password,
3783 password_length,
3784 system_charset_info);
3785}
3786/**
3787 Update record for user in mysql.user privilege table with new password.
3788
3789 @param thd THD
3790 @param table Pointer to TABLE object for open mysql.user table
3791 @param host Hostname
3792 @param user Username
3793 @param new_password New password hash
3794 @param new_password_len Length of new password hash
3795
3796 @see change_password
3797*/
3798
3799static bool update_user_table(THD *thd, const User_table& user_table,
3800 const char *host, const char *user,
3801 const char *new_password, size_t new_password_len)
3802{
3803 char user_key[MAX_KEY_LENGTH];
3804 int error;
3805 DBUG_ENTER("update_user_table");
3806 DBUG_PRINT("enter",("user: %s host: %s",user,host));
3807
3808 TABLE *table= user_table.table();
3809 table->use_all_columns();
3810 user_table.host()->store(host,(uint) strlen(host), system_charset_info);
3811 user_table.user()->store(user,(uint) strlen(user), system_charset_info);
3812 key_copy((uchar *) user_key, table->record[0], table->key_info,
3813 table->key_info->key_length);
3814
3815 if (table->file->ha_index_read_idx_map(table->record[0], 0,
3816 (uchar *) user_key, HA_WHOLE_KEY,
3817 HA_READ_KEY_EXACT))
3818 {
3819 my_message(ER_PASSWORD_NO_MATCH, ER_THD(thd, ER_PASSWORD_NO_MATCH),
3820 MYF(0)); /* purecov: deadcode */
3821 DBUG_RETURN(1); /* purecov: deadcode */
3822 }
3823 store_record(table,record[1]);
3824 /* If the password column is missing, we use the
3825 authentication_string column. */
3826 if (user_table.password())
3827 user_table.password()->store(new_password, new_password_len, system_charset_info);
3828 else
3829 set_authentication_plugin_from_password(user_table, new_password,
3830 new_password_len);
3831
3832
3833 if (unlikely(error= table->file->ha_update_row(table->record[1],
3834 table->record[0])) &&
3835 error != HA_ERR_RECORD_IS_THE_SAME)
3836 {
3837 table->file->print_error(error,MYF(0)); /* purecov: deadcode */
3838 DBUG_RETURN(1);
3839 }
3840 DBUG_RETURN(0);
3841}
3842
3843
3844/*
3845 Return 1 if we are allowed to create new users
3846 the logic here is: INSERT_ACL is sufficient.
3847 It's also a requirement in opt_safe_user_create,
3848 otherwise CREATE_USER_ACL is enough.
3849*/
3850
3851static bool test_if_create_new_users(THD *thd)
3852{
3853 Security_context *sctx= thd->security_ctx;
3854 bool create_new_users= MY_TEST(sctx->master_access & INSERT_ACL) ||
3855 (!opt_safe_user_create &&
3856 MY_TEST(sctx->master_access & CREATE_USER_ACL));
3857 if (!create_new_users)
3858 {
3859 TABLE_LIST tl;
3860 ulong db_access;
3861 tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_USER_NAME, NULL, TL_WRITE);
3862 create_new_users= 1;
3863
3864 db_access=acl_get(sctx->host, sctx->ip,
3865 sctx->priv_user, tl.db.str, 0);
3866 if (sctx->priv_role[0])
3867 db_access|= acl_get("", "", sctx->priv_role, tl.db.str, 0);
3868 if (!(db_access & INSERT_ACL))
3869 {
3870 if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE))
3871 create_new_users=0;
3872 }
3873 }
3874 return create_new_users;
3875}
3876
3877
3878/****************************************************************************
3879 Handle GRANT commands
3880****************************************************************************/
3881
3882static int replace_user_table(THD *thd, const User_table &user_table,
3883 LEX_USER &combo,
3884 ulong rights, bool revoke_grant,
3885 bool can_create_user, bool no_auto_create)
3886{
3887 int error = -1;
3888 bool old_row_exists=0;
3889 char what= (revoke_grant) ? 'N' : 'Y';
3890 uchar user_key[MAX_KEY_LENGTH];
3891 bool handle_as_role= combo.is_role();
3892 LEX *lex= thd->lex;
3893 TABLE *table= user_table.table();
3894 DBUG_ENTER("replace_user_table");
3895
3896 mysql_mutex_assert_owner(&acl_cache->lock);
3897
3898 if (combo.pwhash.str && combo.pwhash.str[0])
3899 {
3900 if (combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
3901 combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
3902 {
3903 DBUG_ASSERT(0);
3904 my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
3905 DBUG_RETURN(-1);
3906 }
3907 }
3908 else
3909 combo.pwhash= empty_clex_str;
3910
3911 /* if the user table is not up to date, we can't handle role updates */
3912 if (!user_table.is_role() && handle_as_role)
3913 {
3914 my_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, MYF(0),
3915 "user", ROLE_ASSIGN_COLUMN_IDX + 1, user_table.num_fields(),
3916 static_cast<int>(table->s->mysql_version), MYSQL_VERSION_ID);
3917 DBUG_RETURN(-1);
3918 }
3919
3920 table->use_all_columns();
3921 user_table.host()->store(combo.host.str,combo.host.length,
3922 system_charset_info);
3923 user_table.user()->store(combo.user.str,combo.user.length,
3924 system_charset_info);
3925 key_copy(user_key, table->record[0], table->key_info,
3926 table->key_info->key_length);
3927
3928 if (table->file->ha_index_read_idx_map(table->record[0], 0, user_key,
3929 HA_WHOLE_KEY,
3930 HA_READ_KEY_EXACT))
3931 {
3932 /* what == 'N' means revoke */
3933 if (what == 'N')
3934 {
3935 my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
3936 goto end;
3937 }
3938 /*
3939 There are four options which affect the process of creation of
3940 a new user (mysqld option --safe-create-user, 'insert' privilege
3941 on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and
3942 SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule
3943 how it should work.
3944 if (safe-user-create && ! INSERT_priv) => reject
3945 else if (identified_by) => create
3946 else if (no_auto_create_user) => reject
3947 else create
3948
3949 see also test_if_create_new_users()
3950 */
3951 else if (!combo.pwhash.length && !combo.plugin.length && no_auto_create)
3952 {
3953 my_error(ER_PASSWORD_NO_MATCH, MYF(0));
3954 goto end;
3955 }
3956 else if (!can_create_user)
3957 {
3958 my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0));
3959 goto end;
3960 }
3961 else if (combo.plugin.str[0])
3962 {
3963 if (!plugin_is_ready(&combo.plugin, MYSQL_AUTHENTICATION_PLUGIN))
3964 {
3965 my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo.plugin.str);
3966 goto end;
3967 }
3968 }
3969
3970 old_row_exists = 0;
3971 restore_record(table,s->default_values);
3972 user_table.host()->store(combo.host.str,combo.host.length,
3973 system_charset_info);
3974 user_table.user()->store(combo.user.str,combo.user.length,
3975 system_charset_info);
3976 }
3977 else