1use super::{registration::RoutineSupportAuthority, routine_kind, routine_local_name};
10use crate::catalog::roles::identity::RoleSubject;
11use crate::catalog::roles::{RoleIdentity, RoleReference};
12
13pub mod binding;
14pub mod grants;
15use crate::{
16 ast::{
17 AlterRoutineOwnerStmt, AlterRoutineStmt, CreateFunction, GrantRoutineStmt, RoutineAclEntry,
18 },
19 catalog::roles::{RoleDefinition, RoleMembership, RoleMembershipKey},
20 catalog::security::object_acl,
21 SQLError,
22};
23use std::collections::BTreeMap;
24use uqa_core::catalog_acl::AclGrantee;
25
26pub trait RoutineExecutionAuthority: RoutineSupportAuthority {
27 fn current_role(&self) -> RoleReference;
28 fn current_user_has_role_identity_privileges(
29 &self,
30 role: crate::catalog::roles::RoleIdentity,
31 ) -> bool;
32}
33
34pub fn routine_owner_identity(stmt: &AlterRoutineOwnerStmt) -> AlterRoutineStmt {
35 AlterRoutineStmt {
36 kind: stmt.kind,
37 name: stmt.name.clone(),
38 arg_types: stmt.arg_types.clone(),
39 arg_type_references: stmt.arg_type_references.clone(),
40 volatility: None,
41 strict: None,
42 security_definer: None,
43 leakproof: None,
44 parallel: None,
45 support: None,
46 cost: None,
47 rows: None,
48 config_actions: Vec::new(),
49 attribute_clauses: crate::ast::RoutineAttributeClauses::default(),
50 }
51}
52
53pub fn ensure_routine_execute_privilege(
54 authority: &dyn RoutineExecutionAuthority,
55 definition: &CreateFunction,
56) -> Result<(), SQLError> {
57 ensure_routine_execute_privilege_named(
58 authority,
59 definition,
60 &routine_local_name(&definition.name)?,
61 )
62}
63
64pub fn ensure_routine_execute_privilege_named(
65 authority: &dyn RoutineExecutionAuthority,
66 definition: &CreateFunction,
67 display_name: &str,
68) -> Result<(), SQLError> {
69 let allowed = routine_privilege_allowed(
70 &bound_routine_owner(definition)?,
71 definition.execute_acl.as_deref(),
72 false,
73 authority.current_user_is_superuser(),
74 |role| authority.current_user_has_role_identity_privileges(*role),
75 );
76 if allowed {
77 Ok(())
78 } else {
79 Err(SQLError::Routine {
80 sqlstate: "42501".into(),
81 message: format!(
82 "permission denied for {} {}",
83 routine_kind(definition),
84 display_name
85 ),
86 })
87 }
88}
89
90pub fn routine_privilege_allowed(
92 owner: &RoleIdentity,
93 acl: Option<&[RoutineAclEntry]>,
94 grant_option: bool,
95 superuser: bool,
96 has_role: impl Fn(&RoleIdentity) -> bool,
97) -> bool {
98 object_acl::privilege_allowed(owner, acl, grant_option, superuser, has_role)
99}
100
101pub fn bound_routine_owner(definition: &CreateFunction) -> Result<RoleIdentity, SQLError> {
102 definition
103 .owner
104 .filter(|owner| owner.is_valid())
105 .ok_or_else(|| {
106 SQLError::Internal(format!(
107 "routine `{}` has no bound catalog owner",
108 definition.name
109 ))
110 })
111}
112
113pub fn validate_routine_acl_roles(
114 _stmt: &GrantRoutineStmt,
115 grantees: &[AclGrantee],
116 requested_grantor: Option<&str>,
117 current_user: &(impl RoleSubject + ?Sized),
118 roles: &BTreeMap<String, RoleDefinition>,
119) -> Result<(), SQLError> {
120 for role in grantees {
121 if role
122 .role_name()
123 .is_some_and(|name| !roles.contains_key(name))
124 {
125 return Err(SQLError::Routine {
126 sqlstate: "42704".into(),
127 message: format!("role \"{role}\" does not exist"),
128 });
129 }
130 }
131 grants::validate_grantor(requested_grantor, current_user, roles)
132}
133
134pub fn select_routine_acl_grantor(
135 definition: &CreateFunction,
136 current_user: &(impl RoleSubject + ?Sized),
137 roles: &BTreeMap<String, RoleDefinition>,
138 memberships: &BTreeMap<RoleMembershipKey, RoleMembership>,
139) -> Result<Option<RoleIdentity>, SQLError> {
140 let owner = bound_routine_owner(definition)?;
141 let grantor = object_acl::select_grantor(
142 owner,
143 definition.execute_acl.as_deref(),
144 current_user,
145 roles,
146 memberships,
147 );
148 if grantor.is_none()
149 && !routine_privilege_allowed(
150 &owner,
151 definition.execute_acl.as_deref(),
152 false,
153 false,
154 |role| crate::catalog::roles::role_inherits(roles, memberships, current_user, role),
155 )
156 {
157 return Err(SQLError::Routine {
158 sqlstate: "42501".into(),
159 message: format!(
160 "permission denied for function {}",
161 routine_local_name(&definition.name)?
162 ),
163 });
164 }
165 Ok(grantor)
166}
167
168pub fn grant_routine_acl(
169 definition: &mut CreateFunction,
170 grantee: Option<RoleIdentity>,
171 grantor: RoleIdentity,
172 grant_option: bool,
173) -> Result<(), SQLError> {
174 let owner = bound_routine_owner(definition)?;
175 object_acl::grant(
176 owner,
177 &mut definition.execute_acl,
178 grantee,
179 grantor,
180 grant_option,
181 );
182 Ok(())
183}
184
185pub fn make_routine_acl_explicit(definition: &mut CreateFunction) -> Result<(), SQLError> {
187 let owner = bound_routine_owner(definition)?;
188 definition.execute_acl = object_acl::explicit_acl(owner, definition.execute_acl.take());
189 Ok(())
190}
191
192pub fn revoke_routine_acl(
193 definition: &mut CreateFunction,
194 grantee: Option<RoleIdentity>,
195 grantor: RoleIdentity,
196 grant_option_only: bool,
197 cascade: bool,
198) -> Result<(), SQLError> {
199 let owner = bound_routine_owner(definition)?;
200 object_acl::revoke(
201 owner,
202 &mut definition.execute_acl,
203 grantee,
204 grantor,
205 grant_option_only,
206 cascade,
207 )
208}
209
210pub fn rewrite_routine_acl_owner(
211 definition: &mut CreateFunction,
212 old_owner: RoleIdentity,
213 new_owner: RoleIdentity,
214) {
215 object_acl::rewrite_owner(&mut definition.execute_acl, old_owner, new_owner);
216}
217
218pub fn routine_acl_warning(is_grant: bool, name: &str) -> crate::SQLNotice {
219 object_acl::acl_warning(is_grant, name.rsplit('.').next().unwrap_or(name))
220}