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