#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; } namespace { std::vector groupByTable(AccessRightsElements && elements) { using Key = std::tuple; std::map grouping_map; for (auto & element : elements) { Key key(element.database, element.any_database, element.table, element.any_table); grouping_map[key].emplace_back(std::move(element)); } std::vector res; res.reserve(grouping_map.size()); boost::range::copy(grouping_map | boost::adaptors::map_values, std::back_inserter(res)); return res; } struct GroupedGrantsAndPartialRevokes { std::vector grants; std::vector partial_revokes; }; GroupedGrantsAndPartialRevokes groupByTable(AccessRights::Elements && elements) { GroupedGrantsAndPartialRevokes res; res.grants = groupByTable(std::move(elements.grants)); res.partial_revokes = groupByTable(std::move(elements.partial_revokes)); return res; } template ASTs getGrantQueriesImpl( const T & grantee, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode = false) { ASTs res; std::shared_ptr to_roles = std::make_shared(); to_roles->names.push_back(grantee.getName()); for (bool grant_option : {true, false}) { if (!grant_option && (grantee.access == grantee.access_with_grant_option)) continue; const auto & access_rights = grant_option ? grantee.access_with_grant_option : grantee.access; const auto grouped_elements = groupByTable(access_rights.getElements()); using Kind = ASTGrantQuery::Kind; for (Kind kind : {Kind::GRANT, Kind::REVOKE}) { for (const auto & elements : (kind == Kind::GRANT ? grouped_elements.grants : grouped_elements.partial_revokes)) { auto grant_query = std::make_shared(); grant_query->kind = kind; grant_query->attach = attach_mode; grant_query->grant_option = grant_option; grant_query->to_roles = to_roles; grant_query->access_rights_elements = elements; res.push_back(std::move(grant_query)); } } } for (bool admin_option : {true, false}) { if (!admin_option && (grantee.granted_roles == grantee.granted_roles_with_admin_option)) continue; const auto & roles = admin_option ? grantee.granted_roles_with_admin_option : grantee.granted_roles; if (roles.empty()) continue; auto grant_query = std::make_shared(); using Kind = ASTGrantQuery::Kind; grant_query->kind = Kind::GRANT; grant_query->attach = attach_mode; grant_query->admin_option = admin_option; grant_query->to_roles = to_roles; if (attach_mode) grant_query->roles = ExtendedRoleSet{roles}.toAST(); else grant_query->roles = ExtendedRoleSet{roles}.toASTWithNames(*manager); res.push_back(std::move(grant_query)); } return res; } ASTs getGrantQueriesImpl( const IAccessEntity & entity, const AccessControlManager * manager /* not used if attach_mode == true */, bool attach_mode = false) { if (const User * user = typeid_cast(&entity)) return getGrantQueriesImpl(*user, manager, attach_mode); if (const Role * role = typeid_cast(&entity)) return getGrantQueriesImpl(*role, manager, attach_mode); throw Exception("Unexpected type of access entity: " + entity.getTypeName(), ErrorCodes::LOGICAL_ERROR); } } BlockIO InterpreterShowGrantsQuery::execute() { BlockIO res; res.in = executeImpl(); return res; } BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl() { const auto & show_query = query_ptr->as(); /// Build a create query. ASTs grant_queries = getGrantQueries(show_query); /// Build the result column. MutableColumnPtr column = ColumnString::create(); std::stringstream grant_ss; for (const auto & grant_query : grant_queries) { grant_ss.str(""); formatAST(*grant_query, grant_ss, false, true); column->insert(grant_ss.str()); } /// Prepare description of the result column. std::stringstream desc_ss; formatAST(show_query, desc_ss, false, true); String desc = desc_ss.str(); String prefix = "SHOW "; if (desc.starts_with(prefix)) desc = desc.substr(prefix.length()); /// `desc` always starts with "SHOW ", so we can trim this prefix. return std::make_shared(Block{{std::move(column), std::make_shared(), desc}}); } ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show_query) const { const auto & access_control = context.getAccessControlManager(); AccessEntityPtr user_or_role; if (show_query.current_user) user_or_role = context.getUser(); else { user_or_role = access_control.tryRead(show_query.name); if (!user_or_role) user_or_role = access_control.read(show_query.name); } return getGrantQueriesImpl(*user_or_role, &access_control); } ASTs InterpreterShowGrantsQuery::getAttachGrantQueries(const IAccessEntity & user_or_role) { return getGrantQueriesImpl(user_or_role, nullptr, true); } }