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