1use std::sync::Arc;
4
5use rupg_common::Result;
6
7use super::{Catalog, no_object};
8use crate::{
9 ObjRef, PG_COLLATION, PG_EXTENSION, PG_LANGUAGE, PG_OPCLASS, PG_OPERATOR, PG_OPFAMILY, PG_PROC,
10 PG_STATISTIC_EXT, PG_TS_CONFIG, PG_TS_DICT, PG_TYPE,
11};
12
13const RIGHTS: &[u8] = b"arwdDxtXUCTcsAm";
15
16struct Item {
18 grantee: String,
19 grantor: String,
20 rights: u32,
21 options: u32,
22}
23
24impl Item {
25 fn parse(text: &str) -> Option<Item> {
27 let (grantee, rest) = text.split_once('=')?;
28 let (privileges, grantor) = rest.rsplit_once('/')?;
29 let (mut rights, mut options) = (0, 0);
30 let mut last = None;
31 for b in privileges.bytes() {
32 if b == b'*' {
33 options |= last?;
34 continue;
35 }
36 let bit = 1 << RIGHTS.iter().position(|&r| r == b)?;
37 rights |= bit;
38 last = Some(bit);
39 }
40 Some(Item { grantee: grantee.into(), grantor: grantor.into(), rights, options })
41 }
42
43 fn text(&self) -> String {
45 let mut out = format!("{}=", self.grantee);
46 for (i, &letter) in RIGHTS.iter().enumerate() {
47 if self.rights & (1 << i) != 0 {
48 out.push(char::from(letter));
49 if self.options & (1 << i) != 0 {
50 out.push('*');
51 }
52 }
53 }
54 out.push('/');
55 out.push_str(&self.grantor);
56 out
57 }
58}
59
60pub fn acl_new_owner(acl: &[String], old: &str, new: &str) -> Vec<String> {
62 let mut items: Vec<(Option<Item>, &String)> = Vec::with_capacity(acl.len());
63 let mut new_present = false;
64 for text in acl {
65 let mut item = Item::parse(text);
66 if let Some(item) = &mut item {
67 for name in [&mut item.grantee, &mut item.grantor] {
68 if name == new {
69 new_present = true;
70 } else if name == old {
71 *name = new.to_string();
72 }
73 }
74 }
75 items.push((item, text));
76 }
77 if new_present {
78 for dst in 0..items.len() {
79 let Some(item) = &items[dst].0 else { continue };
80 if item.rights == 0 {
81 continue;
82 }
83 let (grantee, grantor) = (item.grantee.clone(), item.grantor.clone());
84 let (mut rights, mut options) = (0, 0);
85 for (src, _) in items.iter_mut().skip(dst + 1) {
86 if let Some(src) = src
87 && src.grantee == grantee
88 && src.grantor == grantor
89 {
90 rights |= src.rights;
91 options |= src.options;
92 src.rights = 0;
93 src.options = 0;
94 }
95 }
96 if let Some(item) = &mut items[dst].0 {
97 item.rights |= rights;
98 item.options |= options;
99 }
100 }
101 items.retain(|(item, _)| !matches!(item, Some(item) if item.rights == 0));
102 }
103 items
104 .into_iter()
105 .map(|(item, text)| item.map_or_else(|| text.clone(), |item| item.text()))
106 .collect()
107}
108
109impl Catalog {
110 pub fn set_relation_owner(&mut self, oid: u32, owner: u32, old: &str, new: &str) -> Result<()> {
112 let rel = self.relation_mut(oid)?;
113 rel.owner = owner;
114 if let Some(acl) = &rel.acl {
115 rel.acl = Some(acl_new_owner(acl, old, new));
116 }
117 let row_type = rel.row_type;
118 let array = match self.types.get_mut(&row_type) {
119 Some(ty) => {
120 ty.owner = owner;
121 ty.array
122 }
123 None => 0,
124 };
125 if let Some(ty) = self.types.get_mut(&array) {
126 ty.owner = owner;
127 }
128 Ok(())
129 }
130
131 pub fn set_schema_owner(&mut self, oid: u32, owner: u32, old: &str, new: &str) -> Result<()> {
133 let schema = self.schemas.get_mut(&oid).ok_or_else(|| no_object("schema", oid))?;
134 schema.owner = owner;
135 if let Some(acl) = &schema.acl {
136 schema.acl = Some(acl_new_owner(acl, old, new));
137 }
138 Ok(())
139 }
140
141 pub fn set_object_owner(
147 &mut self,
148 object: ObjRef,
149 owner: u32,
150 old: &str,
151 new: &str,
152 ) -> Result<()> {
153 let found = match object.class {
154 PG_TYPE => true,
155 PG_PROC => self.functions.get_mut(&object.oid).map(|f| f.owner = owner).is_some(),
156 PG_COLLATION => match Arc::make_mut(&mut self.collations).get_mut(&object.oid) {
157 Some(c) => {
158 c.owner = owner;
159 true
160 }
161 None => false,
162 },
163 PG_LANGUAGE => self.languages.get_mut(&object.oid).map(|l| l.owner = owner).is_some(),
164 PG_EXTENSION => self.extensions.get_mut(&object.oid).map(|e| e.owner = owner).is_some(),
165 PG_OPERATOR => self.operators.get_mut(&object.oid).map(|o| o.owner = owner).is_some(),
166 PG_OPCLASS => self.opclasses.get_mut(&object.oid).map(|c| c.owner = owner).is_some(),
167 PG_OPFAMILY => self.opfamilies.get_mut(&object.oid).map(|f| f.owner = owner).is_some(),
168 PG_STATISTIC_EXT => {
169 self.stat_exts.get_mut(&object.oid).map(|s| s.owner = owner).is_some()
170 }
171 PG_TS_DICT => {
172 self.ts_dictionaries.get_mut(&object.oid).map(|d| d.owner = owner).is_some()
173 }
174 PG_TS_CONFIG => self.ts_configs.get_mut(&object.oid).map(|c| c.owner = owner).is_some(),
175 _ => false,
176 };
177 if !found {
178 return Err(no_object("object", object.oid));
179 }
180 if let Some(acl) = self.object_acl(object) {
181 let acl = acl_new_owner(acl, old, new);
182 self.set_object_acl(object, Some(acl));
183 }
184 Ok(())
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 fn acl(items: &[&str]) -> Vec<String> {
193 items.iter().map(|s| s.to_string()).collect()
194 }
195
196 #[test]
197 fn the_new_owner_takes_the_items_of_the_old_owner() {
198 let old = acl(&["alice=arwdDxtm/alice", "=r/alice", "bob=r*/alice"]);
199 assert_eq!(
200 acl_new_owner(&old, "alice", "carol"),
201 ["carol=arwdDxtm/carol", "=r/carol", "bob=r*/carol"]
202 );
203 }
204
205 #[test]
206 fn the_items_of_the_new_owner_merge() {
207 let old = acl(&["alice=arwdDxtm/alice", "bob=r/alice", "bob=w*/bob"]);
208 assert_eq!(acl_new_owner(&old, "alice", "bob"), ["bob=arw*dDxtm/bob"]);
209 let old = acl(&["bob=r/alice", "bob=a*/bob", "alice=UC/alice"]);
210 assert_eq!(acl_new_owner(&old, "alice", "bob"), ["bob=a*rUC/bob"]);
211 let old = acl(&["=U/alice", "bob=X/carol"]);
212 assert_eq!(acl_new_owner(&old, "alice", "bob"), ["=U/bob", "bob=X/carol"]);
213 }
214}