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