PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
user.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * user.c
4  * Commands for manipulating roles (formerly called users).
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * src/backend/commands/user.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "access/genam.h"
16 #include "access/heapam.h"
17 #include "access/htup_details.h"
18 #include "access/xact.h"
19 #include "catalog/binary_upgrade.h"
20 #include "catalog/catalog.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/objectaccess.h"
25 #include "catalog/pg_authid.h"
26 #include "catalog/pg_database.h"
28 #include "commands/comment.h"
29 #include "commands/dbcommands.h"
30 #include "commands/seclabel.h"
31 #include "commands/user.h"
32 #include "libpq/crypt.h"
33 #include "miscadmin.h"
34 #include "storage/lmgr.h"
35 #include "utils/acl.h"
36 #include "utils/builtins.h"
37 #include "utils/fmgroids.h"
38 #include "utils/syscache.h"
39 #include "utils/timestamp.h"
40 #include "utils/tqual.h"
41 
42 /* Potentially set by pg_upgrade_support functions */
44 
45 
46 /* GUC parameter */
48 
49 /* Hook to check passwords in CreateRole() and AlterRole() */
51 
52 static void AddRoleMems(const char *rolename, Oid roleid,
53  List *memberSpecs, List *memberIds,
54  Oid grantorId, bool admin_opt);
55 static void DelRoleMems(const char *rolename, Oid roleid,
56  List *memberSpecs, List *memberIds,
57  bool admin_opt);
58 
59 
60 /* Check if current user has createrole privileges */
61 static bool
63 {
65 }
66 
67 
68 /*
69  * CREATE ROLE
70  */
71 Oid
73 {
74  Relation pg_authid_rel;
75  TupleDesc pg_authid_dsc;
76  HeapTuple tuple;
77  Datum new_record[Natts_pg_authid];
78  bool new_record_nulls[Natts_pg_authid];
79  Oid roleid;
80  ListCell *item;
82  char *password = NULL; /* user password */
83  bool issuper = false; /* Make the user a superuser? */
84  bool inherit = true; /* Auto inherit privileges? */
85  bool createrole = false; /* Can this user create roles? */
86  bool createdb = false; /* Can the user create databases? */
87  bool canlogin = false; /* Can this user login? */
88  bool isreplication = false; /* Is this a replication role? */
89  bool bypassrls = false; /* Is this a row security enabled role? */
90  int connlimit = -1; /* maximum connections allowed */
91  List *addroleto = NIL; /* roles to make this a member of */
92  List *rolemembers = NIL; /* roles to be members of this role */
93  List *adminmembers = NIL; /* roles to be admins of this role */
94  char *validUntil = NULL; /* time the login is valid until */
95  Datum validUntil_datum; /* same, as timestamptz Datum */
96  bool validUntil_null;
97  DefElem *dpassword = NULL;
98  DefElem *dissuper = NULL;
99  DefElem *dinherit = NULL;
100  DefElem *dcreaterole = NULL;
101  DefElem *dcreatedb = NULL;
102  DefElem *dcanlogin = NULL;
103  DefElem *disreplication = NULL;
104  DefElem *dconnlimit = NULL;
105  DefElem *daddroleto = NULL;
106  DefElem *drolemembers = NULL;
107  DefElem *dadminmembers = NULL;
108  DefElem *dvalidUntil = NULL;
109  DefElem *dbypassRLS = NULL;
110 
111  /* The defaults can vary depending on the original statement type */
112  switch (stmt->stmt_type)
113  {
114  case ROLESTMT_ROLE:
115  break;
116  case ROLESTMT_USER:
117  canlogin = true;
118  /* may eventually want inherit to default to false here */
119  break;
120  case ROLESTMT_GROUP:
121  break;
122  }
123 
124  /* Extract options from the statement node tree */
125  foreach(option, stmt->options)
126  {
127  DefElem *defel = (DefElem *) lfirst(option);
128 
129  if (strcmp(defel->defname, "password") == 0)
130  {
131  if (dpassword)
132  ereport(ERROR,
133  (errcode(ERRCODE_SYNTAX_ERROR),
134  errmsg("conflicting or redundant options"),
135  parser_errposition(pstate, defel->location)));
136  dpassword = defel;
137  }
138  else if (strcmp(defel->defname, "sysid") == 0)
139  {
140  ereport(NOTICE,
141  (errmsg("SYSID can no longer be specified")));
142  }
143  else if (strcmp(defel->defname, "superuser") == 0)
144  {
145  if (dissuper)
146  ereport(ERROR,
147  (errcode(ERRCODE_SYNTAX_ERROR),
148  errmsg("conflicting or redundant options"),
149  parser_errposition(pstate, defel->location)));
150  dissuper = defel;
151  }
152  else if (strcmp(defel->defname, "inherit") == 0)
153  {
154  if (dinherit)
155  ereport(ERROR,
156  (errcode(ERRCODE_SYNTAX_ERROR),
157  errmsg("conflicting or redundant options"),
158  parser_errposition(pstate, defel->location)));
159  dinherit = defel;
160  }
161  else if (strcmp(defel->defname, "createrole") == 0)
162  {
163  if (dcreaterole)
164  ereport(ERROR,
165  (errcode(ERRCODE_SYNTAX_ERROR),
166  errmsg("conflicting or redundant options"),
167  parser_errposition(pstate, defel->location)));
168  dcreaterole = defel;
169  }
170  else if (strcmp(defel->defname, "createdb") == 0)
171  {
172  if (dcreatedb)
173  ereport(ERROR,
174  (errcode(ERRCODE_SYNTAX_ERROR),
175  errmsg("conflicting or redundant options"),
176  parser_errposition(pstate, defel->location)));
177  dcreatedb = defel;
178  }
179  else if (strcmp(defel->defname, "canlogin") == 0)
180  {
181  if (dcanlogin)
182  ereport(ERROR,
183  (errcode(ERRCODE_SYNTAX_ERROR),
184  errmsg("conflicting or redundant options"),
185  parser_errposition(pstate, defel->location)));
186  dcanlogin = defel;
187  }
188  else if (strcmp(defel->defname, "isreplication") == 0)
189  {
190  if (disreplication)
191  ereport(ERROR,
192  (errcode(ERRCODE_SYNTAX_ERROR),
193  errmsg("conflicting or redundant options"),
194  parser_errposition(pstate, defel->location)));
195  disreplication = defel;
196  }
197  else if (strcmp(defel->defname, "connectionlimit") == 0)
198  {
199  if (dconnlimit)
200  ereport(ERROR,
201  (errcode(ERRCODE_SYNTAX_ERROR),
202  errmsg("conflicting or redundant options"),
203  parser_errposition(pstate, defel->location)));
204  dconnlimit = defel;
205  }
206  else if (strcmp(defel->defname, "addroleto") == 0)
207  {
208  if (daddroleto)
209  ereport(ERROR,
210  (errcode(ERRCODE_SYNTAX_ERROR),
211  errmsg("conflicting or redundant options"),
212  parser_errposition(pstate, defel->location)));
213  daddroleto = defel;
214  }
215  else if (strcmp(defel->defname, "rolemembers") == 0)
216  {
217  if (drolemembers)
218  ereport(ERROR,
219  (errcode(ERRCODE_SYNTAX_ERROR),
220  errmsg("conflicting or redundant options"),
221  parser_errposition(pstate, defel->location)));
222  drolemembers = defel;
223  }
224  else if (strcmp(defel->defname, "adminmembers") == 0)
225  {
226  if (dadminmembers)
227  ereport(ERROR,
228  (errcode(ERRCODE_SYNTAX_ERROR),
229  errmsg("conflicting or redundant options"),
230  parser_errposition(pstate, defel->location)));
231  dadminmembers = defel;
232  }
233  else if (strcmp(defel->defname, "validUntil") == 0)
234  {
235  if (dvalidUntil)
236  ereport(ERROR,
237  (errcode(ERRCODE_SYNTAX_ERROR),
238  errmsg("conflicting or redundant options"),
239  parser_errposition(pstate, defel->location)));
240  dvalidUntil = defel;
241  }
242  else if (strcmp(defel->defname, "bypassrls") == 0)
243  {
244  if (dbypassRLS)
245  ereport(ERROR,
246  (errcode(ERRCODE_SYNTAX_ERROR),
247  errmsg("conflicting or redundant options"),
248  parser_errposition(pstate, defel->location)));
249  dbypassRLS = defel;
250  }
251  else
252  elog(ERROR, "option \"%s\" not recognized",
253  defel->defname);
254  }
255 
256  if (dpassword && dpassword->arg)
257  password = strVal(dpassword->arg);
258  if (dissuper)
259  issuper = intVal(dissuper->arg) != 0;
260  if (dinherit)
261  inherit = intVal(dinherit->arg) != 0;
262  if (dcreaterole)
263  createrole = intVal(dcreaterole->arg) != 0;
264  if (dcreatedb)
265  createdb = intVal(dcreatedb->arg) != 0;
266  if (dcanlogin)
267  canlogin = intVal(dcanlogin->arg) != 0;
268  if (disreplication)
269  isreplication = intVal(disreplication->arg) != 0;
270  if (dconnlimit)
271  {
272  connlimit = intVal(dconnlimit->arg);
273  if (connlimit < -1)
274  ereport(ERROR,
275  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
276  errmsg("invalid connection limit: %d", connlimit)));
277  }
278  if (daddroleto)
279  addroleto = (List *) daddroleto->arg;
280  if (drolemembers)
281  rolemembers = (List *) drolemembers->arg;
282  if (dadminmembers)
283  adminmembers = (List *) dadminmembers->arg;
284  if (dvalidUntil)
285  validUntil = strVal(dvalidUntil->arg);
286  if (dbypassRLS)
287  bypassrls = intVal(dbypassRLS->arg) != 0;
288 
289  /* Check some permissions first */
290  if (issuper)
291  {
292  if (!superuser())
293  ereport(ERROR,
294  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
295  errmsg("must be superuser to create superusers")));
296  }
297  else if (isreplication)
298  {
299  if (!superuser())
300  ereport(ERROR,
301  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
302  errmsg("must be superuser to create replication users")));
303  }
304  else if (bypassrls)
305  {
306  if (!superuser())
307  ereport(ERROR,
308  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
309  errmsg("must be superuser to change bypassrls attribute")));
310  }
311  else
312  {
314  ereport(ERROR,
315  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
316  errmsg("permission denied to create role")));
317  }
318 
319  /*
320  * Check that the user is not trying to create a role in the reserved
321  * "pg_" namespace.
322  */
323  if (IsReservedName(stmt->role))
324  ereport(ERROR,
325  (errcode(ERRCODE_RESERVED_NAME),
326  errmsg("role name \"%s\" is reserved",
327  stmt->role),
328  errdetail("Role names starting with \"pg_\" are reserved.")));
329 
330  /*
331  * Check the pg_authid relation to be certain the role doesn't already
332  * exist.
333  */
334  pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
335  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
336 
337  if (OidIsValid(get_role_oid(stmt->role, true)))
338  ereport(ERROR,
340  errmsg("role \"%s\" already exists",
341  stmt->role)));
342 
343  /* Convert validuntil to internal form */
344  if (validUntil)
345  {
346  validUntil_datum = DirectFunctionCall3(timestamptz_in,
347  CStringGetDatum(validUntil),
349  Int32GetDatum(-1));
350  validUntil_null = false;
351  }
352  else
353  {
354  validUntil_datum = (Datum) 0;
355  validUntil_null = true;
356  }
357 
358  /*
359  * Call the password checking hook if there is one defined
360  */
361  if (check_password_hook && password)
362  (*check_password_hook) (stmt->role,
363  password,
364  get_password_type(password),
365  validUntil_datum,
366  validUntil_null);
367 
368  /*
369  * Build a tuple to insert
370  */
371  MemSet(new_record, 0, sizeof(new_record));
372  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
373 
374  new_record[Anum_pg_authid_rolname - 1] =
376 
377  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
378  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
379  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
380  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
381  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
382  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
383  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
384 
385  if (password)
386  {
387  /* Encrypt the password to the requested format. */
388  char *shadow_pass;
389 
390  shadow_pass = encrypt_password(Password_encryption, stmt->role,
391  password);
392  new_record[Anum_pg_authid_rolpassword - 1] =
393  CStringGetTextDatum(shadow_pass);
394  }
395  else
396  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
397 
398  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
399  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
400 
401  new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
402 
403  tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
404 
405  /*
406  * pg_largeobject_metadata contains pg_authid.oid's, so we use the
407  * binary-upgrade override.
408  */
409  if (IsBinaryUpgrade)
410  {
412  ereport(ERROR,
413  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
414  errmsg("pg_authid OID value not set when in binary upgrade mode")));
415 
418  }
419 
420  /*
421  * Insert new record in the pg_authid table
422  */
423  roleid = CatalogTupleInsert(pg_authid_rel, tuple);
424 
425  /*
426  * Advance command counter so we can see new record; else tests in
427  * AddRoleMems may fail.
428  */
429  if (addroleto || adminmembers || rolemembers)
431 
432  /*
433  * Add the new role to the specified existing roles.
434  */
435  foreach(item, addroleto)
436  {
437  RoleSpec *oldrole = lfirst(item);
438  HeapTuple oldroletup = get_rolespec_tuple(oldrole);
439  Oid oldroleid = HeapTupleGetOid(oldroletup);
440  char *oldrolename = NameStr(((Form_pg_authid) GETSTRUCT(oldroletup))->rolname);
441 
442  AddRoleMems(oldrolename, oldroleid,
443  list_make1(makeString(stmt->role)),
444  list_make1_oid(roleid),
445  GetUserId(), false);
446 
447  ReleaseSysCache(oldroletup);
448  }
449 
450  /*
451  * Add the specified members to this new role. adminmembers get the admin
452  * option, rolemembers don't.
453  */
454  AddRoleMems(stmt->role, roleid,
455  adminmembers, roleSpecsToIds(adminmembers),
456  GetUserId(), true);
457  AddRoleMems(stmt->role, roleid,
458  rolemembers, roleSpecsToIds(rolemembers),
459  GetUserId(), false);
460 
461  /* Post creation hook for new role */
463 
464  /*
465  * Close pg_authid, but keep lock till commit.
466  */
467  heap_close(pg_authid_rel, NoLock);
468 
469  return roleid;
470 }
471 
472 
473 /*
474  * ALTER ROLE
475  *
476  * Note: the rolemembers option accepted here is intended to support the
477  * backwards-compatible ALTER GROUP syntax. Although it will work to say
478  * "ALTER ROLE role ROLE rolenames", we don't document it.
479  */
480 Oid
482 {
483  Datum new_record[Natts_pg_authid];
484  bool new_record_nulls[Natts_pg_authid];
485  bool new_record_repl[Natts_pg_authid];
486  Relation pg_authid_rel;
487  TupleDesc pg_authid_dsc;
488  HeapTuple tuple,
489  new_tuple;
490  Form_pg_authid authform;
491  ListCell *option;
492  char *rolename = NULL;
493  char *password = NULL; /* user password */
494  int issuper = -1; /* Make the user a superuser? */
495  int inherit = -1; /* Auto inherit privileges? */
496  int createrole = -1; /* Can this user create roles? */
497  int createdb = -1; /* Can the user create databases? */
498  int canlogin = -1; /* Can this user login? */
499  int isreplication = -1; /* Is this a replication role? */
500  int connlimit = -1; /* maximum connections allowed */
501  List *rolemembers = NIL; /* roles to be added/removed */
502  char *validUntil = NULL; /* time the login is valid until */
503  Datum validUntil_datum; /* same, as timestamptz Datum */
504  bool validUntil_null;
505  int bypassrls = -1;
506  DefElem *dpassword = NULL;
507  DefElem *dissuper = NULL;
508  DefElem *dinherit = NULL;
509  DefElem *dcreaterole = NULL;
510  DefElem *dcreatedb = NULL;
511  DefElem *dcanlogin = NULL;
512  DefElem *disreplication = NULL;
513  DefElem *dconnlimit = NULL;
514  DefElem *drolemembers = NULL;
515  DefElem *dvalidUntil = NULL;
516  DefElem *dbypassRLS = NULL;
517  Oid roleid;
518 
520  "Cannot alter reserved roles.");
521 
522  /* Extract options from the statement node tree */
523  foreach(option, stmt->options)
524  {
525  DefElem *defel = (DefElem *) lfirst(option);
526 
527  if (strcmp(defel->defname, "password") == 0)
528  {
529  if (dpassword)
530  ereport(ERROR,
531  (errcode(ERRCODE_SYNTAX_ERROR),
532  errmsg("conflicting or redundant options")));
533  dpassword = defel;
534  }
535  else if (strcmp(defel->defname, "superuser") == 0)
536  {
537  if (dissuper)
538  ereport(ERROR,
539  (errcode(ERRCODE_SYNTAX_ERROR),
540  errmsg("conflicting or redundant options")));
541  dissuper = defel;
542  }
543  else if (strcmp(defel->defname, "inherit") == 0)
544  {
545  if (dinherit)
546  ereport(ERROR,
547  (errcode(ERRCODE_SYNTAX_ERROR),
548  errmsg("conflicting or redundant options")));
549  dinherit = defel;
550  }
551  else if (strcmp(defel->defname, "createrole") == 0)
552  {
553  if (dcreaterole)
554  ereport(ERROR,
555  (errcode(ERRCODE_SYNTAX_ERROR),
556  errmsg("conflicting or redundant options")));
557  dcreaterole = defel;
558  }
559  else if (strcmp(defel->defname, "createdb") == 0)
560  {
561  if (dcreatedb)
562  ereport(ERROR,
563  (errcode(ERRCODE_SYNTAX_ERROR),
564  errmsg("conflicting or redundant options")));
565  dcreatedb = defel;
566  }
567  else if (strcmp(defel->defname, "canlogin") == 0)
568  {
569  if (dcanlogin)
570  ereport(ERROR,
571  (errcode(ERRCODE_SYNTAX_ERROR),
572  errmsg("conflicting or redundant options")));
573  dcanlogin = defel;
574  }
575  else if (strcmp(defel->defname, "isreplication") == 0)
576  {
577  if (disreplication)
578  ereport(ERROR,
579  (errcode(ERRCODE_SYNTAX_ERROR),
580  errmsg("conflicting or redundant options")));
581  disreplication = defel;
582  }
583  else if (strcmp(defel->defname, "connectionlimit") == 0)
584  {
585  if (dconnlimit)
586  ereport(ERROR,
587  (errcode(ERRCODE_SYNTAX_ERROR),
588  errmsg("conflicting or redundant options")));
589  dconnlimit = defel;
590  }
591  else if (strcmp(defel->defname, "rolemembers") == 0 &&
592  stmt->action != 0)
593  {
594  if (drolemembers)
595  ereport(ERROR,
596  (errcode(ERRCODE_SYNTAX_ERROR),
597  errmsg("conflicting or redundant options")));
598  drolemembers = defel;
599  }
600  else if (strcmp(defel->defname, "validUntil") == 0)
601  {
602  if (dvalidUntil)
603  ereport(ERROR,
604  (errcode(ERRCODE_SYNTAX_ERROR),
605  errmsg("conflicting or redundant options")));
606  dvalidUntil = defel;
607  }
608  else if (strcmp(defel->defname, "bypassrls") == 0)
609  {
610  if (dbypassRLS)
611  ereport(ERROR,
612  (errcode(ERRCODE_SYNTAX_ERROR),
613  errmsg("conflicting or redundant options")));
614  dbypassRLS = defel;
615  }
616  else
617  elog(ERROR, "option \"%s\" not recognized",
618  defel->defname);
619  }
620 
621  if (dpassword && dpassword->arg)
622  password = strVal(dpassword->arg);
623  if (dissuper)
624  issuper = intVal(dissuper->arg);
625  if (dinherit)
626  inherit = intVal(dinherit->arg);
627  if (dcreaterole)
628  createrole = intVal(dcreaterole->arg);
629  if (dcreatedb)
630  createdb = intVal(dcreatedb->arg);
631  if (dcanlogin)
632  canlogin = intVal(dcanlogin->arg);
633  if (disreplication)
634  isreplication = intVal(disreplication->arg);
635  if (dconnlimit)
636  {
637  connlimit = intVal(dconnlimit->arg);
638  if (connlimit < -1)
639  ereport(ERROR,
640  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
641  errmsg("invalid connection limit: %d", connlimit)));
642  }
643  if (drolemembers)
644  rolemembers = (List *) drolemembers->arg;
645  if (dvalidUntil)
646  validUntil = strVal(dvalidUntil->arg);
647  if (dbypassRLS)
648  bypassrls = intVal(dbypassRLS->arg);
649 
650  /*
651  * Scan the pg_authid relation to be certain the user exists.
652  */
653  pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
654  pg_authid_dsc = RelationGetDescr(pg_authid_rel);
655 
656  tuple = get_rolespec_tuple(stmt->role);
657  authform = (Form_pg_authid) GETSTRUCT(tuple);
658  rolename = pstrdup(NameStr(authform->rolname));
659  roleid = HeapTupleGetOid(tuple);
660 
661  /*
662  * To mess with a superuser you gotta be superuser; else you need
663  * createrole, or just want to change your own password
664  */
665  if (authform->rolsuper || issuper >= 0)
666  {
667  if (!superuser())
668  ereport(ERROR,
669  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
670  errmsg("must be superuser to alter superusers")));
671  }
672  else if (authform->rolreplication || isreplication >= 0)
673  {
674  if (!superuser())
675  ereport(ERROR,
676  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
677  errmsg("must be superuser to alter replication users")));
678  }
679  else if (authform->rolbypassrls || bypassrls >= 0)
680  {
681  if (!superuser())
682  ereport(ERROR,
683  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
684  errmsg("must be superuser to change bypassrls attribute")));
685  }
686  else if (!have_createrole_privilege())
687  {
688  if (!(inherit < 0 &&
689  createrole < 0 &&
690  createdb < 0 &&
691  canlogin < 0 &&
692  isreplication < 0 &&
693  !dconnlimit &&
694  !rolemembers &&
695  !validUntil &&
696  dpassword &&
697  roleid == GetUserId()))
698  ereport(ERROR,
699  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
700  errmsg("permission denied")));
701  }
702 
703  /* Convert validuntil to internal form */
704  if (validUntil)
705  {
706  validUntil_datum = DirectFunctionCall3(timestamptz_in,
707  CStringGetDatum(validUntil),
709  Int32GetDatum(-1));
710  validUntil_null = false;
711  }
712  else
713  {
714  /* fetch existing setting in case hook needs it */
715  validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
717  &validUntil_null);
718  }
719 
720  /*
721  * Call the password checking hook if there is one defined
722  */
723  if (check_password_hook && password)
724  (*check_password_hook) (rolename,
725  password,
726  get_password_type(password),
727  validUntil_datum,
728  validUntil_null);
729 
730  /*
731  * Build an updated tuple, perusing the information just obtained
732  */
733  MemSet(new_record, 0, sizeof(new_record));
734  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
735  MemSet(new_record_repl, false, sizeof(new_record_repl));
736 
737  /*
738  * issuper/createrole/etc
739  */
740  if (issuper >= 0)
741  {
742  new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
743  new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
744  }
745 
746  if (inherit >= 0)
747  {
748  new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
749  new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
750  }
751 
752  if (createrole >= 0)
753  {
754  new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
755  new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
756  }
757 
758  if (createdb >= 0)
759  {
760  new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
761  new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
762  }
763 
764  if (canlogin >= 0)
765  {
766  new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
767  new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
768  }
769 
770  if (isreplication >= 0)
771  {
772  new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
773  new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
774  }
775 
776  if (dconnlimit)
777  {
778  new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
779  new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
780  }
781 
782  /* password */
783  if (password)
784  {
785  /* Encrypt the password to the requested format. */
786  char *shadow_pass;
787 
788  shadow_pass = encrypt_password(Password_encryption, rolename,
789  password);
790  new_record[Anum_pg_authid_rolpassword - 1] =
791  CStringGetTextDatum(shadow_pass);
792  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
793  }
794 
795  /* unset password */
796  if (dpassword && dpassword->arg == NULL)
797  {
798  new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
799  new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
800  }
801 
802  /* valid until */
803  new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
804  new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
805  new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
806 
807  if (bypassrls >= 0)
808  {
809  new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls > 0);
810  new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
811  }
812 
813  new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
814  new_record_nulls, new_record_repl);
815  CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple);
816 
818 
819  ReleaseSysCache(tuple);
820  heap_freetuple(new_tuple);
821 
822  /*
823  * Advance command counter so we can see new record; else tests in
824  * AddRoleMems may fail.
825  */
826  if (rolemembers)
828 
829  if (stmt->action == +1) /* add members to role */
830  AddRoleMems(rolename, roleid,
831  rolemembers, roleSpecsToIds(rolemembers),
832  GetUserId(), false);
833  else if (stmt->action == -1) /* drop members from role */
834  DelRoleMems(rolename, roleid,
835  rolemembers, roleSpecsToIds(rolemembers),
836  false);
837 
838  /*
839  * Close pg_authid, but keep lock till commit.
840  */
841  heap_close(pg_authid_rel, NoLock);
842 
843  return roleid;
844 }
845 
846 
847 /*
848  * ALTER ROLE ... SET
849  */
850 Oid
852 {
853  HeapTuple roletuple;
854  Oid databaseid = InvalidOid;
855  Oid roleid = InvalidOid;
856 
857  if (stmt->role)
858  {
860  "Cannot alter reserved roles.");
861 
862  roletuple = get_rolespec_tuple(stmt->role);
863  roleid = HeapTupleGetOid(roletuple);
864 
865  /*
866  * Obtain a lock on the role and make sure it didn't go away in the
867  * meantime.
868  */
870 
871  /*
872  * To mess with a superuser you gotta be superuser; else you need
873  * createrole, or just want to change your own settings
874  */
875  if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
876  {
877  if (!superuser())
878  ereport(ERROR,
879  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
880  errmsg("must be superuser to alter superusers")));
881  }
882  else
883  {
884  if (!have_createrole_privilege() &&
885  HeapTupleGetOid(roletuple) != GetUserId())
886  ereport(ERROR,
887  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
888  errmsg("permission denied")));
889  }
890 
891  ReleaseSysCache(roletuple);
892  }
893 
894  /* look up and lock the database, if specified */
895  if (stmt->database != NULL)
896  {
897  databaseid = get_database_oid(stmt->database, false);
899 
900  if (!stmt->role)
901  {
902  /*
903  * If no role is specified, then this is effectively the same as
904  * ALTER DATABASE ... SET, so use the same permission check.
905  */
906  if (!pg_database_ownercheck(databaseid, GetUserId()))
908  stmt->database);
909  }
910  }
911 
912  if (!stmt->role && !stmt->database)
913  {
914  /* Must be superuser to alter settings globally. */
915  if (!superuser())
916  ereport(ERROR,
917  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
918  errmsg("must be superuser to alter settings globally")));
919  }
920 
921  AlterSetting(databaseid, roleid, stmt->setstmt);
922 
923  return roleid;
924 }
925 
926 
927 /*
928  * DROP ROLE
929  */
930 void
932 {
933  Relation pg_authid_rel,
934  pg_auth_members_rel;
935  ListCell *item;
936 
938  ereport(ERROR,
939  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
940  errmsg("permission denied to drop role")));
941 
942  /*
943  * Scan the pg_authid relation to find the Oid of the role(s) to be
944  * deleted.
945  */
946  pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
947  pg_auth_members_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
948 
949  foreach(item, stmt->roles)
950  {
951  RoleSpec *rolspec = lfirst(item);
952  char *role;
953  HeapTuple tuple,
954  tmp_tuple;
955  ScanKeyData scankey;
956  char *detail;
957  char *detail_log;
958  SysScanDesc sscan;
959  Oid roleid;
960 
961  if (rolspec->roletype != ROLESPEC_CSTRING)
962  ereport(ERROR,
963  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
964  errmsg("cannot use special role specifier in DROP ROLE")));
965  role = rolspec->rolename;
966 
967  tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
968  if (!HeapTupleIsValid(tuple))
969  {
970  if (!stmt->missing_ok)
971  {
972  ereport(ERROR,
973  (errcode(ERRCODE_UNDEFINED_OBJECT),
974  errmsg("role \"%s\" does not exist", role)));
975  }
976  else
977  {
978  ereport(NOTICE,
979  (errmsg("role \"%s\" does not exist, skipping",
980  role)));
981  }
982 
983  continue;
984  }
985 
986  roleid = HeapTupleGetOid(tuple);
987 
988  if (roleid == GetUserId())
989  ereport(ERROR,
990  (errcode(ERRCODE_OBJECT_IN_USE),
991  errmsg("current user cannot be dropped")));
992  if (roleid == GetOuterUserId())
993  ereport(ERROR,
994  (errcode(ERRCODE_OBJECT_IN_USE),
995  errmsg("current user cannot be dropped")));
996  if (roleid == GetSessionUserId())
997  ereport(ERROR,
998  (errcode(ERRCODE_OBJECT_IN_USE),
999  errmsg("session user cannot be dropped")));
1000 
1001  /*
1002  * For safety's sake, we allow createrole holders to drop ordinary
1003  * roles but not superuser roles. This is mainly to avoid the
1004  * scenario where you accidentally drop the last superuser.
1005  */
1006  if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
1007  !superuser())
1008  ereport(ERROR,
1009  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1010  errmsg("must be superuser to drop superusers")));
1011 
1012  /* DROP hook for the role being removed */
1014 
1015  /*
1016  * Lock the role, so nobody can add dependencies to her while we drop
1017  * her. We keep the lock until the end of transaction.
1018  */
1020 
1021  /* Check for pg_shdepend entries depending on this role */
1023  &detail, &detail_log))
1024  ereport(ERROR,
1025  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1026  errmsg("role \"%s\" cannot be dropped because some objects depend on it",
1027  role),
1028  errdetail_internal("%s", detail),
1029  errdetail_log("%s", detail_log)));
1030 
1031  /*
1032  * Remove the role from the pg_authid table
1033  */
1034  CatalogTupleDelete(pg_authid_rel, &tuple->t_self);
1035 
1036  ReleaseSysCache(tuple);
1037 
1038  /*
1039  * Remove role from the pg_auth_members table. We have to remove all
1040  * tuples that show it as either a role or a member.
1041  *
1042  * XXX what about grantor entries? Maybe we should do one heap scan.
1043  */
1044  ScanKeyInit(&scankey,
1046  BTEqualStrategyNumber, F_OIDEQ,
1047  ObjectIdGetDatum(roleid));
1048 
1049  sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
1050  true, NULL, 1, &scankey);
1051 
1052  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1053  {
1054  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1055  }
1056 
1057  systable_endscan(sscan);
1058 
1059  ScanKeyInit(&scankey,
1061  BTEqualStrategyNumber, F_OIDEQ,
1062  ObjectIdGetDatum(roleid));
1063 
1064  sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
1065  true, NULL, 1, &scankey);
1066 
1067  while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
1068  {
1069  CatalogTupleDelete(pg_auth_members_rel, &tmp_tuple->t_self);
1070  }
1071 
1072  systable_endscan(sscan);
1073 
1074  /*
1075  * Remove any comments or security labels on this role.
1076  */
1079 
1080  /*
1081  * Remove settings for this role.
1082  */
1083  DropSetting(InvalidOid, roleid);
1084 
1085  /*
1086  * Advance command counter so that later iterations of this loop will
1087  * see the changes already made. This is essential if, for example,
1088  * we are trying to drop both a role and one of its direct members ---
1089  * we'll get an error if we try to delete the linking pg_auth_members
1090  * tuple twice. (We do not need a CCI between the two delete loops
1091  * above, because it's not allowed for a role to directly contain
1092  * itself.)
1093  */
1095  }
1096 
1097  /*
1098  * Now we can clean up; but keep locks until commit.
1099  */
1100  heap_close(pg_auth_members_rel, NoLock);
1101  heap_close(pg_authid_rel, NoLock);
1102 }
1103 
1104 /*
1105  * Rename role
1106  */
1108 RenameRole(const char *oldname, const char *newname)
1109 {
1110  HeapTuple oldtuple,
1111  newtuple;
1112  TupleDesc dsc;
1113  Relation rel;
1114  Datum datum;
1115  bool isnull;
1116  Datum repl_val[Natts_pg_authid];
1117  bool repl_null[Natts_pg_authid];
1118  bool repl_repl[Natts_pg_authid];
1119  int i;
1120  Oid roleid;
1121  ObjectAddress address;
1122  Form_pg_authid authform;
1123 
1125  dsc = RelationGetDescr(rel);
1126 
1127  oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
1128  if (!HeapTupleIsValid(oldtuple))
1129  ereport(ERROR,
1130  (errcode(ERRCODE_UNDEFINED_OBJECT),
1131  errmsg("role \"%s\" does not exist", oldname)));
1132 
1133  /*
1134  * XXX Client applications probably store the session user somewhere, so
1135  * renaming it could cause confusion. On the other hand, there may not be
1136  * an actual problem besides a little confusion, so think about this and
1137  * decide. Same for SET ROLE ... we don't restrict renaming the current
1138  * effective userid, though.
1139  */
1140 
1141  roleid = HeapTupleGetOid(oldtuple);
1142  authform = (Form_pg_authid) GETSTRUCT(oldtuple);
1143 
1144  if (roleid == GetSessionUserId())
1145  ereport(ERROR,
1146  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1147  errmsg("session user cannot be renamed")));
1148  if (roleid == GetOuterUserId())
1149  ereport(ERROR,
1150  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1151  errmsg("current user cannot be renamed")));
1152 
1153  /*
1154  * Check that the user is not trying to rename a system role and not
1155  * trying to rename a role into the reserved "pg_" namespace.
1156  */
1157  if (IsReservedName(NameStr(authform->rolname)))
1158  ereport(ERROR,
1159  (errcode(ERRCODE_RESERVED_NAME),
1160  errmsg("role name \"%s\" is reserved",
1161  NameStr(authform->rolname)),
1162  errdetail("Role names starting with \"pg_\" are reserved.")));
1163 
1164  if (IsReservedName(newname))
1165  ereport(ERROR,
1166  (errcode(ERRCODE_RESERVED_NAME),
1167  errmsg("role name \"%s\" is reserved",
1168  newname),
1169  errdetail("Role names starting with \"pg_\" are reserved.")));
1170 
1171  /* make sure the new name doesn't exist */
1173  ereport(ERROR,
1175  errmsg("role \"%s\" already exists", newname)));
1176 
1177  /*
1178  * createrole is enough privilege unless you want to mess with a superuser
1179  */
1180  if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
1181  {
1182  if (!superuser())
1183  ereport(ERROR,
1184  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1185  errmsg("must be superuser to rename superusers")));
1186  }
1187  else
1188  {
1190  ereport(ERROR,
1191  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1192  errmsg("permission denied to rename role")));
1193  }
1194 
1195  /* OK, construct the modified tuple */
1196  for (i = 0; i < Natts_pg_authid; i++)
1197  repl_repl[i] = false;
1198 
1199  repl_repl[Anum_pg_authid_rolname - 1] = true;
1201  CStringGetDatum(newname));
1202  repl_null[Anum_pg_authid_rolname - 1] = false;
1203 
1204  datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);
1205 
1206  if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5)
1207  {
1208  /* MD5 uses the username as salt, so just clear it on a rename */
1209  repl_repl[Anum_pg_authid_rolpassword - 1] = true;
1210  repl_null[Anum_pg_authid_rolpassword - 1] = true;
1211 
1212  ereport(NOTICE,
1213  (errmsg("MD5 password cleared because of role rename")));
1214  }
1215 
1216  newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
1217  CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple);
1218 
1220 
1221  ObjectAddressSet(address, AuthIdRelationId, roleid);
1222 
1223  ReleaseSysCache(oldtuple);
1224 
1225  /*
1226  * Close pg_authid, but keep lock till commit.
1227  */
1228  heap_close(rel, NoLock);
1229 
1230  return address;
1231 }
1232 
1233 /*
1234  * GrantRoleStmt
1235  *
1236  * Grant/Revoke roles to/from roles
1237  */
1238 void
1240 {
1241  Relation pg_authid_rel;
1242  Oid grantor;
1243  List *grantee_ids;
1244  ListCell *item;
1245 
1246  if (stmt->grantor)
1247  grantor = get_rolespec_oid(stmt->grantor, false);
1248  else
1249  grantor = GetUserId();
1250 
1251  grantee_ids = roleSpecsToIds(stmt->grantee_roles);
1252 
1253  /* AccessShareLock is enough since we aren't modifying pg_authid */
1254  pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
1255 
1256  /*
1257  * Step through all of the granted roles and add/remove entries for the
1258  * grantees, or, if admin_opt is set, then just add/remove the admin
1259  * option.
1260  *
1261  * Note: Permissions checking is done by AddRoleMems/DelRoleMems
1262  */
1263  foreach(item, stmt->granted_roles)
1264  {
1265  AccessPriv *priv = (AccessPriv *) lfirst(item);
1266  char *rolename = priv->priv_name;
1267  Oid roleid;
1268 
1269  /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
1270  if (rolename == NULL || priv->cols != NIL)
1271  ereport(ERROR,
1272  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1273  errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
1274 
1275  roleid = get_role_oid(rolename, false);
1276  if (stmt->is_grant)
1277  AddRoleMems(rolename, roleid,
1278  stmt->grantee_roles, grantee_ids,
1279  grantor, stmt->admin_opt);
1280  else
1281  DelRoleMems(rolename, roleid,
1282  stmt->grantee_roles, grantee_ids,
1283  stmt->admin_opt);
1284  }
1285 
1286  /*
1287  * Close pg_authid, but keep lock till commit.
1288  */
1289  heap_close(pg_authid_rel, NoLock);
1290 }
1291 
1292 /*
1293  * DropOwnedObjects
1294  *
1295  * Drop the objects owned by a given list of roles.
1296  */
1297 void
1299 {
1300  List *role_ids = roleSpecsToIds(stmt->roles);
1301  ListCell *cell;
1302 
1303  /* Check privileges */
1304  foreach(cell, role_ids)
1305  {
1306  Oid roleid = lfirst_oid(cell);
1307 
1308  if (!has_privs_of_role(GetUserId(), roleid))
1309  ereport(ERROR,
1310  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1311  errmsg("permission denied to drop objects")));
1312  }
1313 
1314  /* Ok, do it */
1315  shdepDropOwned(role_ids, stmt->behavior);
1316 }
1317 
1318 /*
1319  * ReassignOwnedObjects
1320  *
1321  * Give the objects owned by a given list of roles away to another user.
1322  */
1323 void
1325 {
1326  List *role_ids = roleSpecsToIds(stmt->roles);
1327  ListCell *cell;
1328  Oid newrole;
1329 
1330  /* Check privileges */
1331  foreach(cell, role_ids)
1332  {
1333  Oid roleid = lfirst_oid(cell);
1334 
1335  if (!has_privs_of_role(GetUserId(), roleid))
1336  ereport(ERROR,
1337  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1338  errmsg("permission denied to reassign objects")));
1339  }
1340 
1341  /* Must have privileges on the receiving side too */
1342  newrole = get_rolespec_oid(stmt->newrole, false);
1343 
1344  if (!has_privs_of_role(GetUserId(), newrole))
1345  ereport(ERROR,
1346  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1347  errmsg("permission denied to reassign objects")));
1348 
1349  /* Ok, do it */
1350  shdepReassignOwned(role_ids, newrole);
1351 }
1352 
1353 /*
1354  * roleSpecsToIds
1355  *
1356  * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
1357  *
1358  * ROLESPEC_PUBLIC is not allowed.
1359  */
1360 List *
1361 roleSpecsToIds(List *memberNames)
1362 {
1363  List *result = NIL;
1364  ListCell *l;
1365 
1366  foreach(l, memberNames)
1367  {
1368  RoleSpec *rolespec = lfirst_node(RoleSpec, l);
1369  Oid roleid;
1370 
1371  roleid = get_rolespec_oid(rolespec, false);
1372  result = lappend_oid(result, roleid);
1373  }
1374  return result;
1375 }
1376 
1377 /*
1378  * AddRoleMems -- Add given members to the specified role
1379  *
1380  * rolename: name of role to add to (used only for error messages)
1381  * roleid: OID of role to add to
1382  * memberSpecs: list of RoleSpec of roles to add (used only for error messages)
1383  * memberIds: OIDs of roles to add
1384  * grantorId: who is granting the membership
1385  * admin_opt: granting admin option?
1386  *
1387  * Note: caller is responsible for calling auth_file_update_needed().
1388  */
1389 static void
1390 AddRoleMems(const char *rolename, Oid roleid,
1391  List *memberSpecs, List *memberIds,
1392  Oid grantorId, bool admin_opt)
1393 {
1394  Relation pg_authmem_rel;
1395  TupleDesc pg_authmem_dsc;
1396  ListCell *specitem;
1397  ListCell *iditem;
1398 
1399  Assert(list_length(memberSpecs) == list_length(memberIds));
1400 
1401  /* Skip permission check if nothing to do */
1402  if (!memberIds)
1403  return;
1404 
1405  /*
1406  * Check permissions: must have createrole or admin option on the role to
1407  * be changed. To mess with a superuser role, you gotta be superuser.
1408  */
1409  if (superuser_arg(roleid))
1410  {
1411  if (!superuser())
1412  ereport(ERROR,
1413  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1414  errmsg("must be superuser to alter superusers")));
1415  }
1416  else
1417  {
1418  if (!have_createrole_privilege() &&
1419  !is_admin_of_role(grantorId, roleid))
1420  ereport(ERROR,
1421  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1422  errmsg("must have admin option on role \"%s\"",
1423  rolename)));
1424  }
1425 
1426  /*
1427  * The role membership grantor of record has little significance at
1428  * present. Nonetheless, inasmuch as users might look to it for a crude
1429  * audit trail, let only superusers impute the grant to a third party.
1430  *
1431  * Before lifting this restriction, give the member == role case of
1432  * is_admin_of_role() a fresh look. Ensure that the current role cannot
1433  * use an explicit grantor specification to take advantage of the session
1434  * user's self-admin right.
1435  */
1436  if (grantorId != GetUserId() && !superuser())
1437  ereport(ERROR,
1438  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1439  errmsg("must be superuser to set grantor")));
1440 
1441  pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1442  pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1443 
1444  forboth(specitem, memberSpecs, iditem, memberIds)
1445  {
1446  RoleSpec *memberRole = lfirst(specitem);
1447  Oid memberid = lfirst_oid(iditem);
1448  HeapTuple authmem_tuple;
1449  HeapTuple tuple;
1450  Datum new_record[Natts_pg_auth_members];
1451  bool new_record_nulls[Natts_pg_auth_members];
1452  bool new_record_repl[Natts_pg_auth_members];
1453 
1454  /*
1455  * Refuse creation of membership loops, including the trivial case
1456  * where a role is made a member of itself. We do this by checking to
1457  * see if the target role is already a member of the proposed member
1458  * role. We have to ignore possible superuserness, however, else we
1459  * could never grant membership in a superuser-privileged role.
1460  */
1461  if (is_member_of_role_nosuper(roleid, memberid))
1462  ereport(ERROR,
1463  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1464  (errmsg("role \"%s\" is a member of role \"%s\"",
1465  rolename, get_rolespec_name(memberRole)))));
1466 
1467  /*
1468  * Check if entry for this role/member already exists; if so, give
1469  * warning unless we are adding admin option.
1470  */
1471  authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1472  ObjectIdGetDatum(roleid),
1473  ObjectIdGetDatum(memberid));
1474  if (HeapTupleIsValid(authmem_tuple) &&
1475  (!admin_opt ||
1476  ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option))
1477  {
1478  ereport(NOTICE,
1479  (errmsg("role \"%s\" is already a member of role \"%s\"",
1480  get_rolespec_name(memberRole), rolename)));
1481  ReleaseSysCache(authmem_tuple);
1482  continue;
1483  }
1484 
1485  /* Build a tuple to insert or update */
1486  MemSet(new_record, 0, sizeof(new_record));
1487  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1488  MemSet(new_record_repl, false, sizeof(new_record_repl));
1489 
1490  new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
1491  new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
1492  new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
1493  new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);
1494 
1495  if (HeapTupleIsValid(authmem_tuple))
1496  {
1497  new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
1498  new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1499  tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1500  new_record,
1501  new_record_nulls, new_record_repl);
1502  CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1503  ReleaseSysCache(authmem_tuple);
1504  }
1505  else
1506  {
1507  tuple = heap_form_tuple(pg_authmem_dsc,
1508  new_record, new_record_nulls);
1509  CatalogTupleInsert(pg_authmem_rel, tuple);
1510  }
1511 
1512  /* CCI after each change, in case there are duplicates in list */
1514  }
1515 
1516  /*
1517  * Close pg_authmem, but keep lock till commit.
1518  */
1519  heap_close(pg_authmem_rel, NoLock);
1520 }
1521 
1522 /*
1523  * DelRoleMems -- Remove given members from the specified role
1524  *
1525  * rolename: name of role to del from (used only for error messages)
1526  * roleid: OID of role to del from
1527  * memberSpecs: list of RoleSpec of roles to del (used only for error messages)
1528  * memberIds: OIDs of roles to del
1529  * admin_opt: remove admin option only?
1530  *
1531  * Note: caller is responsible for calling auth_file_update_needed().
1532  */
1533 static void
1534 DelRoleMems(const char *rolename, Oid roleid,
1535  List *memberSpecs, List *memberIds,
1536  bool admin_opt)
1537 {
1538  Relation pg_authmem_rel;
1539  TupleDesc pg_authmem_dsc;
1540  ListCell *specitem;
1541  ListCell *iditem;
1542 
1543  Assert(list_length(memberSpecs) == list_length(memberIds));
1544 
1545  /* Skip permission check if nothing to do */
1546  if (!memberIds)
1547  return;
1548 
1549  /*
1550  * Check permissions: must have createrole or admin option on the role to
1551  * be changed. To mess with a superuser role, you gotta be superuser.
1552  */
1553  if (superuser_arg(roleid))
1554  {
1555  if (!superuser())
1556  ereport(ERROR,
1557  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1558  errmsg("must be superuser to alter superusers")));
1559  }
1560  else
1561  {
1562  if (!have_createrole_privilege() &&
1563  !is_admin_of_role(GetUserId(), roleid))
1564  ereport(ERROR,
1565  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1566  errmsg("must have admin option on role \"%s\"",
1567  rolename)));
1568  }
1569 
1570  pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
1571  pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);
1572 
1573  forboth(specitem, memberSpecs, iditem, memberIds)
1574  {
1575  RoleSpec *memberRole = lfirst(specitem);
1576  Oid memberid = lfirst_oid(iditem);
1577  HeapTuple authmem_tuple;
1578 
1579  /*
1580  * Find entry for this role/member
1581  */
1582  authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
1583  ObjectIdGetDatum(roleid),
1584  ObjectIdGetDatum(memberid));
1585  if (!HeapTupleIsValid(authmem_tuple))
1586  {
1587  ereport(WARNING,
1588  (errmsg("role \"%s\" is not a member of role \"%s\"",
1589  get_rolespec_name(memberRole), rolename)));
1590  continue;
1591  }
1592 
1593  if (!admin_opt)
1594  {
1595  /* Remove the entry altogether */
1596  CatalogTupleDelete(pg_authmem_rel, &authmem_tuple->t_self);
1597  }
1598  else
1599  {
1600  /* Just turn off the admin option */
1601  HeapTuple tuple;
1602  Datum new_record[Natts_pg_auth_members];
1603  bool new_record_nulls[Natts_pg_auth_members];
1604  bool new_record_repl[Natts_pg_auth_members];
1605 
1606  /* Build a tuple to update with */
1607  MemSet(new_record, 0, sizeof(new_record));
1608  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
1609  MemSet(new_record_repl, false, sizeof(new_record_repl));
1610 
1611  new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
1612  new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
1613 
1614  tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
1615  new_record,
1616  new_record_nulls, new_record_repl);
1617  CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple);
1618  }
1619 
1620  ReleaseSysCache(authmem_tuple);
1621 
1622  /* CCI after each change, in case there are duplicates in list */
1624  }
1625 
1626  /*
1627  * Close pg_authmem, but keep lock till commit.
1628  */
1629  heap_close(pg_authmem_rel, NoLock);
1630 }
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:5171
Value * makeString(char *str)
Definition: value.c:53
#define NIL
Definition: pg_list.h:69
static char password[100]
Definition: streamutil.c:41
RoleSpec * role
Definition: parsenodes.h:2426
void shdepDropOwned(List *roleids, DropBehavior behavior)
Definition: pg_shdepend.c:1163
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid binary_upgrade_next_pg_authid_oid
Definition: user.c:43
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define RelationGetDescr(relation)
Definition: rel.h:428
Oid GetUserId(void)
Definition: miscinit.c:283
int Password_encryption
Definition: user.c:47
#define PointerGetDatum(X)
Definition: postgres.h:562
#define AuthMemRelationId
RoleStmtType stmt_type
Definition: parsenodes.h:2418
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define DatabaseRelationId
Definition: pg_database.h:29
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:99
void DropOwnedObjects(DropOwnedStmt *stmt)
Definition: user.c:1298
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4813
void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
#define InvokeObjectDropHook(classId, objectId, subId)
Definition: objectaccess.h:154
bool is_admin_of_role(Oid member, Oid role)
Definition: acl.c:4895
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define MemSet(start, val, len)
Definition: c.h:857
#define Anum_pg_authid_rolpassword
Definition: pg_authid.h:88
List * granted_roles
Definition: parsenodes.h:1896
return result
Definition: formatting.c:1633
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
RoleSpec * role
Definition: parsenodes.h:2434
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define Anum_pg_authid_rolreplication
Definition: pg_authid.h:85
List * roles
Definition: parsenodes.h:2442
#define heap_close(r, l)
Definition: heapam.h:97
List * cols
Definition: parsenodes.h:1881
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:584
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
bool IsReservedName(const char *name)
Definition: catalog.c:194
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:538
Oid GetSessionUserId(void)
Definition: miscinit.c:317
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
bool IsBinaryUpgrade
Definition: globals.c:102
Oid CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
Definition: user.c:72
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5096
#define AuthIdRelationId
Definition: pg_authid.h:42
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
#define Natts_pg_auth_members
#define list_make1(x1)
Definition: pg_list.h:139
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:72
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:174
Oid GetOuterUserId(void)
Definition: miscinit.c:294
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
void GrantRole(GrantRoleStmt *stmt)
Definition: user.c:1239
#define Anum_pg_authid_rolvaliduntil
Definition: pg_authid.h:89
static void AddRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, Oid grantorId, bool admin_opt)
Definition: user.c:1390
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:987
ItemPointerData t_self
Definition: htup.h:65
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NoLock
Definition: lockdefs.h:34
void shdepReassignOwned(List *roleids, Oid newrole)
Definition: pg_shdepend.c:1285
#define Anum_pg_authid_rolsuper
Definition: pg_authid.h:80
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
int location
Definition: parsenodes.h:722
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define Anum_pg_auth_members_grantor
#define CStringGetDatum(X)
Definition: postgres.h:584
#define Anum_pg_authid_rolcanlogin
Definition: pg_authid.h:84
int errdetail_log(const char *fmt,...)
Definition: elog.c:921
#define Anum_pg_authid_rolconnlimit
Definition: pg_authid.h:87
DropBehavior behavior
Definition: parsenodes.h:3307
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
RoleSpec * grantor
Definition: parsenodes.h:1900
bool pg_database_ownercheck(Oid db_oid, Oid roleid)
Definition: aclchk.c:4964
bool superuser_arg(Oid roleid)
Definition: superuser.c:57
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:588
Node * arg
Definition: parsenodes.h:720
char * get_rolespec_name(const RoleSpec *role)
Definition: acl.c:5211
#define AuthMemRoleMemIndexId
Definition: indexing.h:102
#define WARNING
Definition: elog.h:40
Oid AlterRole(AlterRoleStmt *stmt)
Definition: user.c:481
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
#define Anum_pg_authid_rolbypassrls
Definition: pg_authid.h:86
#define TextDatumGetCString(d)
Definition: builtins.h:92
#define Anum_pg_auth_members_roleid
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:922
void check_rolespec_name(const RoleSpec *role, const char *detail_msg)
Definition: acl.c:5233
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
RoleSpecType roletype
Definition: parsenodes.h:327
Oid AlterRoleSet(AlterRoleSetStmt *stmt)
Definition: user.c:851
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
#define list_make1_oid(x1)
Definition: pg_list.h:151
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5129
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
FormData_pg_auth_members * Form_pg_auth_members
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:871
#define Anum_pg_authid_rolcreatedb
Definition: pg_authid.h:83
VariableSetStmt * setstmt
Definition: parsenodes.h:2436
char * encrypt_password(PasswordType target_type, const char *role, const char *password)
Definition: crypt.c:116
#define BoolGetDatum(X)
Definition: postgres.h:408
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:2009
#define InvalidOid
Definition: postgres_ext.h:36
ObjectAddress RenameRole(const char *oldname, const char *newname)
Definition: user.c:1108
#define NOTICE
Definition: elog.h:37
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1361
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
void DeleteSharedComments(Oid oid, Oid classoid)
Definition: comment.c:373
List * options
Definition: parsenodes.h:2427
#define AuthMemMemRoleIndexId
Definition: indexing.h:104
HeapTuple get_rolespec_tuple(const RoleSpec *role)
Definition: acl.c:5167
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
RoleSpec * newrole
Definition: parsenodes.h:3317
char * rolename
Definition: parsenodes.h:328
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void DeleteSharedSecurityLabel(Oid objectId, Oid classId)
Definition: seclabel.c:414
#define Anum_pg_authid_rolname
Definition: pg_authid.h:79
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define Int32GetDatum(X)
Definition: postgres.h:485
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:4875
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:383
#define intVal(v)
Definition: value.h:52
Oid createdb(ParseState *pstate, const CreatedbStmt *stmt)
Definition: dbcommands.c:99
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ReassignOwnedObjects(ReassignOwnedStmt *stmt)
Definition: user.c:1324
static bool have_createrole_privilege(void)
Definition: user.c:62
int i
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define Anum_pg_auth_members_admin_option
#define CStringGetTextDatum(s)
Definition: builtins.h:91
void DropRole(DropRoleStmt *stmt)
Definition: user.c:931
char * defname
Definition: parsenodes.h:719
#define Anum_pg_authid_rolcreaterole
Definition: pg_authid.h:82
List * grantee_roles
Definition: parsenodes.h:1897
#define elog
Definition: elog.h:219
bool checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
Definition: pg_shdepend.c:522
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:791
check_password_hook_type check_password_hook
Definition: user.c:50
void DropSetting(Oid databaseid, Oid roleid)
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:45
#define Anum_pg_authid_rolinherit
Definition: pg_authid.h:81
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void(* check_password_hook_type)(const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
Definition: user.h:23
char * priv_name
Definition: parsenodes.h:1880
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define Natts_pg_authid
Definition: pg_authid.h:78
static void DelRoleMems(const char *rolename, Oid roleid, List *memberSpecs, List *memberIds, bool admin_opt)
Definition: user.c:1534
#define Anum_pg_auth_members_member
#define SearchSysCache2(cacheId, key1, key2)
Definition: syscache.h:158