Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
221558ef
Commit
221558ef
authored
Oct 17, 2013
by
Vicențiu Ciorbaru
Committed by
Sergei Golubchik
Oct 17, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extended ACL_USER to create ACL_ROLE.
Moved fields corresponding to role entries to the ACL_ROLE class.
parent
7faba82b
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
116 additions
and
79 deletions
+116
-79
sql/sql_acl.cc
sql/sql_acl.cc
+116
-79
No files found.
sql/sql_acl.cc
View file @
221558ef
...
...
@@ -221,26 +221,14 @@ public:
LEX_STRING
user
;
uint8
salt
[
SCRAMBLE_LENGTH
+
1
];
// scrambled password in binary form
uint8
salt_len
;
// 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
uchar
flags
;
// field used to store various state information
enum
SSL_type
ssl_type
;
const
char
*
ssl_cipher
,
*
x509_issuer
,
*
x509_subject
;
LEX_STRING
plugin
;
LEX_STRING
auth_string
;
/*
list to hold references to granted roles (ACL_USER instances)
if the instance of the class represents a user, or a user if the
instance of the class represents a role.
*/
DYNAMIC_ARRAY
role_grants
;
/*
In case of granting a role to a role, the access bits are merged together
via a bit OR operation and placed in the ACL_USER::access field.
When rebuilding role_grants via the rebuild_role_grant function,
the ACL_USER::access field needs to be reset aswell. The field
initial_role_access holds the initial grants present in the table row.
*/
ulong
initial_role_access
;
ACL_USER
*
copy
(
MEM_ROOT
*
root
)
{
...
...
@@ -263,6 +251,24 @@ public:
bzero
(
&
dst
->
role_grants
,
sizeof
(
role_grants
));
return
dst
;
}
};
class
ACL_ROLE
:
public
ACL_USER
{
public:
uchar
flags
;
// field used to store various state information
/*
In case of granting a role to a role, the access bits are merged together
via a bit OR operation and placed in the ACL_USER::access field.
When rebuilding role_grants via the rebuild_role_grant function,
the ACL_USER::access field needs to be reset aswell. The field
initial_role_access holds the initial grants present in the table row.
*/
ulong
initial_role_access
;
DYNAMIC_ARRAY
parent_grantee
;
// array of backlinks to elements granted
};
class
ACL_DB
:
public
ACL_ACCESS
...
...
@@ -554,10 +560,10 @@ typedef struct st_role_grant
/*
Struct to hold the state of a node during a Depth First Search exploration
*/
template
<
class
T
>
class
NODE_STATE
class
NODE_STATE
{
public:
T
*
node_data
;
/* pointer to the node data */
ACL_ROLE
*
node_data
;
/* pointer to the node data */
uint
neigh_idx
;
/* the neighbour that needs to be evaluated next */
};
...
...
@@ -659,10 +665,11 @@ static void init_check_host(void);
static
void
rebuild_check_host
(
void
);
static
void
rebuild_role_grants
(
void
);
static
void
free_acl_user
(
ACL_USER
*
acl_user
);
static
void
free_acl_role
(
ACL_ROLE
*
acl_role
);
static
ACL_USER
*
find_user_no_anon
(
const
char
*
host
,
const
char
*
user
,
my_bool
exact
);
static
ACL_USER
*
find_user
(
const
char
*
host
,
const
char
*
user
,
const
char
*
ip
);
static
ACL_
USER
*
find_acl_role
(
const
char
*
user
);
static
ACL_
ROLE
*
find_acl_role
(
const
char
*
user
);
static
bool
update_user_table
(
THD
*
thd
,
TABLE
*
table
,
const
char
*
host
,
const
char
*
user
,
const
char
*
new_password
,
uint
new_password_len
);
...
...
@@ -671,12 +678,12 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables);
static
inline
void
get_grantor
(
THD
*
thd
,
char
*
grantor
);
static
my_bool
acl_user_reset_grant
(
ACL_USER
*
user
,
void
*
not_used
__attribute__
((
unused
)));
static
my_bool
acl_role_reset_grant
(
ACL_
USER
*
role
,
static
my_bool
acl_role_reset_grant
(
ACL_
ROLE
*
role
,
void
*
not_used
__attribute__
((
unused
)));
static
my_bool
acl_role_propagate_grants
(
ACL_
USER
*
role
,
static
my_bool
acl_role_propagate_grants
(
ACL_
ROLE
*
role
,
void
*
not_used
__attribute__
((
unused
)));
static
int
add_role_user_mapping
(
ROLE_GRANT_PAIR
*
mapping
);
static
my_bool
get_role_access
(
ACL_
USER
*
role
,
ulong
*
access
);
static
my_bool
get_role_access
(
ACL_
ROLE
*
role
,
ulong
*
access
);
/*
Enumeration of various ACL's and Hashes used in handle_grant_struct()
...
...
@@ -692,13 +699,42 @@ enum enum_acl_lists
ROLES_MAPPINGS_HASH
};
static
ACL_ROLE
*
create_role_from_user
(
MEM_ROOT
*
root
,
ACL_USER
*
user
)
{
ACL_ROLE
*
dst
=
(
ACL_ROLE
*
)
alloc_root
(
root
,
sizeof
(
ACL_ROLE
));
if
(
!
dst
)
return
0
;
*
(
ACL_USER
*
)
dst
=
*
user
;
dst
->
user
.
str
=
safe_strdup_root
(
root
,
user
->
user
.
str
);
dst
->
user
.
length
=
user
->
user
.
length
;
dst
->
ssl_cipher
=
safe_strdup_root
(
root
,
user
->
ssl_cipher
);
dst
->
x509_issuer
=
safe_strdup_root
(
root
,
user
->
x509_issuer
);
dst
->
x509_subject
=
safe_strdup_root
(
root
,
user
->
x509_subject
);
if
(
user
->
plugin
.
str
==
native_password_plugin_name
.
str
||
user
->
plugin
.
str
==
old_password_plugin_name
.
str
)
dst
->
plugin
=
user
->
plugin
;
else
dst
->
plugin
.
str
=
strmake_root
(
root
,
user
->
plugin
.
str
,
user
->
plugin
.
length
);
dst
->
auth_string
.
str
=
safe_strdup_root
(
root
,
user
->
auth_string
.
str
);
dst
->
host
.
hostname
=
safe_strdup_root
(
root
,
user
->
host
.
hostname
);
bzero
(
&
dst
->
role_grants
,
sizeof
(
dst
->
role_grants
));
bzero
(
&
dst
->
parent_grantee
,
sizeof
(
dst
->
parent_grantee
));
dst
->
flags
=
0
;
return
dst
;
}
static
void
free_acl_user
(
ACL_USER
*
user
)
{
delete_dynamic
(
&
(
user
->
role_grants
));
}
/*
static
void
free_acl_role
(
ACL_ROLE
*
role
)
{
delete_dynamic
(
&
(
role
->
role_grants
));
delete_dynamic
(
&
(
role
->
parent_grantee
));
}
/*
Convert scrambled password to binary form, according to scramble type,
Binary form is stored in user.salt.
*/
...
...
@@ -953,7 +989,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
(
void
)
my_init_dynamic_array
(
&
acl_users
,
sizeof
(
ACL_USER
),
50
,
100
,
MYF
(
0
));
(
void
)
my_hash_init2
(
&
acl_roles
,
50
,
system_charset_info
,
0
,
0
,
0
,
(
my_hash_get_key
)
acl_role_get_key
,
(
void
(
*
)(
void
*
))
free_acl_
user
,
0
);
(
void
(
*
)(
void
*
))
free_acl_
role
,
0
);
username_char_length
=
min
(
table
->
field
[
1
]
->
char_length
(),
USERNAME_CHAR_LENGTH
);
password_length
=
table
->
field
[
2
]
->
field_length
/
...
...
@@ -1008,7 +1044,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user
.
user
.
str
=
username
;
user
.
user
.
length
=
username
?
strlen
(
username
)
:
0
;
/* If the user entry is a role, skip password and hostname checks
/*
If the user entry is a role, skip password and hostname checks
A user can not log in with a role so some checks are not necessary
*/
is_role
=
check_is_role
(
table
);
...
...
@@ -1152,15 +1189,17 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
#endif
}
(
void
)
my_init_dynamic_array
(
&
user
.
role_grants
,
sizeof
(
ACL_
USER
*
),
(
void
)
my_init_dynamic_array
(
&
user
.
role_grants
,
sizeof
(
ACL_
ROLE
*
),
50
,
100
,
MYF
(
0
));
if
(
is_role
)
{
DBUG_PRINT
(
"info"
,
(
"Found role %s"
,
user
.
user
.
str
));
ACL_
USER
*
entry
=
user
.
copy
(
&
mem
);
ACL_
ROLE
*
entry
=
create_role_from_user
(
&
mem
,
&
user
);
entry
->
role_grants
=
user
.
role_grants
;
(
void
)
my_init_dynamic_array
(
&
entry
->
parent_grantee
,
sizeof
(
ACL_USER
*
),
50
,
100
,
MYF
(
0
));
/* set initial role access the same as the table row privileges */
entry
->
initial_role_access
=
entry
->
access
;
entry
->
initial_role_access
=
entry
->
access
;
my_hash_insert
(
&
acl_roles
,
(
uchar
*
)
entry
);
continue
;
...
...
@@ -1707,7 +1746,7 @@ int acl_check_setrole(THD *thd, char *rolename, ulonglong *access)
/* clear role privileges */
mysql_mutex_lock
(
&
acl_cache
->
lock
);
ACL_
USER
*
role
=
find_acl_role
(
rolename
);
ACL_
ROLE
*
role
=
find_acl_role
(
rolename
);
ACL_USER
*
acl_user
;
if
(
!
strcasecmp
(
rolename
,
"NONE"
))
{
...
...
@@ -1733,9 +1772,9 @@ int acl_check_setrole(THD *thd, char *rolename, ulonglong *access)
goto
end
;
}
for
(
uint
i
=
0
;
i
<
role
->
role_grants
.
elements
;
i
++
)
for
(
uint
i
=
0
;
i
<
role
->
parent_grantee
.
elements
;
i
++
)
{
acl_user
=
*
(
dynamic_element
(
&
role
->
role_grants
,
i
,
ACL_USER
**
));
acl_user
=
*
(
dynamic_element
(
&
role
->
parent_grantee
,
i
,
ACL_USER
**
));
if
((
!
acl_user
->
user
.
str
&&
!
thd
->
security_ctx
->
user
[
0
])
||
(
acl_user
->
user
.
str
&&
!
strcmp
(
thd
->
security_ctx
->
user
,
acl_user
->
user
.
str
)))
...
...
@@ -2140,7 +2179,7 @@ void rebuild_check_host(void)
init_check_host
();
}
static
my_bool
acl_role_propagate_grants
(
ACL_
USER
*
role
,
static
my_bool
acl_role_propagate_grants
(
ACL_
ROLE
*
role
,
void
*
not_used
__attribute__
((
unused
)))
{
ulong
access
;
...
...
@@ -2154,10 +2193,11 @@ static my_bool acl_role_propagate_grants(ACL_USER *role,
The function can be used as a walk action for hash elements aswell.
*/
my_bool
acl_role_reset_grant
(
ACL_
USER
*
role
,
my_bool
acl_role_reset_grant
(
ACL_
ROLE
*
role
,
void
*
not_used
__attribute__
((
unused
)))
{
reset_dynamic
(
&
role
->
role_grants
);
reset_dynamic
(
&
role
->
parent_grantee
);
/* Also reset the role access bits */
role
->
access
=
role
->
initial_role_access
;
role
->
flags
&=
~
ROLE_GRANTS_FINAL
;
...
...
@@ -2184,13 +2224,15 @@ my_bool acl_user_reset_grant(ACL_USER *user,
TRUE: Error or invalid parameteres
FALSE: All ok;
*/
my_bool
get_role_access
(
ACL_
USER
*
role
,
ulong
*
access
)
my_bool
get_role_access
(
ACL_
ROLE
*
role
,
ulong
*
access
)
{
DBUG_ENTER
(
"get_role_access"
);
DBUG_ASSERT
(
role
);
DBUG_ASSERT
(
access
);
/* the search operation should always leave the ROLE_VISITED flag clean
for all nodes involved in the search */
/*
The search operation should always leave the ROLE_VISITED flag clean
for all nodes involved in the search
*/
DBUG_ASSERT
(
!
(
role
->
flags
&
ROLE_VISITED
));
/*
...
...
@@ -2204,41 +2246,40 @@ my_bool get_role_access(ACL_USER *role, ulong *access)
DBUG_RETURN
(
FALSE
);
}
DYNAMIC_ARRAY
stack
;
/* stack used to simulate the recursive calls of DFS
* used a DYNAMIC_ARRAY to reduce the number of
* malloc calls to a minimum */
NODE_STATE
<
ACL_USER
>
state
;
/* variable used to insert elements in the stack */
/*
Stack used to simulate the recursive calls of DFS.
It uses a DYNAMIC_ARRAY to reduce the number of
malloc calls to a minimum
*/
DYNAMIC_ARRAY
stack
;
NODE_STATE
state
;
/* variable used to insert elements in the stack */
state
.
neigh_idx
=
0
;
state
.
node_data
=
role
;
role
->
flags
|=
ROLE_VISITED
;
(
void
)
my_init_dynamic_array
(
&
stack
,
sizeof
(
NODE_STATE
<
ACL_USER
>
),
20
,
50
,
MYF
(
0
));
insert_dynamic
(
&
stack
,
&
state
);
(
void
)
my_init_dynamic_array
(
&
stack
,
sizeof
(
NODE_STATE
),
20
,
50
,
MYF
(
0
));
push_dynamic
(
&
stack
,
&
state
);
while
(
stack
.
elements
)
{
NODE_STATE
<
ACL_USER
>
*
curr_state
=
dynamic_element
(
&
stack
,
stack
.
elements
-
1
,
NODE_STATE
<
ACL_USER
>
*
);
NODE_STATE
*
curr_state
=
dynamic_element
(
&
stack
,
stack
.
elements
-
1
,
NODE_STATE
*
);
DBUG_ASSERT
(
curr_state
->
node_data
->
flags
&
ROLE_VISITED
);
ACL_USER
*
current
=
state
.
node_data
;
ACL_USER
*
neighbour
=
NULL
;
/* iterate through the neighbours until a first valid jump-to
neighbour is found */
ACL_ROLE
*
current
=
state
.
node_data
;
ACL_ROLE
*
neighbour
=
NULL
;
/*
Iterate through the neighbours until a first valid jump-to
neighbour is found
*/
my_bool
found
=
FALSE
;
uint
i
;
for
(
i
=
curr_state
->
neigh_idx
;
i
<
current
->
role_grants
.
elements
&&
found
==
FALSE
;
i
++
)
{
neighbour
=
*
(
dynamic_element
(
&
current
->
role_grants
,
i
,
ACL_USER
**
));
/* check if the neighbour is a role; pass if not*/
if
(
!
(
neighbour
->
flags
&
IS_ROLE
))
continue
;
neighbour
=
*
(
dynamic_element
(
&
current
->
role_grants
,
i
,
ACL_ROLE
**
));
/* check if it forms a cycle */
if
(
neighbour
->
flags
&
ROLE_VISITED
)
...
...
@@ -2247,15 +2288,18 @@ my_bool get_role_access(ACL_USER *role, ulong *access)
continue
;
}
/* check if it was already explored, in that case, just set the rights
and move on */
/*
Check if it was already explored, in that case, just set the rights
and move on
*/
if
(
neighbour
->
flags
&
ROLE_GRANTS_FINAL
)
{
current
->
access
|=
neighbour
->
access
;
continue
;
}
/* set the current state search index to the next index
/*
Set the current state search index to the next index
this needs to be done before inserting, so as to make sure that the
pointer is valid
*/
...
...
@@ -2264,9 +2308,11 @@ my_bool get_role_access(ACL_USER *role, ulong *access)
if
(
found
)
{
/* we're going to have to take a look at the same neighbour again
/*
we're going to have to take a look at the same neighbour again
once it is done being explored, thus, set the neigh_idx to "i"
which is the current neighbour that will be added on the stack*/
which is the current neighbour that will be added on the stack
*/
curr_state
->
neigh_idx
=
i
;
/* some sanity checks */
...
...
@@ -2276,29 +2322,26 @@ my_bool get_role_access(ACL_USER *role, ulong *access)
neighbour
->
flags
|=
ROLE_VISITED
;
state
.
neigh_idx
=
0
;
state
.
node_data
=
neighbour
;
insert
_dynamic
(
&
stack
,
&
state
);
push
_dynamic
(
&
stack
,
&
state
);
}
else
{
/*
m
ake sure we got a correct node */
/*
M
ake sure we got a correct node */
DBUG_ASSERT
(
!
(
curr_state
->
node_data
->
flags
&
ROLE_GRANTS_FINAL
));
DBUG_ASSERT
(
curr_state
->
node_data
->
flags
&
ROLE_VISITED
);
/*
if we have finished with exploring the current node, pop it off the
stack
*/
curr_state
=
(
NODE_STATE
<
ACL_USER
>
*
)
pop_dynamic
(
&
stack
);
/* Finished with exploring the current node, pop it off the stack */
curr_state
=
(
NODE_STATE
*
)
pop_dynamic
(
&
stack
);
curr_state
->
node_data
->
flags
&=
~
ROLE_VISITED
;
/* clear the visited bit */
curr_state
->
node_data
->
flags
|=
ROLE_GRANTS_FINAL
;
/*
a
dd the own role's rights once it's finished exploring */
/*
A
dd the own role's rights once it's finished exploring */
curr_state
->
node_data
->
access
|=
curr_state
->
node_data
->
initial_role_access
;
}
}
/*
c
leanup */
/*
C
leanup */
delete_dynamic
(
&
stack
);
/*
f
inally set the access */
/*
F
inally set the access */
*
access
=
role
->
access
;
DBUG_RETURN
(
0
);
}
...
...
@@ -2317,7 +2360,7 @@ int add_role_user_mapping(ROLE_GRANT_PAIR *mapping)
ACL_USER
*
user
=
find_user_no_anon
((
mapping
->
u_hname
)
?
mapping
->
u_hname
:
""
,
(
mapping
->
u_uname
)
?
mapping
->
u_uname
:
""
,
TRUE
);
ACL_
USER
*
role
=
find_acl_role
(
mapping
->
r_uname
?
mapping
->
r_uname
:
""
);
ACL_
ROLE
*
role
=
find_acl_role
(
mapping
->
r_uname
?
mapping
->
r_uname
:
""
);
int
result
=
0
;
...
...
@@ -2341,13 +2384,7 @@ int add_role_user_mapping(ROLE_GRANT_PAIR *mapping)
}
push_dynamic
(
&
user
->
role_grants
,
(
uchar
*
)
&
role
);
/*
Only add the other link if the grant is between a user
and a role, otherwise, the grant is unidirectional,
so as to prevent cycles in the grant role to role graph.
*/
if
(
!
result
)
push_dynamic
(
&
role
->
role_grants
,
(
uchar
*
)
&
user
);
push_dynamic
(
&
role
->
parent_grantee
,
(
uchar
*
)
&
user
);
DBUG_PRINT
(
"info"
,
(
"Found %s %s@%s having role granted %s@%s
\n
"
,
(
result
)
?
"role"
:
"user"
,
...
...
@@ -2681,7 +2718,7 @@ find_user_no_anon(const char *host, const char *user, my_bool exact)
/*
Find first entry that matches the current user
*/
static
ACL_
USER
*
static
ACL_
ROLE
*
find_acl_role
(
const
char
*
user
)
{
DBUG_ENTER
(
"find_acl_role"
);
...
...
@@ -2689,7 +2726,7 @@ find_acl_role(const char *user)
mysql_mutex_assert_owner
(
&
acl_cache
->
lock
);
DBUG_RETURN
((
ACL_
USER
*
)
my_hash_search
(
&
acl_roles
,
(
uchar
*
)
user
,
DBUG_RETURN
((
ACL_
ROLE
*
)
my_hash_search
(
&
acl_roles
,
(
uchar
*
)
user
,
user
?
strlen
(
user
)
:
0
));
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment