1 /*-------------------------------------------------------------------------
2  *
3  * Utility routines for SQL dumping
4  *
5  * Basically this is stuff that is useful in both pg_dump and pg_dumpall.
6  *
7  *
8  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  * src/bin/pg_dump/dumputils.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres_fe.h"
16 
17 #include <ctype.h>
18 
19 #include "dumputils.h"
20 #include "fe_utils/string_utils.h"
21 
22 
23 #define supports_grant_options(version) ((version) >= 70400)
24 
25 static bool parseAclItem(const char *item, const char *type,
26 			 const char *name, const char *subname, int remoteVersion,
27 			 PQExpBuffer grantee, PQExpBuffer grantor,
28 			 PQExpBuffer privs, PQExpBuffer privswgo);
29 static char *copyAclUserName(PQExpBuffer output, char *input);
30 static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
31 	   const char *subname);
32 
33 
34 /*
35  * Build GRANT/REVOKE command(s) for an object.
36  *
37  *	name: the object name, in the form to use in the commands (already quoted)
38  *	subname: the sub-object name, if any (already quoted); NULL if none
39  *	nspname: the namespace the object is in (NULL if none); not pre-quoted
40  *	type: the object type (as seen in GRANT command: must be one of
41  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
42  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
43  *	acls: the ACL string fetched from the database
44  *	racls: the ACL string of any initial-but-now-revoked privileges
45  *	owner: username of object owner (will be passed through fmtId); can be
46  *		NULL or empty string to indicate "no owner known"
47  *	prefix: string to prefix to each generated command; typically empty
48  *	remoteVersion: version of database
49  *
50  * Returns TRUE if okay, FALSE if could not parse the acl string.
51  * The resulting commands (if any) are appended to the contents of 'sql'.
52  *
53  * Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
54  * or something similar, and name is an empty string.
55  *
56  * Note: beware of passing a fmtId() result directly as 'name' or 'subname',
57  * since this routine uses fmtId() internally.
58  */
59 bool
buildACLCommands(const char * name,const char * subname,const char * nspname,const char * type,const char * acls,const char * racls,const char * owner,const char * prefix,int remoteVersion,PQExpBuffer sql)60 buildACLCommands(const char *name, const char *subname, const char *nspname,
61 				 const char *type, const char *acls, const char *racls,
62 				 const char *owner, const char *prefix, int remoteVersion,
63 				 PQExpBuffer sql)
64 {
65 	bool		ok = true;
66 	char	  **aclitems = NULL;
67 	char	  **raclitems = NULL;
68 	int			naclitems = 0;
69 	int			nraclitems = 0;
70 	int			i;
71 	PQExpBuffer grantee,
72 				grantor,
73 				privs,
74 				privswgo;
75 	PQExpBuffer firstsql,
76 				secondsql;
77 	bool		found_owner_privs = false;
78 
79 	if (strlen(acls) == 0 && strlen(racls) == 0)
80 		return true;			/* object has default permissions */
81 
82 	/* treat empty-string owner same as NULL */
83 	if (owner && *owner == '\0')
84 		owner = NULL;
85 
86 	if (strlen(acls) != 0)
87 	{
88 		if (!parsePGArray(acls, &aclitems, &naclitems))
89 		{
90 			if (aclitems)
91 				free(aclitems);
92 			return false;
93 		}
94 	}
95 
96 	if (strlen(racls) != 0)
97 	{
98 		if (!parsePGArray(racls, &raclitems, &nraclitems))
99 		{
100 			if (raclitems)
101 				free(raclitems);
102 			return false;
103 		}
104 	}
105 
106 	grantee = createPQExpBuffer();
107 	grantor = createPQExpBuffer();
108 	privs = createPQExpBuffer();
109 	privswgo = createPQExpBuffer();
110 
111 	/*
112 	 * At the end, these two will be pasted together to form the result.
113 	 *
114 	 * For older systems we use these to ensure that the owner privileges go
115 	 * before the other ones, as a GRANT could create the default entry for
116 	 * the object, which generally includes all rights for the owner. In more
117 	 * recent versions we normally handle this because the owner rights come
118 	 * first in the ACLs, but older versions might have them after the PUBLIC
119 	 * privileges.
120 	 *
121 	 * For 9.6 and later systems, much of this changes.  With 9.6, we check
122 	 * the default privileges for the objects at dump time and create two sets
123 	 * of ACLs- "racls" which are the ACLs to REVOKE from the object (as the
124 	 * object may have initial privileges on it, along with any default ACLs
125 	 * which are not part of the current set of privileges), and regular
126 	 * "acls", which are the ACLs to GRANT to the object.  We handle the
127 	 * REVOKEs first, followed by the GRANTs.
128 	 */
129 	firstsql = createPQExpBuffer();
130 	secondsql = createPQExpBuffer();
131 
132 	/*
133 	 * For pre-9.6 systems, we always start with REVOKE ALL FROM PUBLIC, as we
134 	 * don't wish to make any assumptions about what the default ACLs are, and
135 	 * we do not collect them during the dump phase (and racls will always be
136 	 * the empty set, see above).
137 	 *
138 	 * For 9.6 and later, if any revoke ACLs have been provided, then include
139 	 * them in 'firstsql'.
140 	 *
141 	 * Revoke ACLs happen when an object starts out life with a set of
142 	 * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has
143 	 * decided to revoke those rights.  Since those objects come into being
144 	 * with those default privileges, we have to revoke them to match what the
145 	 * current state of affairs is.  Note that we only started explicitly
146 	 * tracking such initial rights in 9.6, and prior to that all initial
147 	 * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'
148 	 * case, for initdb-created objects.  Prior to 9.6, we didn't handle
149 	 * extensions correctly, but we do now by tracking their initial
150 	 * privileges, in the same way we track initdb initial privileges, see
151 	 * pg_init_privs.
152 	 */
153 	if (remoteVersion < 90600)
154 	{
155 		Assert(nraclitems == 0);
156 
157 		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
158 		if (subname)
159 			appendPQExpBuffer(firstsql, "(%s)", subname);
160 		appendPQExpBuffer(firstsql, " ON %s ", type);
161 		if (nspname && *nspname)
162 			appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
163 		appendPQExpBuffer(firstsql, "%s FROM PUBLIC;\n", name);
164 	}
165 	else
166 	{
167 		/* Scan individual REVOKE ACL items */
168 		for (i = 0; i < nraclitems; i++)
169 		{
170 			if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
171 							  grantee, grantor, privs, NULL))
172 			{
173 				ok = false;
174 				break;
175 			}
176 
177 			if (privs->len > 0)
178 			{
179 				appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s ",
180 								  prefix, privs->data, type);
181 				if (nspname && *nspname)
182 					appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
183 				appendPQExpBuffer(firstsql, "%s FROM ", name);
184 				if (grantee->len == 0)
185 					appendPQExpBufferStr(firstsql, "PUBLIC;\n");
186 				else if (strncmp(grantee->data, "group ",
187 								 strlen("group ")) == 0)
188 					appendPQExpBuffer(firstsql, "GROUP %s;\n",
189 									  fmtId(grantee->data + strlen("group ")));
190 				else
191 					appendPQExpBuffer(firstsql, "%s;\n",
192 									  fmtId(grantee->data));
193 			}
194 		}
195 	}
196 
197 	/*
198 	 * We still need some hacking though to cover the case where new default
199 	 * public privileges are added in new versions: the REVOKE ALL will revoke
200 	 * them, leading to behavior different from what the old version had,
201 	 * which is generally not what's wanted.  So add back default privs if the
202 	 * source database is too old to have had that particular priv.
203 	 */
204 	if (remoteVersion < 80200 && strcmp(type, "DATABASE") == 0)
205 	{
206 		/* database CONNECT priv didn't exist before 8.2 */
207 		appendPQExpBuffer(firstsql, "%sGRANT CONNECT ON %s %s TO PUBLIC;\n",
208 						  prefix, type, name);
209 	}
210 
211 	/* Scan individual ACL items */
212 	for (i = 0; i < naclitems; i++)
213 	{
214 		if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,
215 						  grantee, grantor, privs, privswgo))
216 		{
217 			ok = false;
218 			break;
219 		}
220 
221 		if (grantor->len == 0 && owner)
222 			printfPQExpBuffer(grantor, "%s", owner);
223 
224 		if (privs->len > 0 || privswgo->len > 0)
225 		{
226 			/*
227 			 * Prior to 9.6, we had to handle owner privileges in a special
228 			 * manner by first REVOKE'ing the rights and then GRANT'ing them
229 			 * after.  With 9.6 and above, what we need to REVOKE and what we
230 			 * need to GRANT is figured out when we dump and stashed into
231 			 * "racls" and "acls", respectively.  See above.
232 			 */
233 			if (remoteVersion < 90600 && owner
234 				&& strcmp(grantee->data, owner) == 0
235 				&& strcmp(grantor->data, owner) == 0)
236 			{
237 				found_owner_privs = true;
238 
239 				/*
240 				 * For the owner, the default privilege level is ALL WITH
241 				 * GRANT OPTION (only ALL prior to 7.4).
242 				 */
243 				if (supports_grant_options(remoteVersion)
244 					? strcmp(privswgo->data, "ALL") != 0
245 					: strcmp(privs->data, "ALL") != 0)
246 				{
247 					appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
248 					if (subname)
249 						appendPQExpBuffer(firstsql, "(%s)", subname);
250 					appendPQExpBuffer(firstsql, " ON %s ", type);
251 					if (nspname && *nspname)
252 						appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
253 					appendPQExpBuffer(firstsql, "%s FROM %s;\n",
254 									  name, fmtId(grantee->data));
255 					if (privs->len > 0)
256 					{
257 						appendPQExpBuffer(firstsql,
258 										  "%sGRANT %s ON %s ",
259 										  prefix, privs->data, type);
260 						if (nspname && *nspname)
261 							appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
262 						appendPQExpBuffer(firstsql,
263 										  "%s TO %s;\n",
264 										  name, fmtId(grantee->data));
265 					}
266 					if (privswgo->len > 0)
267 					{
268 						appendPQExpBuffer(firstsql,
269 										  "%sGRANT %s ON %s ",
270 										  prefix, privswgo->data, type);
271 						if (nspname && *nspname)
272 							appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
273 						appendPQExpBuffer(firstsql,
274 										  "%s TO %s WITH GRANT OPTION;\n",
275 										  name, fmtId(grantee->data));
276 					}
277 				}
278 			}
279 			else
280 			{
281 				/*
282 				 * For systems prior to 9.6, we can assume we are starting
283 				 * from no privs at this point.
284 				 *
285 				 * For 9.6 and above, at this point we have issued REVOKE
286 				 * statements for all initial and default privileges which are
287 				 * no longer present on the object (as they were passed in as
288 				 * 'racls') and we can simply GRANT the rights which are in
289 				 * 'acls'.
290 				 */
291 				if (grantor->len > 0
292 					&& (!owner || strcmp(owner, grantor->data) != 0))
293 					appendPQExpBuffer(secondsql, "SET SESSION AUTHORIZATION %s;\n",
294 									  fmtId(grantor->data));
295 
296 				if (privs->len > 0)
297 				{
298 					appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",
299 									  prefix, privs->data, type);
300 					if (nspname && *nspname)
301 						appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));
302 					appendPQExpBuffer(secondsql, "%s TO ", name);
303 					if (grantee->len == 0)
304 						appendPQExpBufferStr(secondsql, "PUBLIC;\n");
305 					else if (strncmp(grantee->data, "group ",
306 									 strlen("group ")) == 0)
307 						appendPQExpBuffer(secondsql, "GROUP %s;\n",
308 									fmtId(grantee->data + strlen("group ")));
309 					else
310 						appendPQExpBuffer(secondsql, "%s;\n", fmtId(grantee->data));
311 				}
312 				if (privswgo->len > 0)
313 				{
314 					appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",
315 									  prefix, privswgo->data, type);
316 					if (nspname && *nspname)
317 						appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));
318 					appendPQExpBuffer(secondsql, "%s TO ", name);
319 					if (grantee->len == 0)
320 						appendPQExpBufferStr(secondsql, "PUBLIC");
321 					else if (strncmp(grantee->data, "group ",
322 									 strlen("group ")) == 0)
323 						appendPQExpBuffer(secondsql, "GROUP %s",
324 									fmtId(grantee->data + strlen("group ")));
325 					else
326 						appendPQExpBufferStr(secondsql, fmtId(grantee->data));
327 					appendPQExpBufferStr(secondsql, " WITH GRANT OPTION;\n");
328 				}
329 
330 				if (grantor->len > 0
331 					&& (!owner || strcmp(owner, grantor->data) != 0))
332 					appendPQExpBufferStr(secondsql, "RESET SESSION AUTHORIZATION;\n");
333 			}
334 		}
335 	}
336 
337 	/*
338 	 * For systems prior to 9.6, if we didn't find any owner privs, the owner
339 	 * must have revoked 'em all.
340 	 *
341 	 * For 9.6 and above, we handle this through the 'racls'.  See above.
342 	 */
343 	if (remoteVersion < 90600 && !found_owner_privs && owner)
344 	{
345 		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
346 		if (subname)
347 			appendPQExpBuffer(firstsql, "(%s)", subname);
348 		appendPQExpBuffer(firstsql, " ON %s ", type);
349 		if (nspname && *nspname)
350 			appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
351 		appendPQExpBuffer(firstsql, "%s FROM %s;\n",
352 						  name, fmtId(owner));
353 	}
354 
355 	destroyPQExpBuffer(grantee);
356 	destroyPQExpBuffer(grantor);
357 	destroyPQExpBuffer(privs);
358 	destroyPQExpBuffer(privswgo);
359 
360 	appendPQExpBuffer(sql, "%s%s", firstsql->data, secondsql->data);
361 	destroyPQExpBuffer(firstsql);
362 	destroyPQExpBuffer(secondsql);
363 
364 	if (aclitems)
365 		free(aclitems);
366 
367 	if (raclitems)
368 		free(raclitems);
369 
370 	return ok;
371 }
372 
373 /*
374  * Build ALTER DEFAULT PRIVILEGES command(s) for single pg_default_acl entry.
375  *
376  *	type: the object type (TABLES, FUNCTIONS, etc)
377  *	nspname: schema name, or NULL for global default privileges
378  *	acls: the ACL string fetched from the database
379  *	owner: username of privileges owner (will be passed through fmtId)
380  *	remoteVersion: version of database
381  *
382  * Returns TRUE if okay, FALSE if could not parse the acl string.
383  * The resulting commands (if any) are appended to the contents of 'sql'.
384  */
385 bool
buildDefaultACLCommands(const char * type,const char * nspname,const char * acls,const char * racls,const char * initacls,const char * initracls,const char * owner,int remoteVersion,PQExpBuffer sql)386 buildDefaultACLCommands(const char *type, const char *nspname,
387 						const char *acls, const char *racls,
388 						const char *initacls, const char *initracls,
389 						const char *owner,
390 						int remoteVersion,
391 						PQExpBuffer sql)
392 {
393 	PQExpBuffer prefix;
394 
395 	prefix = createPQExpBuffer();
396 
397 	/*
398 	 * We incorporate the target role directly into the command, rather than
399 	 * playing around with SET ROLE or anything like that.  This is so that a
400 	 * permissions error leads to nothing happening, rather than changing
401 	 * default privileges for the wrong user.
402 	 */
403 	appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
404 					  fmtId(owner));
405 	if (nspname)
406 		appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
407 
408 	if (strlen(initacls) != 0 || strlen(initracls) != 0)
409 	{
410 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
411 		if (!buildACLCommands("", NULL, NULL, type,
412 							  initacls, initracls, owner,
413 							  prefix->data, remoteVersion, sql))
414 		{
415 			destroyPQExpBuffer(prefix);
416 			return false;
417 		}
418 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
419 	}
420 
421 	if (!buildACLCommands("", NULL, NULL, type,
422 						  acls, racls, owner,
423 						  prefix->data, remoteVersion, sql))
424 	{
425 		destroyPQExpBuffer(prefix);
426 		return false;
427 	}
428 
429 	destroyPQExpBuffer(prefix);
430 
431 	return true;
432 }
433 
434 /*
435  * This will parse an aclitem string, having the general form
436  *		username=privilegecodes/grantor
437  * or
438  *		group groupname=privilegecodes/grantor
439  * (the /grantor part will not be present if pre-7.4 database).
440  *
441  * The returned grantee string will be the dequoted username or groupname
442  * (preceded with "group " in the latter case).  Note that a grant to PUBLIC
443  * is represented by an empty grantee string.  The returned grantor is the
444  * dequoted grantor name.  Privilege characters are translated to GRANT/REVOKE
445  * comma-separated privileges lists.  If "privswgo" is non-NULL, the result is
446  * separate lists for privileges with grant option ("privswgo") and without
447  * ("privs").  Otherwise, "privs" bears every relevant privilege, ignoring the
448  * grant option distinction.
449  *
450  * Note: for cross-version compatibility, it's important to use ALL when
451  * appropriate.
452  */
453 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)454 parseAclItem(const char *item, const char *type,
455 			 const char *name, const char *subname, int remoteVersion,
456 			 PQExpBuffer grantee, PQExpBuffer grantor,
457 			 PQExpBuffer privs, PQExpBuffer privswgo)
458 {
459 	char	   *buf;
460 	bool		all_with_go = true;
461 	bool		all_without_go = true;
462 	char	   *eqpos;
463 	char	   *slpos;
464 	char	   *pos;
465 
466 	buf = strdup(item);
467 	if (!buf)
468 		return false;
469 
470 	/* user or group name is string up to = */
471 	eqpos = copyAclUserName(grantee, buf);
472 	if (*eqpos != '=')
473 	{
474 		free(buf);
475 		return false;
476 	}
477 
478 	/* grantor may be listed after / */
479 	slpos = strchr(eqpos + 1, '/');
480 	if (slpos)
481 	{
482 		*slpos++ = '\0';
483 		slpos = copyAclUserName(grantor, slpos);
484 		if (*slpos != '\0')
485 		{
486 			free(buf);
487 			return false;
488 		}
489 	}
490 	else
491 		resetPQExpBuffer(grantor);
492 
493 	/* privilege codes */
494 #define CONVERT_PRIV(code, keywd) \
495 do { \
496 	if ((pos = strchr(eqpos + 1, code))) \
497 	{ \
498 		if (*(pos + 1) == '*' && privswgo != NULL) \
499 		{ \
500 			AddAcl(privswgo, keywd, subname); \
501 			all_without_go = false; \
502 		} \
503 		else \
504 		{ \
505 			AddAcl(privs, keywd, subname); \
506 			all_with_go = false; \
507 		} \
508 	} \
509 	else \
510 		all_with_go = all_without_go = false; \
511 } while (0)
512 
513 	resetPQExpBuffer(privs);
514 	resetPQExpBuffer(privswgo);
515 
516 	if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0 ||
517 		strcmp(type, "TABLES") == 0 || strcmp(type, "SEQUENCES") == 0)
518 	{
519 		CONVERT_PRIV('r', "SELECT");
520 
521 		if (strcmp(type, "SEQUENCE") == 0 ||
522 			strcmp(type, "SEQUENCES") == 0)
523 			/* sequence only */
524 			CONVERT_PRIV('U', "USAGE");
525 		else
526 		{
527 			/* table only */
528 			CONVERT_PRIV('a', "INSERT");
529 			if (remoteVersion >= 70200)
530 				CONVERT_PRIV('x', "REFERENCES");
531 			/* rest are not applicable to columns */
532 			if (subname == NULL)
533 			{
534 				if (remoteVersion >= 70200)
535 				{
536 					CONVERT_PRIV('d', "DELETE");
537 					CONVERT_PRIV('t', "TRIGGER");
538 				}
539 				if (remoteVersion >= 80400)
540 					CONVERT_PRIV('D', "TRUNCATE");
541 			}
542 		}
543 
544 		/* UPDATE */
545 		if (remoteVersion >= 70200 ||
546 			strcmp(type, "SEQUENCE") == 0 ||
547 			strcmp(type, "SEQUENCES") == 0)
548 			CONVERT_PRIV('w', "UPDATE");
549 		else
550 			/* 7.0 and 7.1 have a simpler worldview */
551 			CONVERT_PRIV('w', "UPDATE,DELETE");
552 	}
553 	else if (strcmp(type, "FUNCTION") == 0 ||
554 			 strcmp(type, "FUNCTIONS") == 0)
555 		CONVERT_PRIV('X', "EXECUTE");
556 	else if (strcmp(type, "LANGUAGE") == 0)
557 		CONVERT_PRIV('U', "USAGE");
558 	else if (strcmp(type, "SCHEMA") == 0)
559 	{
560 		CONVERT_PRIV('C', "CREATE");
561 		CONVERT_PRIV('U', "USAGE");
562 	}
563 	else if (strcmp(type, "DATABASE") == 0)
564 	{
565 		CONVERT_PRIV('C', "CREATE");
566 		CONVERT_PRIV('c', "CONNECT");
567 		CONVERT_PRIV('T', "TEMPORARY");
568 	}
569 	else if (strcmp(type, "TABLESPACE") == 0)
570 		CONVERT_PRIV('C', "CREATE");
571 	else if (strcmp(type, "TYPE") == 0 ||
572 			 strcmp(type, "TYPES") == 0)
573 		CONVERT_PRIV('U', "USAGE");
574 	else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
575 		CONVERT_PRIV('U', "USAGE");
576 	else if (strcmp(type, "FOREIGN SERVER") == 0)
577 		CONVERT_PRIV('U', "USAGE");
578 	else if (strcmp(type, "FOREIGN TABLE") == 0)
579 		CONVERT_PRIV('r', "SELECT");
580 	else if (strcmp(type, "LARGE OBJECT") == 0)
581 	{
582 		CONVERT_PRIV('r', "SELECT");
583 		CONVERT_PRIV('w', "UPDATE");
584 	}
585 	else
586 		abort();
587 
588 #undef CONVERT_PRIV
589 
590 	if (all_with_go)
591 	{
592 		resetPQExpBuffer(privs);
593 		printfPQExpBuffer(privswgo, "ALL");
594 		if (subname)
595 			appendPQExpBuffer(privswgo, "(%s)", subname);
596 	}
597 	else if (all_without_go)
598 	{
599 		resetPQExpBuffer(privswgo);
600 		printfPQExpBuffer(privs, "ALL");
601 		if (subname)
602 			appendPQExpBuffer(privs, "(%s)", subname);
603 	}
604 
605 	free(buf);
606 
607 	return true;
608 }
609 
610 /*
611  * Transfer a user or group name starting at *input into the output buffer,
612  * dequoting if needed.  Returns a pointer to just past the input name.
613  * The name is taken to end at an unquoted '=' or end of string.
614  */
615 static char *
copyAclUserName(PQExpBuffer output,char * input)616 copyAclUserName(PQExpBuffer output, char *input)
617 {
618 	resetPQExpBuffer(output);
619 
620 	while (*input && *input != '=')
621 	{
622 		/*
623 		 * If user name isn't quoted, then just add it to the output buffer
624 		 */
625 		if (*input != '"')
626 			appendPQExpBufferChar(output, *input++);
627 		else
628 		{
629 			/* Otherwise, it's a quoted username */
630 			input++;
631 			/* Loop until we come across an unescaped quote */
632 			while (!(*input == '"' && *(input + 1) != '"'))
633 			{
634 				if (*input == '\0')
635 					return input;		/* really a syntax error... */
636 
637 				/*
638 				 * Quoting convention is to escape " as "".  Keep this code in
639 				 * sync with putid() in backend's acl.c.
640 				 */
641 				if (*input == '"' && *(input + 1) == '"')
642 					input++;
643 				appendPQExpBufferChar(output, *input++);
644 			}
645 			input++;
646 		}
647 	}
648 	return input;
649 }
650 
651 /*
652  * Append a privilege keyword to a keyword list, inserting comma if needed.
653  */
654 static void
AddAcl(PQExpBuffer aclbuf,const char * keyword,const char * subname)655 AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
656 {
657 	if (aclbuf->len > 0)
658 		appendPQExpBufferChar(aclbuf, ',');
659 	appendPQExpBufferStr(aclbuf, keyword);
660 	if (subname)
661 		appendPQExpBuffer(aclbuf, "(%s)", subname);
662 }
663 
664 
665 /*
666  * buildShSecLabelQuery
667  *
668  * Build a query to retrieve security labels for a shared object.
669  * The object is identified by its OID plus the name of the catalog
670  * it can be found in (e.g., "pg_database" for database names).
671  * The query is appended to "sql".  (We don't execute it here so as to
672  * keep this file free of assumptions about how to deal with SQL errors.)
673  */
674 void
buildShSecLabelQuery(PGconn * conn,const char * catalog_name,Oid objectId,PQExpBuffer sql)675 buildShSecLabelQuery(PGconn *conn, const char *catalog_name, Oid objectId,
676 					 PQExpBuffer sql)
677 {
678 	appendPQExpBuffer(sql,
679 					  "SELECT provider, label FROM pg_catalog.pg_shseclabel "
680 					  "WHERE classoid = 'pg_catalog.%s'::pg_catalog.regclass "
681 					  "AND objoid = '%u'", catalog_name, objectId);
682 }
683 
684 /*
685  * emitShSecLabels
686  *
687  * Construct SECURITY LABEL commands using the data retrieved by the query
688  * generated by buildShSecLabelQuery, and append them to "buffer".
689  * Here, the target object is identified by its type name (e.g. "DATABASE")
690  * and its name (not pre-quoted).
691  */
692 void
emitShSecLabels(PGconn * conn,PGresult * res,PQExpBuffer buffer,const char * objtype,const char * objname)693 emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
694 				const char *objtype, const char *objname)
695 {
696 	int			i;
697 
698 	for (i = 0; i < PQntuples(res); i++)
699 	{
700 		char	   *provider = PQgetvalue(res, i, 0);
701 		char	   *label = PQgetvalue(res, i, 1);
702 
703 		/* must use fmtId result before calling it again */
704 		appendPQExpBuffer(buffer,
705 						  "SECURITY LABEL FOR %s ON %s",
706 						  fmtId(provider), objtype);
707 		appendPQExpBuffer(buffer,
708 						  " %s IS ",
709 						  fmtId(objname));
710 		appendStringLiteralConn(buffer, label, conn);
711 		appendPQExpBufferStr(buffer, ";\n");
712 	}
713 }
714 
715 /*
716  * buildACLQueries
717  *
718  * Build the subqueries to extract out the correct set of ACLs to be
719  * GRANT'd and REVOKE'd for the specific kind of object, accounting for any
720  * initial privileges (from pg_init_privs) and based on if we are in binary
721  * upgrade mode or not.
722  *
723  * Also builds subqueries to extract out the set of ACLs to go from the object
724  * default privileges to the privileges in pg_init_privs, if we are in binary
725  * upgrade mode, so that those privileges can be set up and recorded in the new
726  * cluster before the regular privileges are added on top of those.
727  */
728 void
buildACLQueries(PQExpBuffer acl_subquery,PQExpBuffer racl_subquery,PQExpBuffer init_acl_subquery,PQExpBuffer init_racl_subquery,const char * acl_column,const char * acl_owner,const char * obj_kind,bool binary_upgrade)729 buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
730 				PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,
731 				const char *acl_column, const char *acl_owner,
732 				const char *obj_kind, bool binary_upgrade)
733 {
734 	/*
735 	 * To get the delta from what the permissions were at creation time
736 	 * (either initdb or CREATE EXTENSION) vs. what they are now, we have to
737 	 * look at two things:
738 	 *
739 	 * What privileges have been added, which we calculate by extracting all
740 	 * the current privileges (using the set of default privileges for the
741 	 * object type if current privileges are NULL) and then removing those
742 	 * which existed at creation time (again, using the set of default
743 	 * privileges for the object type if there were no creation time
744 	 * privileges).
745 	 *
746 	 * What privileges have been removed, which we calculate by extracting the
747 	 * privileges as they were at creation time (or the default privileges, as
748 	 * above), and then removing the current privileges (or the default
749 	 * privileges, if current privileges are NULL).
750 	 *
751 	 * As a good cross-check, both directions of these checks should result in
752 	 * the empty set if both the current ACL and the initial privs are NULL
753 	 * (meaning, in practice, that the default ACLs were there at init time
754 	 * and is what the current privileges are).
755 	 *
756 	 * We always perform this delta on all ACLs and expect that by the time
757 	 * these are run the initial privileges will be in place, even in a binary
758 	 * upgrade situation (see below).
759 	 *
760 	 * Finally, the order in which privileges are in the ACL string (the order
761 	 * they been GRANT'd in, which the backend maintains) must be preserved to
762 	 * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
763 	 * those are dumped in the correct order.
764 	 */
765 	printfPQExpBuffer(acl_subquery,
766 					  "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "
767 					  "(SELECT acl, row_n FROM "
768 					  "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
769 					  "WITH ORDINALITY AS perm(acl,row_n) "
770 					  "WHERE NOT EXISTS ( "
771 					  "SELECT 1 FROM "
772 					  "pg_catalog.unnest(coalesce(pip.initprivs,pg_catalog.acldefault(%s,%s))) "
773 					  "AS init(init_acl) WHERE acl = init_acl)) as foo)",
774 					  acl_column,
775 					  obj_kind,
776 					  acl_owner,
777 					  obj_kind,
778 					  acl_owner);
779 
780 	printfPQExpBuffer(racl_subquery,
781 					  "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "
782 					  "(SELECT acl, row_n FROM "
783 					  "pg_catalog.unnest(coalesce(pip.initprivs,pg_catalog.acldefault(%s,%s))) "
784 					  "WITH ORDINALITY AS initp(acl,row_n) "
785 					  "WHERE NOT EXISTS ( "
786 					  "SELECT 1 FROM "
787 					  "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
788 					  "AS permp(orig_acl) WHERE acl = orig_acl)) as foo)",
789 					  obj_kind,
790 					  acl_owner,
791 					  acl_column,
792 					  obj_kind,
793 					  acl_owner);
794 
795 	/*
796 	 * In binary upgrade mode we don't run the extension script but instead
797 	 * dump out the objects independently and then recreate them.  To preserve
798 	 * the initial privileges which were set on extension objects, we need to
799 	 * grab the set of GRANT and REVOKE commands necessary to get from the
800 	 * default privileges of an object to the initial privileges as recorded
801 	 * in pg_init_privs.
802 	 *
803 	 * These will then be run ahead of the regular ACL commands, which were
804 	 * calculated using the queries above, inside of a block which sets a flag
805 	 * to indicate that the backend should record the results of these GRANT
806 	 * and REVOKE statements into pg_init_privs.  This is how we preserve the
807 	 * contents of that catalog across binary upgrades.
808 	 */
809 	if (binary_upgrade)
810 	{
811 		printfPQExpBuffer(init_acl_subquery,
812 						  "CASE WHEN privtype = 'e' THEN "
813 						  "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "
814 						  "(SELECT acl, row_n FROM pg_catalog.unnest(pip.initprivs) "
815 						  "WITH ORDINALITY AS initp(acl,row_n) "
816 						  "WHERE NOT EXISTS ( "
817 						  "SELECT 1 FROM "
818 						  "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "
819 						  "AS privm(orig_acl) WHERE acl = orig_acl)) as foo) END",
820 						  obj_kind,
821 						  acl_owner);
822 
823 		printfPQExpBuffer(init_racl_subquery,
824 						  "CASE WHEN privtype = 'e' THEN "
825 						  "(SELECT pg_catalog.array_agg(acl) FROM "
826 						  "(SELECT acl, row_n FROM "
827 						  "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "
828 						  "WITH ORDINALITY AS privp(acl,row_n) "
829 						  "WHERE NOT EXISTS ( "
830 						  "SELECT 1 FROM pg_catalog.unnest(pip.initprivs) "
831 						  "AS initp(init_acl) WHERE acl = init_acl)) as foo) END",
832 						  obj_kind,
833 						  acl_owner);
834 	}
835 	else
836 	{
837 		printfPQExpBuffer(init_acl_subquery, "NULL");
838 		printfPQExpBuffer(init_racl_subquery, "NULL");
839 	}
840 }
841 
842 /*
843  * Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
844  *
845  * It'd be better if we could inquire this directly from the backend; but even
846  * if there were a function for that, it could only tell us about variables
847  * currently known to guc.c, so that it'd be unsafe for extensions to declare
848  * GUC_LIST_QUOTE variables anyway.  Lacking a solution for that, it doesn't
849  * seem worth the work to do more than have this list, which must be kept in
850  * sync with the variables actually marked GUC_LIST_QUOTE in guc.c.
851  */
852 bool
variable_is_guc_list_quote(const char * name)853 variable_is_guc_list_quote(const char *name)
854 {
855 	if (pg_strcasecmp(name, "temp_tablespaces") == 0 ||
856 		pg_strcasecmp(name, "session_preload_libraries") == 0 ||
857 		pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
858 		pg_strcasecmp(name, "local_preload_libraries") == 0 ||
859 		pg_strcasecmp(name, "search_path") == 0)
860 		return true;
861 	else
862 		return false;
863 }
864 
865 /*
866  * SplitGUCList --- parse a string containing identifiers or file names
867  *
868  * This is used to split the value of a GUC_LIST_QUOTE GUC variable, without
869  * presuming whether the elements will be taken as identifiers or file names.
870  * See comparable code in src/backend/utils/adt/varlena.c.
871  *
872  * Inputs:
873  *	rawstring: the input string; must be overwritable!	On return, it's
874  *			   been modified to contain the separated identifiers.
875  *	separator: the separator punctuation expected between identifiers
876  *			   (typically '.' or ',').  Whitespace may also appear around
877  *			   identifiers.
878  * Outputs:
879  *	namelist: receives a malloc'd, null-terminated array of pointers to
880  *			  identifiers within rawstring.  Caller should free this
881  *			  even on error return.
882  *
883  * Returns true if okay, false if there is a syntax error in the string.
884  */
885 bool
SplitGUCList(char * rawstring,char separator,char *** namelist)886 SplitGUCList(char *rawstring, char separator,
887 			 char ***namelist)
888 {
889 	char	   *nextp = rawstring;
890 	bool		done = false;
891 	char	  **nextptr;
892 
893 	/*
894 	 * Since we disallow empty identifiers, this is a conservative
895 	 * overestimate of the number of pointers we could need.  Allow one for
896 	 * list terminator.
897 	 */
898 	*namelist = nextptr = (char **)
899 		pg_malloc((strlen(rawstring) / 2 + 2) * sizeof(char *));
900 	*nextptr = NULL;
901 
902 	while (isspace((unsigned char) *nextp))
903 		nextp++;				/* skip leading whitespace */
904 
905 	if (*nextp == '\0')
906 		return true;			/* allow empty string */
907 
908 	/* At the top of the loop, we are at start of a new identifier. */
909 	do
910 	{
911 		char	   *curname;
912 		char	   *endp;
913 
914 		if (*nextp == '"')
915 		{
916 			/* Quoted name --- collapse quote-quote pairs */
917 			curname = nextp + 1;
918 			for (;;)
919 			{
920 				endp = strchr(nextp + 1, '"');
921 				if (endp == NULL)
922 					return false;	/* mismatched quotes */
923 				if (endp[1] != '"')
924 					break;		/* found end of quoted name */
925 				/* Collapse adjacent quotes into one quote, and look again */
926 				memmove(endp, endp + 1, strlen(endp));
927 				nextp = endp;
928 			}
929 			/* endp now points at the terminating quote */
930 			nextp = endp + 1;
931 		}
932 		else
933 		{
934 			/* Unquoted name --- extends to separator or whitespace */
935 			curname = nextp;
936 			while (*nextp && *nextp != separator &&
937 				   !isspace((unsigned char) *nextp))
938 				nextp++;
939 			endp = nextp;
940 			if (curname == nextp)
941 				return false;	/* empty unquoted name not allowed */
942 		}
943 
944 		while (isspace((unsigned char) *nextp))
945 			nextp++;			/* skip trailing whitespace */
946 
947 		if (*nextp == separator)
948 		{
949 			nextp++;
950 			while (isspace((unsigned char) *nextp))
951 				nextp++;		/* skip leading whitespace for next */
952 			/* we expect another name, so done remains false */
953 		}
954 		else if (*nextp == '\0')
955 			done = true;
956 		else
957 			return false;		/* invalid syntax */
958 
959 		/* Now safe to overwrite separator with a null */
960 		*endp = '\0';
961 
962 		/*
963 		 * Finished isolating current name --- add it to output array
964 		 */
965 		*nextptr++ = curname;
966 
967 		/* Loop back if we didn't reach end of string */
968 	} while (!done);
969 
970 	*nextptr = NULL;
971 	return true;
972 }
973