diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index e1d80ab27..c78a694c6 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -201,7 +201,7 @@ def is_hash(password): def user_mod(cursor, user, host, host_all, password, encrypted, plugin, plugin_hash_string, plugin_auth_string, new_priv, - append_privs, subtract_privs, tls_requires, module, role=False, maria_role=False): + append_privs, subtract_privs, tls_requires, module, role=False): changed = False msg = "User unchanged" grant_option = False @@ -323,7 +323,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted, # Handle privileges if new_priv is not None: - curr_priv = privileges_get(cursor, user, host, maria_role) + curr_priv = privileges_get(cursor, user, host) # If the user has privileges on a db.table that doesn't appear at all in # the new specification, then revoke all privileges on it. @@ -337,7 +337,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted, msg = "Privileges updated" if module.check_mode: return {'changed': True, 'msg': msg, 'password_changed': password_changed} - privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role) + privileges_revoke(cursor, user, host, db_table, priv, grant_option) changed = True # If the user doesn't currently have any privileges on a db.table, then @@ -348,7 +348,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted, msg = "New privileges granted" if module.check_mode: return {'changed': True, 'msg': msg, 'password_changed': password_changed} - privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role) + privileges_grant(cursor, user, host, db_table, priv, tls_requires) changed = True # If the db.table specification exists in both the user's current privileges @@ -390,12 +390,12 @@ def user_mod(cursor, user, host, host_all, password, encrypted, if module.check_mode: return {'changed': True, 'msg': msg, 'password_changed': password_changed} if len(revoke_privs) > 0: - privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option, maria_role) + privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option) if len(grant_privs) > 0: - privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires, maria_role) + privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires) # after privilege manipulation, compare privileges from before and now - after_priv = privileges_get(cursor, user, host, maria_role) + after_priv = privileges_get(cursor, user, host) changed = changed or (curr_priv != after_priv) if role: @@ -454,7 +454,7 @@ def user_get_hostnames(cursor, user): return hostnames -def privileges_get(cursor, user, host, maria_role=False): +def privileges_get(cursor, user, host): """ MySQL doesn't have a better method of getting privileges aside from the SHOW GRANTS query syntax, which requires us to then parse the returned string. Here's an example of the string that is returned from MySQL: @@ -465,10 +465,8 @@ def privileges_get(cursor, user, host, maria_role=False): The dictionary format is the same as that returned by privileges_unpack() below. """ output = {} - if not maria_role: - cursor.execute("SHOW GRANTS FOR %s@%s", (user, host)) - else: - cursor.execute("SHOW GRANTS FOR %s", (user,)) + query = "SHOW GRANTS FOR '%s'@'%s'" % (user, host) + cursor.execute(query) grants = cursor.fetchall() def pick(x): @@ -478,10 +476,10 @@ def pick(x): return x for grant in grants: - if not maria_role: + if get_server_type(cursor) == 'mariadb': res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0]) else: - res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3""", grant[0]) + res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3 ?(.*)""", grant[0]) if res is None: # If a user has roles assigned, we'll have one of priv tuples looking like @@ -490,7 +488,7 @@ def pick(x): # As we use the mysql_role module to manipulate roles # we just ignore such privs below: res = re.match("""GRANT (.+) TO (['`"]).*""", grant[0]) - if not maria_role and res: + if res: continue raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0]) @@ -505,10 +503,14 @@ def pick(x): # Determine if there's a case similar to the above: privileges = normalize_col_grants(privileges) - if not maria_role: + if get_server_type(cursor) == 'mariadb': if "WITH GRANT OPTION" in res.group(7): privileges.append('GRANT') + else: + if "WITH GRANT OPTION" in res.group(4): + privileges.append('GRANT') db = res.group(2) + output.setdefault(db, []).extend(privileges) return output @@ -684,48 +686,33 @@ def privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=True): return output -def privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role=False): +def privileges_revoke(cursor, user, host, db_table, priv, grant_option): # Escape '%' since mysql db.execute() uses a format string db_table = db_table.replace('%', '%%') if grant_option: query = ["REVOKE GRANT OPTION ON %s" % db_table] - if not maria_role: - query.append("FROM %s@%s") - else: - query.append("FROM %s") - + query.append("FROM %s@%s") query = ' '.join(query) cursor.execute(query, (user, host)) priv_string = ",".join([p for p in priv if p not in ('GRANT', )]) if priv_string != "": query = ["REVOKE %s ON %s" % (priv_string, db_table)] - - if not maria_role: - query.append("FROM %s@%s") - params = (user, host) - else: - query.append("FROM %s") - params = (user,) - + query.append("FROM %s@%s") query = ' '.join(query) - cursor.execute(query, params) + cursor.execute(query, (user, host)) cursor.execute("FLUSH PRIVILEGES") -def privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role=False): +def privileges_grant(cursor, user, host, db_table, priv, tls_requires): # Escape '%' since mysql db.execute uses a format string and the # specification of db and table often use a % (SQL wildcard) db_table = db_table.replace('%', '%%') priv_string = ",".join([p for p in priv if p not in ('GRANT', )]) query = ["GRANT %s ON %s" % (priv_string, db_table)] - if not maria_role: - query.append("TO %s@%s") - params = (user, host) - else: - query.append("TO %s") - params = (user) + query.append("TO %s@%s") + params = (user, host) if tls_requires and impl.use_old_user_mgmt(cursor): query, params = mogrify_requires(" ".join(query), params, tls_requires) @@ -851,8 +838,7 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode): module.fail_json(msg="The server version does not match the requirements " "for resource_limits parameter. See module's documentation.") - cursor.execute("SELECT VERSION()") - if 'mariadb' not in cursor.fetchone()[0].lower(): + if get_server_type(cursor) != 'mariadb': if 'MAX_STATEMENT_TIME' in resource_limits: module.fail_json(msg="MAX_STATEMENT_TIME resource limit is only supported by MariaDB.") @@ -879,8 +865,8 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode): def get_impl(cursor): global impl - cursor.execute("SELECT VERSION()") - if 'mariadb' in cursor.fetchone()[0].lower(): + + if get_server_type(cursor) == 'mariadb': from ansible_collections.community.mysql.plugins.module_utils.implementations.mariadb import user as mariauser impl = mariauser else: diff --git a/plugins/modules/mysql_role.py b/plugins/modules/mysql_role.py index e8920933b..1d50faf11 100644 --- a/plugins/modules/mysql_role.py +++ b/plugins/modules/mysql_role.py @@ -789,8 +789,7 @@ def add(self, users, privs, check_mode=False, admin=False, if privs: for db_table, priv in iteritems(privs): privileges_grant(self.cursor, self.name, self.host, - db_table, priv, tls_requires=None, - maria_role=self.is_mariadb) + db_table, priv, tls_requires=None) return True @@ -932,7 +931,7 @@ def update(self, users, privs, check_mode=False, result = user_mod(self.cursor, self.name, self.host, None, None, None, None, None, None, privs, append_privs, subtract_privs, None, - self.module, role=True, maria_role=self.is_mariadb) + self.module, role=True) changed = result['changed'] if admin: