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