108{
109 bool ok = true;
110 char **aclitems = NULL;
111 char **baseitems = NULL;
112 char **grantitems = NULL;
113 char **revokeitems = NULL;
114 int naclitems = 0;
115 int nbaseitems = 0;
116 int ngrantitems = 0;
117 int nrevokeitems = 0;
120 grantor,
121 privs,
122 privswgo;
124 secondsql;
125
126 /*
127 * If the acl was NULL (initial default state), we need do nothing. Note
128 * that this is distinguishable from all-privileges-revoked, which will
129 * look like an empty array ("{}").
130 */
131 if (acls == NULL || *acls == '0円')
132 return true; /* object has default permissions */
133
134 /* treat empty-string owner same as NULL */
135 if (owner && *owner == '0円')
136 owner = NULL;
137
138 /* Parse the acls array */
140 {
142 return false;
143 }
144
145 /* Parse the baseacls too */
147 {
150 return false;
151 }
152
153 /*
154 * Compare the actual ACL with the base ACL, extracting the privileges
155 * that need to be granted (i.e., are in the actual ACL but not the base
156 * ACL) and the ones that need to be revoked (the reverse). We use plain
157 * string comparisons to check for matches. In principle that could be
158 * fooled by extraneous issues such as whitespace, but since all these
159 * strings are the work of aclitemout(), it should be OK in practice.
160 * Besides, a false mismatch will just cause the output to be a little
161 * more verbose than it really needed to be.
162 */
163 grantitems = (
char **)
pg_malloc(naclitems *
sizeof(
char *));
164 for (
i = 0;
i < naclitems;
i++)
165 {
166 bool found = false;
167
168 for (
int j = 0;
j < nbaseitems;
j++)
169 {
170 if (strcmp(aclitems[
i], baseitems[
j]) == 0)
171 {
172 found = true;
173 break;
174 }
175 }
176 if (!found)
177 grantitems[ngrantitems++] = aclitems[
i];
178 }
179 revokeitems = (
char **)
pg_malloc(nbaseitems *
sizeof(
char *));
180 for (
i = 0;
i < nbaseitems;
i++)
181 {
182 bool found = false;
183
184 for (
int j = 0;
j < naclitems;
j++)
185 {
186 if (strcmp(baseitems[
i], aclitems[
j]) == 0)
187 {
188 found = true;
189 break;
190 }
191 }
192 if (!found)
193 revokeitems[nrevokeitems++] = baseitems[
i];
194 }
195
196 /* Prepare working buffers */
201
202 /*
203 * At the end, these two will be pasted together to form the result.
204 */
207
208 /*
209 * Build REVOKE statements for ACLs listed in revokeitems[].
210 */
211 for (
i = 0;
i < nrevokeitems;
i++)
212 {
215 grantee, grantor, privs, NULL))
216 {
217 ok = false;
218 break;
219 }
220
222 {
225 if (nspname && *nspname)
230 if (grantee->
len == 0)
232 else
235 }
236 }
237
238 /*
239 * At this point we have issued REVOKE statements for all initial and
240 * default privileges that are no longer present on the object, so we are
241 * almost ready to GRANT the privileges listed in grantitems[].
242 *
243 * We still need some hacking though to cover the case where new default
244 * public privileges are added in new versions: the REVOKE ALL will revoke
245 * them, leading to behavior different from what the old version had,
246 * which is generally not what's wanted. So add back default privs if the
247 * source database is too old to have had that particular priv. (As of
248 * right now, no such cases exist in supported versions.)
249 */
250
251 /*
252 * Scan individual ACL items to be granted.
253 *
254 * The order in which privileges appear in the ACL string (the order they
255 * have been GRANT'd in, which the backend maintains) must be preserved to
256 * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
257 * those are dumped in the correct order. However, some old server
258 * versions will show grants to PUBLIC before the owner's own grants; for
259 * consistency's sake, force the owner's grants to be output first.
260 */
261 for (
i = 0;
i < ngrantitems;
i++)
262 {
264 grantee, grantor, privs, privswgo))
265 {
266 /*
267 * If the grantor isn't the owner, we'll need to use SET SESSION
268 * AUTHORIZATION to become the grantor. Issue the SET/RESET only
269 * if there's something useful to do.
270 */
271 if (privs->
len > 0 || privswgo->
len > 0)
272 {
274
275 /* Set owner as grantor if that's not explicit in the ACL */
276 if (grantor->
len == 0 && owner)
278
279 /* Make sure owner's own grants are output before others */
280 if (owner &&
281 strcmp(grantee->
data, owner) == 0 &&
282 strcmp(grantor->
data, owner) == 0)
283 thissql = firstsql;
284 else
285 thissql = secondsql;
286
288 && (!owner || strcmp(owner, grantor->
data) != 0))
291
293 {
296 if (nspname && *nspname)
301 if (grantee->
len == 0)
303 else
305 }
306 if (privswgo->
len > 0)
307 {
310 if (nspname && *nspname)
315 if (grantee->
len == 0)
317 else
320 }
321
323 && (!owner || strcmp(owner, grantor->
data) != 0))
325 }
326 }
327 else
328 {
329 /* parseAclItem failed, give up */
330 ok = false;
331 break;
332 }
333 }
334
339
343
348
349 return ok;
350}
static bool parseAclItem(const char *item, const char *type, const char *name, const char *subname, int remoteVersion, PQExpBuffer grantee, PQExpBuffer grantor, PQExpBuffer privs, PQExpBuffer privswgo)
void * pg_malloc(size_t size)
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
PQExpBuffer createPQExpBuffer(void)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void destroyPQExpBuffer(PQExpBuffer str)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
const char * fmtId(const char *rawid)
bool parsePGArray(const char *atext, char ***itemarray, int *nitems)